package xapi.fu; import xapi.fu.Out1.Out1Unsafe; import static xapi.fu.Immutable.immutable1; import java.util.Map.Entry; /** * @author James X. Nelson (james@wetheinter.net) * Created on 07/11/15. */ @SuppressWarnings("unchecked") public interface Out2<O1, O2> extends OutMany { default O1 out1() { return out1Provider().out1(); } default O2 out2() { return out2Provider().out1(); } default Out1<O1> out1Provider() { return (Out1<O1>) out0()[0]; } default Out1<O2> out2Provider() { return (Out1<O2>) out0()[1]; } default Out2<O1, O2> use1(In1<O1> callback) { callback.in(out1()); return this; } default Out2<O1, O2> use2(In1<O2> callback) { callback.in(out2()); return this; } /** * @return an immutable copy of this object. */ default <F extends Out2<O1, O2> & Frozen> F freeze2() { if (this instanceof Frozen) { return (F) this; } final Out1[] outs = out0(); outs[0] = outs[0].freeze(); outs[1] = outs[1].freeze(); F f = (F)(Out2<O1, O2> & Frozen)()->outs; return f; } static <O1, O2> Out2<O1, O2> out2(Out1<O1> o1, Out1<O2> o2) { final Out1[] out = new Out1[]{o1, o2}; return ()->out; } static <O1, O2> Out2<O1, O2> out2(O1 o1, Out1<O2> o2) { final Out1[] out = new Out1[]{immutable1(o1), o2}; return ()->out; } static <O1, O2> Out2Immutable <O1, O2> out2Immutable(O1 o1, O2 o2) { return new Out2Immutable<>(o1, o2); } class Out2Immutable <O1, O2> implements Out2<O1, O2>, Entry<O1, O2>, IsImmutable { private final O1 one; private final O2 two; public Out2Immutable(O1 one, O2 two) { this.one = one; this.two = two; } @Override public Out1[] out0() { // arrays are mutable, so we give everyone that asks a new one return new Out1[]{ immutable1(one), immutable1(two) }; } @Override public final O1 getKey() { return out1(); } @Override public final O2 getValue() { return out2(); } @Override public final O2 setValue(O2 value) { throw new UnsupportedOperationException("Object is immutable"); } @Override public O1 out1() { return one; } @Override public O2 out2() { return two; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Out2Immutable)) return false; final Out2Immutable<?, ?> that = (Out2Immutable<?, ?>) o; if (one != null ? !one.equals(that.one) : that.one != null) return false; return two != null ? two.equals(that.two) : that.two == null; } @Override public int hashCode() { int result = one != null ? one.hashCode() : 0; result = 31 * result + (two != null ? two.hashCode() : 0); return result; } } static <O1, O2> Out2<O1, O2> out2(Out1<O1> o1, O2 o2) { final Out1[] out = new Out1[]{o1, immutable1(o2)}; return ()->out; } static <O1, O2> Out2<O1, O2> out2Unsafe(O1 o1, Out1Unsafe<O2> o2) { return out2(o1, o2); } static <O1, O2> Out2<O1, O2> out2Unsafe(Out1Unsafe<O1> o1, Out1Unsafe<O2> o2) { return out2(o1, o2); } static <O1, O2> Out2<O1, O2> out2Unsafe(Out1Unsafe<O1> o1, O2 o2) { return out2(o1, o2); } static <O1, O2> Out2<O1, O2> fromEntry(Entry<O1, O2> entry) { return entry instanceof Out2 ? (Out2<O1, O2>) entry : out2Immutable(entry.getKey(), entry.getValue()); } }