com.github.tonivade.purefun.effect.Managed Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2022, 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.Consumer1.noop;
import static com.github.tonivade.purefun.Function1.identity;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import java.time.Duration;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Nothing;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.type.Either;
@HigherKind
public final class Managed implements ManagedOf {
private final PureIO>> resource;
protected Managed(PureIO>> resource) {
this.resource = checkNonNull(resource);
}
public Managed map(Function1 super A, ? extends B> mapper) {
return flatMap(a -> pure(PureIO.pure(mapper.apply(a))));
}
public Managed mapError(Function1 super E, ? extends F> mapper) {
return new Managed<>(resource.mapError(mapper));
}
public Managed flatMap(Function1 super A, ? extends Managed> mapper) {
PureIO>> result = resource.flatMap(t -> {
Managed apply = ManagedOf.narrowK(mapper.apply(t.get1()));
return apply.resource.map(r -> r.map2(ignore -> releaseAndThen(t, r)));
});
return new Managed<>(result);
}
public Managed flatMapError(Function1 super E, ? extends Managed> mapper) {
return new Managed<>(resource.flatMapError(e -> ManagedOf.narrowK(mapper.apply(e)).resource));
}
public Managed andThen(Managed other) {
PureIO>> flatMap = resource.flatMap(a -> {
Either>> next = other.resource.provide(a.get1());
return PureIO.fromEither(() -> next.map(t -> t.map2(ignore -> releaseAndThen(a, t))));
});
return new Managed<>(flatMap);
}
public PureIO use(Function1 super A, ? extends PureIO> use) {
return PureIO.bracket(resource, a -> use.apply(a.get1()), release());
}
public Managed fold(
Function1 super E, ? extends B> mapError, Function1 super A, ? extends B> mapper) {
return foldM(
mapError.andThen(Managed::pure),
mapper.andThen(Managed::pure));
}
public Managed recover(Function1 super E, ? extends A> mapError) {
return fold(mapError, identity());
}
public Managed orElse(Managed other) {
return foldM(Function1.cons(other), Function1.cons(this));
}
public Managed foldM(
Function1 super E, ? extends Managed> mapError,
Function1 super A, ? extends Managed> mapper) {
PureIO>> foldM =
resource.foldM(
error -> ManagedOf.narrowK(mapError.apply(error)).resource,
a -> ManagedOf.narrowK(mapper.apply(a.get1())).resource.map(b -> b.map2(ignore -> releaseAndThen(a, b))));
return new Managed<>(foldM);
}
public Managed> combine(Managed other) {
return new Managed<>(PureIO.bracket(resource,
t -> PureIO.bracket(other.resource,
r -> PureIO.pure(Tuple.of(Tuple.of(t.get1(), r.get1()), noop())),
release()),
release()));
}
public Managed> either(Managed other) {
PureIO>, Tuple2>>> foldM =
this.resource.foldM(
error -> other.resource.map(Either::right),
success -> PureIO.pure(Either.left(success)));
return new Managed<>(foldM.map(
e -> e.fold(
a -> a.map(Either::left, x -> either -> Managed.release().accept(a)),
b -> b.map(Either::right, y -> either -> Managed.release().accept(b)))
));
}
public Managed retry() {
return retry(1);
}
public Managed retry(int maxRetries) {
return retry(Schedule.recurs(maxRetries));
}
public Managed retry(Duration delay) {
return retry(delay, 1);
}
public Managed retry(Duration delay, int maxRetries) {
return retry(Schedule.recursSpaced(delay, maxRetries));
}
public Managed retry(Schedule schedule) {
return new Managed<>(resource.retry(schedule));
}
public Managed> timed() {
return new Managed<>(resource.timed().map(
tt -> Tuple.of(Tuple.of(tt.get1(), tt.get2().get1()), t -> tt.get2().get2().accept(t.get2()))));
}
public static Managed pure(A resource) {
return pure(PureIO.pure(resource));
}
public static Managed pure(PureIO resource) {
return from(resource, noop());
}
public static Managed from(PureIO resource) {
return from(resource, AutoCloseable::close);
}
public static Managed from(PureIO resource, Consumer1 super A> release) {
return new Managed<>(resource.map(a -> Tuple.of(a, release)));
}
public static Managed from(Function1 super R, ? extends A> mapper) {
return from(mapper, AutoCloseable::close);
}
public static Managed from(Function1 super R, ? extends A> mapper, Consumer1 super A> release) {
return new Managed<>(PureIO.access(mapper).map(y -> Tuple.of(y, release)));
}
public static Managed fromM(Function1 super R, ? extends PureIO> mapper) {
return fromM(mapper, AutoCloseable::close);
}
public static Managed fromM(
Function1 super R, ? extends PureIO> mapper, Consumer1 super A> release) {
return new Managed<>(PureIO.accessM(mapper).map(y -> Tuple.of(y, release)));
}
private static Consumer1 releaseAndThen(
Tuple2> outter, Tuple2> inner) {
return ignore -> {
try {
Managed.release().accept(inner);
} finally {
Managed.release().accept(outter);
}
};
}
private static Consumer1>> release() {
return t -> t.get2().accept(t.get1());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy