package cs2030s.fp; public abstract class Actually implements Immutatorable, Actionable { public static Actually ok(T value) { return new Success(value); } public static Actually err(Exception e) { // It is okay to do an unchecked cast here as failure types don't use // the value T. @SuppressWarnings("unchecked") Actually failure = (Actually) new Failure(e); return failure; } public abstract T unwrap() throws Exception; public abstract T except(Constant c); public abstract void finish(Action action); public abstract T unless(U other); public abstract Actually next( Immutator, ? super T> immutator); private static class Success extends Actually { private final T value; private Success(T value) { this.value = value; } @Override public T unwrap() { return this.value; } @Override public T except(Constant c) { return this.value; } @Override public void finish(Action action) { action.call(this.value); } @Override public T unless(U other) { return this.value; } @Override public Actually next(Immutator, ? super T> immutator) { try { // it is okay to cast from to @SuppressWarnings("unchecked") Actually result = (Actually) immutator.invoke(this.value); return result; } catch (Exception e) { return Actually.err(e); } } @Override public Actually transform(Immutator immutator) { try { return Actually.ok(immutator.invoke(this.value)); } catch (Exception e) { return Actually.err(e); } } @Override public void act(Action action) { action.call(this.value); } @Override public String toString() { return "<" + value + ">"; } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Success) { Success other = (Success) obj; if (this.value == other.value) { return true; } if (this.value != null && this.value.equals(other.value)) { return true; } } return false; } } private static class Failure extends Actually { private final Exception e; Failure(Exception e) { this.e = e; } @Override public Object unwrap() throws Exception { throw e; } @Override public U except(Constant c) { return c.init(); } @Override public Object unless(Object other) { return other; } @Override public void finish(Action action) { return; } @Override public Actually transform(Immutator immutator) { return Actually.err(this.e); } @Override public Actually next( Immutator, ? super Object> immutator) { return Actually.err(this.e); } @Override public void act(Action action) { // Do nothing return; } @Override public String toString() { return "[" + e.getClass().getName() + "] " + e.getMessage(); } @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof Failure) { Failure other = (Failure) obj; if (this.e == other.e) { return true; } if (this.e == null || other.e == null) { return false; } if (this.e.getMessage() == null || other.e.getMessage() == null) { return false; } return this.e.getMessage() == other.e.getMessage(); } return false; } } }