net.diversionmc.error.Functionals Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of result Show documentation
Show all versions of result Show documentation
Diversion Network Result type.
package net.diversionmc.error;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Stream;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static net.diversionmc.error.Result.tryGet;
/**
* Utils for {@link Result}, {@link Success}, {@link Optional}, {@link Stream} types.
*/
@SuppressWarnings({"unused", "NewMethodNamingConvention"})
public class Functionals {
public static void noop() {
}
//
// Optional, Stream
//
/**
* @return {@link Optional#of(Object)}
*/
public static Optional some(T t) {
return Optional.of(t);
}
/**
* @return {@link Optional#ofNullable(Object)}
*/
public static Optional optional(T t) {
return Optional.ofNullable(t);
}
/**
* @return {@link Stream#ofNullable(Object)}
*/
@SafeVarargs
public static Stream stream(T... t) {
return Stream.of(t)
.filter(Objects::nonNull);
}
/**
* @return {@link Optional#empty()}
*/
public static Optional none() {
return Optional.empty();
}
/**
* Convert boolean to optional.
*
* @param test Boolean to convert.
* @param ifTrue Object to wrap on true test value.
* @param Optional type.
* @return Optional wrapping value if check has passed.
*/
public static Optional optional(boolean test, Supplier ifTrue) {
return test ? some(ifTrue.get()) : none();
}
/**
* Convert boolean to optional.
*
* @param test Boolean to convert.
* @param ifTrue Object to wrap on true test value.
* @param Optional type.
* @return Optional wrapping value if check has passed.
*/
public static Optional optional(boolean test, T ifTrue) {
return test ? some(ifTrue) : none();
}
public static Function> optionalF(Function f) {
return f.andThen(Functionals::optional);
}
public static Function> streamF(Function> f) {
return f.andThen(Optional::stream);
}
//
// Reflective Casts
//
/**
* Try to dynamically cast an object to a type.
* Used for functional style castings in streams and such.
*
* @param obj Object to cast.
* @param Type to cast to.
* @return Cast type or empty optional.
*/
public static Optional cast(Object obj, Class c) {
return tryGet(
ClassCastException.class,
TryS.of(applyF2(Class::cast, c, obj)))
.mapOk(Functionals::optional)
.ok()
.flatMap(f());
}
public static Function> cast(Class c) {
return applyF2F(Functionals::cast, c);
}
public static Function> castStream(Class c) {
return Functionals
.cast(c)
.andThen(Optional::stream);
}
//
// Entry
//
public static Predicate byKey(T key) {
return byKey(
key,
f(),
Objects::equals);
}
public static Predicate byKey(K key, Function keyExtractor) {
return byKey(
key,
keyExtractor,
Objects::equals);
}
public static Predicate byKey(K key, BiPredicate keyEquality) {
return byKey(
key,
f(),
keyEquality);
}
public static Predicate byKey(K1 key,
Function keyExtractor,
BiPredicate keyEquality) {
return repeatP(mapP(
keyEquality,
ignoreS(applyS(key)),
keyExtractor));
}
public static Predicate> byEntryKey(Predicate keyCheck) {
return mapP(
keyCheck,
Entry::getKey);
}
public static Predicate> byEntryValue(Predicate valueCheck) {
return mapP(
valueCheck,
Entry::getValue);
}
public static Predicate> byEntry(BiPredicate entryCheck) {
return repeatP(mapP(
entryCheck,
Entry::getKey,
Entry::getValue));
}
public static Collector, ?, Map> toEntryMap() {
return toMap(
Entry::getKey,
Entry::getValue);
}
public static > Collector, ?, M> toEntryMap(Supplier map) {
return toMap(
Entry::getKey,
Entry::getValue,
Functionals.ignoreF()::apply,
map);
}
//
// Lambda Conversion (keeping the parameter count)
//
// BiP -> BiP
// P -> P
// P,P -> BiP
public static BiPredicate not(BiPredicate f) {
return f.negate();
}
public static Predicate not(Predicate f) {
return f.negate();
}
public static BiPredicate and(Predicate fa, Predicate fb) {
return mapP(
Boolean::logicalAnd,
fa::test,
fb::test);
}
public static BiPredicate or(Predicate fa, Predicate fb) {
return mapP(
Boolean::logicalOr,
fa::test,
fb::test);
}
// Lambda quick cast
public static Function f() {
return identity();
}
public static Function f(Function f) {
return f;
}
public static BiFunction f2(BiFunction f) {
return f;
}
public static Predicate p() {
return Functionals.f()::apply;
}
public static Predicate p(Predicate f) {
return f;
}
public static BiPredicate p2(BiPredicate f) {
return f;
}
public static Consumer c() {
return ignoreR();
}
public static Consumer c(Consumer f) {
return f;
}
public static BiConsumer c2(BiConsumer f) {
return f;
}
public static Supplier s(Supplier f) {
return f;
}
public static Runnable r() {
return Functionals::noop;
}
public static Runnable r(Runnable f) {
return f;
}
// Other
public static T map(T t, Predicate check, Function ifTrue) {
return map(t, check, ifTrue, f());
}
public static T map(T t, Predicate check,
Function ifTrue,
Function ifFalse) {
return (check.test(t) ? ifTrue : ifFalse).apply(t);
}
// Flip
// BiF(A, B)->BiF(B, A)
// BiP(A, B)->BiP(B, A)
// BiC(A, B)->BiC(B, A)
public static BiFunction flipF(BiFunction f) {
return (b, a) -> f.apply(a, b);
}
public static BiPredicate flipP(BiPredicate f) {
return flipF(f::test)::apply;
}
public static BiConsumer flipC(BiConsumer f) {
return (b, a) -> f.accept(a, b);
}
//
// Partial Application (lower the parameter count by supplying them)
//
// Function
// BiF(A, B)->R -> F(B)->R
// BiF(A, B)->R -> F(A)->R
// BiF(A, B)->R -> S()->R
// F(T)->R -> S()->R
public static Function applyF2(BiFunction f, A a) {
return b -> f.apply(a, b);
}
public static Function applyF2F(BiFunction f, B b) {
return applyF2(flipF(f), b);
}
public static Supplier applyF2(BiFunction f, A a, B b) {
return () -> f.apply(a, b);
}
public static Supplier applyF(Function f, T t) {
return () -> f.apply(t);
}
// BiF(S()->A, B)->R -> F(B)->R
// BiF(A, S()->B)->R -> F(A)->R
// BiF(S()->A, S()->B)->R -> S()->R
// F(S()->T)->R -> S()->R
public static Function applyF2S(BiFunction f, Supplier a) {
return b -> f.apply(a.get(), b);
}
public static Function applyF2SF(BiFunction f, Supplier b) {
return applyF2S(flipF(f), b);
}
public static Supplier applyF2S(BiFunction f, Supplier a, Supplier b) {
return () -> f.apply(a.get(), b.get());
}
public static Supplier applyFS(Function f, Supplier t) {
return () -> f.apply(t.get());
}
// Predicate
// BiP(A, B) -> P(B)
// BiP(A, B) -> P(A)
// BiP(A, B) -> S()->bool
// P(T) -> S()->bool
public static Predicate applyP2(BiPredicate f, A a) {
return applyF2(f::test, a)::apply;
}
public static Predicate applyP2F(BiPredicate f, B b) {
return applyF2F(f::test, b)::apply;
}
public static BooleanSupplier applyP2(BiPredicate f, A a, B b) {
return applyF2(f::test, a, b)::get;
}
public static BooleanSupplier applyP(Predicate f, T t) {
return applyF(f::test, t)::get;
}
// BiP(S()->A, B) -> P(B)
// BiP(A, S()->B) -> P(A)
// BiP(S()->A, S()->B) -> S()->bool
// P(S()->T) -> S()->bool
public static Predicate applyP2S(BiPredicate f, Supplier a) {
return applyF2S(f::test, a)::apply;
}
public static Predicate applyP2SF(BiPredicate f, Supplier b) {
return applyF2SF(f::test, b)::apply;
}
public static BooleanSupplier applyP2S(BiPredicate f, Supplier a, Supplier b) {
return applyF2S(f::test, a, b)::get;
}
public static BooleanSupplier applyPS(Predicate f, Supplier t) {
return applyFS(f::test, t)::get;
}
// Consumer
// BiC(A, B) -> C(A)
// BiC(A, B) -> C(B)
// BiC(A, B) -> R()
// C(T) -> R()
public static Consumer applyC2(BiConsumer f, A a) {
return b -> f.accept(a, b);
}
public static Consumer applyC2F(BiConsumer f, B b) {
return applyC2(flipC(f), b);
}
public static Runnable applyC2(BiConsumer f, A a, B b) {
return () -> f.accept(a, b);
}
public static Runnable applyC(Consumer f, T t) {
return () -> f.accept(t);
}
// BiC(S()->A, B) -> C(A)
// BiC(A, S()->B) -> C(B)
// BiC(S()->A, S()->B) -> R()
// C(S()->T) -> R()
public static Consumer applyC2S(BiConsumer f, Supplier a) {
return b -> f.accept(a.get(), b);
}
public static Consumer applyC2SF(BiConsumer f, Supplier b) {
return applyC2S(flipC(f), b);
}
public static Runnable applyC2S(BiConsumer f, Supplier a, Supplier b) {
return () -> f.accept(a.get(), b.get());
}
public static Runnable applyCS(Consumer f, Supplier t) {
return () -> f.accept(t.get());
}
// Supplier
// T -> S()->T
public static Supplier applyS(T t) {
return () -> t;
}
//
// Parameter Ignorance (raise the parameter count by ignoring them)
//
// Function
// F(A)->R -> BiF(A, B)->R
public static BiFunction ignoreF(Function f) {
return (a, b) -> f.apply(a);
}
public static BiFunction ignoreF() {
return ignoreF(f());
}
// Predicate
// P(A) -> BiP(A, B)
public static BiPredicate ignoreP(Predicate f) {
return ignoreF(f::test)::apply;
}
// Consumer
// C(A) -> BiC(A, B)
public static BiConsumer ignoreC(Consumer f) {
return (a, b) -> f.accept(a);
}
public static BiConsumer ignoreC() {
return ignoreC(c());
}
// Supplier
// S()->R -> BiF(A, B)->R
// S()->R -> F(T)->R
public static BiFunction ignoreS2(Supplier f) {
return (a, b) -> f.get();
}
public static Function ignoreS(Supplier f) {
return t -> f.get();
}
// Runnable
// R() -> BiC(A, B)
// R() -> C(T)
public static BiConsumer ignoreR2(Runnable f) {
return (a, b) -> f.run();
}
public static BiConsumer ignoreR2() {
return ignoreR2(r());
}
public static Consumer ignoreR(Runnable f) {
return t -> f.run();
}
public static Consumer ignoreR() {
return ignoreR(r());
}
//
// Parameter Repeating (lower the parameter count by repeating them)
//
// Function
public static Function repeatF(BiFunction f) {
return t -> f.apply(t, t);
}
// Predicate
public static Predicate repeatP(BiPredicate f) {
return repeatF(f::test)::apply;
}
// Consumer
public static Consumer repeatC(BiConsumer f) {
return t -> f.accept(t, t);
}
//
// Mapping (keeping the parameter count, but converting input types)
//
// Function
public static BiFunction mapF(BiFunction f,
Function na,
Function mb) {
return (n, m) -> f.apply(na.apply(n), mb.apply(m));
}
public static Function mapF(Function f,
Function na) {
return f.compose(na);
}
// Predicate
public static BiPredicate mapP(BiPredicate f,
Function na,
Function mb) {
return mapF(f::test, na, mb)::apply;
}
public static Predicate mapP(Predicate f,
Function na) {
return mapF(f::test, na)::apply;
}
// Consumer
public static BiConsumer mapC(BiConsumer f,
Function na,
Function mb) {
return (n, m) -> f.accept(na.apply(n), mb.apply(m));
}
public static Consumer mapC(Consumer f,
Function na) {
return n -> f.accept(na.apply(n));
}
// Supplier
public static Supplier mapS(Supplier f,
Function na) {
return applyFS(na, f);
}
//
// Peeking (keeping the parameter count, but performing a side effect action)
//
// Function
public static BiFunction peekF2(BiConsumer action, BiFunction f) {
return (a, b) -> {
action.accept(a, b);
return f.apply(a, b);
};
}
public static Function peekF(Consumer action, Function f) {
return t -> {
action.accept(t);
return f.apply(t);
};
}
public static BiFunction peekF2O(Consumer action, BiFunction f) {
return (a, b) -> {
var r = f.apply(a, b);
action.accept(r);
return r;
};
}
public static Function peekFO(Consumer action, Function f) {
return t -> {
var r = f.apply(t);
action.accept(r);
return r;
};
}
// Predicate
public static BiPredicate peekP2(BiConsumer action, BiPredicate f) {
return peekF2(action, f::test)::apply;
}
public static Predicate peekP(Consumer action, Predicate f) {
return peekF(action, f::test)::apply;
}
// Consumer
public static BiConsumer peekC2(BiConsumer action, BiConsumer f) {
return action.andThen(f);
}
public static Consumer peekC(Consumer action, Consumer f) {
return action.andThen(f);
}
public static BiConsumer peekC2O(BiConsumer action, BiConsumer f) {
return f.andThen(action);
}
public static Consumer peekCO(Consumer action, Consumer f) {
return f.andThen(action);
}
// Supplier
public static Supplier peekSO(Consumer action, Supplier f) {
return () -> {
var t = f.get();
action.accept(t);
return t;
};
}
// Runnable
public static Runnable peekR(Runnable action, Runnable f) {
return () -> {
action.run();
f.run();
};
}
public static Runnable peekRO(Runnable action, Runnable f) {
return () -> {
f.run();
action.run();
};
}
//
// Higher Order Partial Application
//
// Function
public static Function, R> flatApplyF(T t) {
return applyF2F(Function::apply, t);
}
// Predicate
public static Predicate> flatApplyP(T t) {
return applyP2F(Predicate::test, t);
}
// Consumer
public static Consumer> flatApplyC(T t) {
return applyC2F(Consumer::accept, t);
}
// Supplier
public static Supplier> flatApplyS(T t) {
return applyS(applyS(t));
}
//
// Propagation
//
public static boolean get(boolean res) {
if (!res) throw new NoSuchElementException("Cannot unwrap error");
return true;
}
public static T get(Optional res) {
return res.get();
}
public static void get(Success res) {
res.get();
}
public static T get(Result res) {
return res.get();
}
public static boolean isError(boolean res) {
return !res;
}
public static boolean isError(Optional> res) {
return res.isEmpty();
}
public static boolean isError(Success> res) {
return res.isError();
}
public static boolean isError(Result, ?> res) {
return res.isError();
}
public static boolean propagate(boolean res) {
return false; // default propagation assumed false
}
public static Optional propagate(Optional> opt) {
return none(); // default propagation assumed none()
}
public static Success propagate(Success res) {
return Success.error(res.error().get());
}
public static Result