Newer
Older
vavr-effect / src / main / java / com / github / tonivade / vavr / effect / Ref.java
@Antonio Muñoz Antonio Muñoz on 6 May 2022 1 KB remove useless subproject
/*
 * 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());
  }
}