![JAR search and dependency download from the Maven repository](/logo.png)
net.diversionmc.error.Functionals Maven / Gradle / Ivy
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