com.github.tonivade.purefun.effect.EIO Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2021, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.effect;
import static com.github.tonivade.purefun.Function2.first;
import static com.github.tonivade.purefun.Function2.second;
import static com.github.tonivade.purefun.Nothing.nothing;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import static com.github.tonivade.purefun.Producer.cons;
import java.time.Duration;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import com.github.tonivade.purefun.CheckedRunnable;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Effect;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Nothing;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.concurrent.Future;
import com.github.tonivade.purefun.data.ImmutableList;
import com.github.tonivade.purefun.data.Sequence;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.type.Option;
import com.github.tonivade.purefun.type.Try;
import com.github.tonivade.purefun.typeclasses.Fiber;
import com.github.tonivade.purefun.typeclasses.FunctionK;
@HigherKind
public final class EIO implements EIOOf, Effect, A> {
private static final EIO, Unit> UNIT = new EIO<>(PureIO.unit());
private final PureIO instance;
EIO(PureIO value) {
this.instance = checkNonNull(value);
}
@SuppressWarnings("unchecked")
public PureIO toPureIO() {
return (PureIO) instance;
}
public UIO toUIO() {
return new UIO<>(instance.toURIO().toPureIO());
}
public Either safeRunSync() {
return instance.provide(nothing());
}
public Future> runAsync() {
return instance.runAsync(nothing());
}
public Future> runAsync(Executor executor) {
return EIO.forked(executor).andThen(this).runAsync();
}
public void safeRunAsync(Consumer1 super Try extends Either>> callback) {
instance.provideAsync(nothing(), callback);
}
@Override
public EIO map(Function1 super A, ? extends B> map) {
return new EIO<>(instance.map(map));
}
@Override
public EIO flatMap(Function1 super A, ? extends Kind, ? extends B>> map) {
return new EIO<>(instance.flatMap(value -> {
EIO apply = map.andThen(EIOOf::narrowK).apply(value);
return apply.instance;
}));
}
@Override
public EIO andThen(Kind, ? extends B> next) {
return new EIO<>(instance.andThen(next.fix(EIOOf.toEIO()).instance));
}
@Override
public EIO ap(Kind, Function1 super A, ? extends B>> apply) {
return new EIO<>(instance.ap(apply.fix(EIOOf.toEIO()).toPureIO()));
}
public EIO swap() {
return new EIO<>(instance.swap());
}
public EIO mapError(Function1 super E, ? extends B> map) {
return new EIO<>(instance.mapError(map));
}
public EIO flatMapError(Function1 super E, ? extends Kind, ? extends A>> map) {
return new EIO<>(instance.flatMapError(error -> {
EIO apply = map.andThen(EIOOf::narrowK).apply(error);
return apply.instance;
}));
}
public EIO bimap(Function1 super E, ? extends F> mapError, Function1 super A, ? extends B> map) {
return new EIO<>(instance.bimap(mapError, map));
}
public EIO foldM(
Function1 super E, ? extends Kind, ? extends B>> mapError,
Function1 super A, ? extends Kind, ? extends B>> map) {
return new EIO<>(instance.foldM(
error -> mapError.andThen(EIOOf::narrowK).apply(error).instance,
value -> map.andThen(EIOOf::narrowK).apply(value).instance));
}
public UIO fold(Function1 super E, ? extends B> mapError, Function1 super A, ? extends B> map) {
return new UIO<>(instance.fold(mapError, map).toPureIO());
}
public UIO recover(Function1 super E, ? extends A> mapError) {
return new UIO<>(instance.recover(mapError).toPureIO());
}
public EIO orElse(EIO other) {
return new EIO<>(instance.orElse(other.instance));
}
@Override
public EIO> zip(Kind, ? extends B> other) {
return zipWith(other, Tuple::of);
}
@Override
public EIO zipLeft(Kind, ? extends B> other) {
return zipWith(other, first());
}
@Override
public EIO zipRight(Kind, ? extends B> other) {
return zipWith(other, second());
}
@Override
public EIO zipWith(Kind, ? extends B> other,
Function2 super A, ? super B, ? extends C> mapper) {
return parMap2(this, other.fix(EIOOf.toEIO()), mapper);
}
public EIO, A>> fork() {
return new EIO<>(instance.fork().map(f -> f.mapK(new FunctionK, E>, Kind>() {
@Override
public EIO apply(Kind, E>, ? extends T> from) {
return new EIO<>(from.fix(PureIOOf::narrowK));
}
})));
}
public EIO timeout(Duration duration) {
return timeout(Future.DEFAULT_EXECUTOR, duration);
}
public EIO timeout(Executor executor, Duration duration) {
return racePair(executor, this, EIO.sleep(duration)).flatMap(either -> either.fold(
ta -> ta.get2().cancel().fix(EIOOf.toEIO()).map(x -> ta.get1()),
tb -> tb.get1().cancel().fix(EIOOf.toEIO()).flatMap(x -> EIO.throwError(new TimeoutException()))));
}
@Override
public EIO repeat() {
return repeat(1);
}
@Override
public EIO repeat(int times) {
return new EIO<>(instance.repeat(times));
}
@Override
public EIO repeat(Duration delay) {
return repeat(delay, 1);
}
@Override
public EIO repeat(Duration delay, int times) {
return new EIO<>(instance.repeat(delay, times));
}
public EIO repeat(Schedule schedule) {
return new EIO<>(instance.repeat(schedule));
}
@Override
public EIO retry() {
return retry(1);
}
@Override
public EIO retry(int maxRetries) {
return retry(Schedule.recurs(maxRetries));
}
@Override
public EIO retry(Duration delay) {
return retry(delay, 1);
}
@Override
public EIO retry(Duration delay, int maxRetries) {
return retry(Schedule.recursSpaced(delay, maxRetries));
}
public EIO retry(Schedule schedule) {
return new EIO<>(instance.retry(schedule));
}
@Override
public EIO> timed() {
return new EIO<>(instance.timed());
}
public static EIO forked(Executor executor) {
return async(callback -> executor.execute(() -> callback.accept(Try.success(Either.right(Unit.unit())))));
}
public EIO refineOrDie(Class type) {
return new EIO<>(instance.refineOrDie(type));
}
public static EIO parMap2(Kind, ? extends A> za, Kind, ? extends B> zb,
Function2 super A, ? super B, ? extends C> mapper) {
return parMap2(Future.DEFAULT_EXECUTOR, za, zb, mapper);
}
public static EIO parMap2(Executor executor, Kind, ? extends A> za, Kind, ? extends B> zb,
Function2 super A, ? super B, ? extends C> mapper) {
return new EIO<>(PureIO.parMap2(executor, za.fix(EIOOf::narrowK).instance, zb.fix(EIOOf::narrowK).instance, mapper));
}
public static EIO> race(Kind, ? extends A> fa, Kind, ? extends B> fb) {
return race(Future.DEFAULT_EXECUTOR, fa, fb);
}
public static EIO> race(Executor executor, Kind, ? extends A> fa, Kind, ? extends B> fb) {
return racePair(executor, fa, fb).flatMap(either -> either.fold(
ta -> ta.get2().cancel().fix(EIOOf.toEIO()).map(x -> Either.left(ta.get1())),
tb -> tb.get1().cancel().fix(EIOOf.toEIO()).map(x -> Either.right(tb.get2()))));
}
public static EIO, B>>, Tuple2, A>, B>>>
racePair(Executor executor, Kind, ? extends A> fa, Kind, ? extends B> fb) {
PureIO instance1 = fa.fix(EIOOf.toEIO()).instance.fix(PureIOOf::narrowK);
PureIO instance2 = fb.fix(EIOOf.toEIO()).instance.fix(PureIOOf::narrowK);
return new EIO<>(PureIO.racePair(executor, instance1, instance2).map(
either -> either.bimap(a -> a.map2(f -> f.mapK(new FunctionK, E>, Kind>() {
@Override
public EIO apply(Kind, E>, ? extends T> from) {
return new EIO<>(from.fix(PureIOOf::narrowK));
}
})), b -> b.map1(f -> f.mapK(new FunctionK, E>, Kind>() {
@Override
public EIO apply(Kind, E>, ? extends T> from) {
return new EIO<>(from.fix(PureIOOf::narrowK));
}
})))));
}
public static EIO absorb(EIO> value) {
return new EIO<>(PureIO.absorb(value.instance));
}
public static Function1> lift(Function1 super A, ? extends B> function) {
return PureIO.lift(function).andThen(EIO::new);
}
public static Function1> liftOption(Function1 super A, Option extends B>> function) {
return value -> fromOption(function.apply(value));
}
public static Function1> liftTry(Function1 super A, Try extends B>> function) {
return value -> fromTry(function.apply(value));
}
public static Function1> liftEither(Function1 super A, Either> function) {
return value -> fromEither(function.apply(value));
}
public static EIO fromOption(Option extends A> task) {
return fromOption(cons(task));
}
public static EIO fromOption(Producer © 2015 - 2025 Weber Informatics LLC | Privacy Policy