package org.syndicate_lang.actors; import java.lang.reflect.Proxy; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class Remote { private final Actor _actor; private final T _target; public Remote(Actor actor, T target) { this._actor = actor; this._target = target; } public Actor getActor() { return _actor; } public void async(BiConsumer f) { this._actor.execute(() -> f.accept(this._target, this._actor)); } public void async(long delayMilliseconds, BiConsumer f) { this._actor.later(delayMilliseconds, () -> f.accept(this._target, this._actor)); } public Promise syncVoid(BiConsumer f) { return this.sync((t, ac) -> { f.accept(t, ac); return null; }); } public Promise syncVoid(long delayMilliseconds, BiConsumer f) { return this.sync(delayMilliseconds, (t, ac) -> { f.accept(t, ac); return null; }); } public Promise sync(BiFunction f) { Promise p = new Promise<>(); this._actor.execute( () -> p.resolveWith(f.apply(this._target, this._actor)), () -> p.rejectWith(this._actor.getExitReason())); return p; } public Promise sync(long delayMilliseconds, BiFunction f) { Promise p = new Promise<>(); this._actor.later( delayMilliseconds, () -> p.resolveWith(f.apply(this._target, this._actor)), () -> p.rejectWith(this._actor.getExitReason())); return p; } private void checkTargetInstance(Class c) { if (!c.isInstance(this._target)) { throw new IllegalArgumentException("target is not an instance of " + c); } } @SuppressWarnings("unchecked") public I syncProxy(Class c) { checkTargetInstance(c); return (I) Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, new SyncProxy<>(this)); } @SuppressWarnings("unchecked") public I asyncProxy(Class c) { checkTargetInstance(c); return (I) Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, new AsyncProxy<>(this)); } @SuppressWarnings("unchecked") public static Remote from(I proxy) { return ((AbstractProxy) Proxy.getInvocationHandler(proxy)).ref(); } @Override public String toString() { return this.getClass().getSimpleName() + "(" + this._actor.getName() + "::" + this._target + ")"; } }