/* * Copyright (c) 2022, Antonio Gabriel Muñoz Conejo <antoniogmc at gmail dot com> * 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; import io.vavr.Function1; import io.vavr.Tuple2; public final class Ref<A> { private final AtomicReference<A> value; private Ref(AtomicReference<A> value) { this.value = Objects.requireNonNull(value); } public IO<A> get() { return IO.task(value::get); } public IO<Unit> set(A newValue) { return IO.task(() -> { value.set(newValue); return Unit.unit(); }); } public <B> IO<B> modify(Function1<A, Tuple2<B, A>> change) { return IO.task(() -> { var loop = true; B result = null; while (loop) { A current = value.get(); var tuple = change.apply(current); result = tuple._1(); loop = !value.compareAndSet(current, tuple._2()); } return result; }); } public IO<Unit> lazySet(A newValue) { return IO.task(() -> { value.lazySet(newValue); return Unit.unit(); }); } public IO<A> getAndSet(A newValue) { return IO.task(() -> value.getAndSet(newValue)); } public IO<A> updateAndGet(UnaryOperator<A> update) { return IO.task(() -> value.updateAndGet(update::apply)); } public IO<A> getAndUpdate(UnaryOperator<A> update) { return IO.task(() -> value.getAndUpdate(update::apply)); } public static <A> IO<Ref<A>> make(A value) { return IO.pure(of(value)); } public static <A> Ref<A> of(A value) { return new Ref<>(new AtomicReference<>(value)); } @Override public String toString() { return String.format("Ref(%s)", value.get()); } }