package bjc.utils.data.internals; import bjc.utils.data.IHolder; import bjc.utils.data.Lazy; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IList; import java.util.function.Function; import java.util.function.Supplier; import java.util.function.UnaryOperator; /** * Implements a lazy holder that has been bound */ public class BoundLazy implements IHolder { /* * The old value */ private Supplier> oldSupplier; /* * The function to use to transform the old value into a new value */ private Function> binder; /* * The bound value being held */ private IHolder boundHolder; /* * Whether the bound value has been actualized or not */ private boolean holderBound; /* * Transformations currently pending on the bound value */ private IList> actions = new FunctionalList<>(); /* * Create a new bound lazy value */ public BoundLazy(Supplier> supp, Function> binder) { oldSupplier = supp; this.binder = binder; } @Override public IHolder bind(Function> bindr) { if(bindr == null) throw new NullPointerException("Binder must not be null"); /* * Prepare a list of pending actions */ IList> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); /* * Create the new supplier of a value */ Supplier> typeSupplier = () -> { IHolder oldHolder = boundHolder; /* * Bind the value if it hasn't been bound before */ if(!holderBound) { oldHolder = oldSupplier.get().unwrap(binder); } /* * Apply all the pending actions */ return pendingActions.reduceAux(oldHolder, (action, state) -> { return state.transform(action); }, (value) -> value); }; return new BoundLazy<>(typeSupplier, bindr); } @Override public Function> lift( Function func) { if(func == null) throw new NullPointerException("Function to lift must not be null"); return (val) -> { return new Lazy<>(func.apply(val)); }; } @Override public IHolder map(Function mapper) { if(mapper == null) throw new NullPointerException("Mapper must not be null"); // Prepare a list of pending actions IList> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); // Prepare the new supplier Supplier typeSupplier = () -> { IHolder oldHolder = boundHolder; // Bound the value if it hasn't been bound if(!holderBound) { oldHolder = oldSupplier.get().unwrap(binder); } return pendingActions.reduceAux(oldHolder.getValue(), (action, state) -> { return action.apply(state); }, (value) -> mapper.apply(value)); }; return new Lazy<>(typeSupplier); } @Override public String toString() { if(holderBound) return boundHolder.toString(); return "(unmaterialized)"; } @Override public IHolder transform(UnaryOperator transformer) { if(transformer == null) throw new NullPointerException("Transformer must not be null"); actions.add(transformer); return this; } @Override public UnwrappedType unwrap(Function unwrapper) { if(unwrapper == null) throw new NullPointerException("Unwrapper must not be null"); if(!holderBound) { boundHolder = oldSupplier.get().unwrap(binder::apply); } return boundHolder.unwrap(unwrapper); } }