/*
* Copyright (c) 2024-2025, Antonio Gabriel Muñoz Conejo <me at tonivade dot es>
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.vavr.effect;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
sealed interface IOConnection {
IOConnection UNCANCELLABLE = new Uncancellable();
boolean isCancellable();
void setCancelToken(IO<Unit> cancel);
void cancelNow();
void cancel();
StateIO updateState(UnaryOperator<StateIO> update);
static IOConnection cancellable() {
return new Cancellable();
}
static final class Uncancellable implements IOConnection {
private Uncancellable() { }
@Override
public boolean isCancellable() {
return false;
}
@Override
public void setCancelToken(IO<Unit> cancel) {
// uncancellable
}
@Override
public void cancelNow() {
// uncancellable
}
@Override
public void cancel() {
// uncancellable
}
@Override
public StateIO updateState(UnaryOperator<StateIO> update) {
return StateIO.INITIAL;
}
}
static final class Cancellable implements IOConnection {
private IO<Unit> cancelToken = IO.UNIT;
private final AtomicReference<StateIO> state = new AtomicReference<>(StateIO.INITIAL);
private Cancellable() { }
@Override
public boolean isCancellable() {
return true;
}
@Override
public void setCancelToken(IO<Unit> cancel) {
this.cancelToken = Objects.requireNonNull(cancel);
}
@Override
public void cancelNow() {
cancelToken.runAsync();
}
@Override
public void cancel() {
if (state.getAndUpdate(StateIO::cancellingNow).isCancelable()) {
cancelNow();
state.set(StateIO.CANCELLED);
}
}
@Override
public StateIO updateState(UnaryOperator<StateIO> update) {
return state.updateAndGet(update::apply);
}
}
}