private static Event <TA> SwitchE <TA>(Transaction trans1, Behavior <Event <TA> > bea) { var @out = new EventSink <TA>(); var h2 = new TransactionHandler <TA> { Run = (trans2, a) => @out.Send(trans2, a) }; var h1 = new TransactionHandler <Event <TA> > { CurrentListener = bea.SampleNoTrans().Listen(@out.Node, trans1, h2, false) }; h1.Run = (trans2, ea) => trans2.Last( new Runnable { Run = () => { if (h1.CurrentListener != null) { h1.CurrentListener.Unlisten(); } h1.CurrentListener = ea.Listen(@out.Node, trans2, h2, true); } }); Listener l1 = bea.Updates().Listen(@out.Node, trans1, h1, false); return(@out.AddCleanup(l1)); }
/// ///Unwrap a behavior inside another behavior to give a time-varying behavior implementation. /// public static Behavior <TA> SwitchB <TA>(Behavior <Behavior <TA> > bba) { Func <TA> za = () => bba.SampleNoTrans().SampleNoTrans(); var @out = new EventSink <TA>(); var h = new TransactionHandler <Behavior <TA> >(); h.Run = (trans2, ba) => { // Note: If any switch takes place during a transaction, then the // value().listen will always cause a sample to be fetched from the // one we just switched to. The caller will be fetching our output // using value().listen, and value() throws away all firings except // for the last one. Therefore, anything from the old input behaviour // that might have happened during this transaction will be suppressed. if (h.CurrentListener != null) { h.CurrentListener.Unlisten(); } h.CurrentListener = ba.Value(trans2).Listen( @out.Node, trans2, new TransactionHandler <TA> { Run = (trans3, a) => @out.Send(trans3, a) }, false); }; Listener l1 = bba.Value().Listen_(@out.Node, h); return(@out.AddCleanup(l1).HoldLazy(za)); }
public ListenerImplementation(Event <TA> @event, TransactionHandler <TA> action, Node target) { _event = @event; this.action = action; this.target = target; Unlisten = UnlistenImpl; }
/// ///Merge two streams of events of the same type. /// ///In the case where two event occurrences are simultaneous (i.e. both ///within the same transaction), both will be delivered in the same ///transaction. If the event firings are ordered for some reason, then ///their ordering is retained. In many common cases the ordering will ///be undefined. /// public static Event <TA> Merge <TA>(Event <TA> ea, Event <TA> eb) { var @out = new EventSink <TA> { SampleNow = () => { Object[] oa = ea.SampleNow(); Object[] ob = eb.SampleNow(); if (oa != null && ob != null) { var oo = new Object[oa.Length + ob.Length]; int j = 0; for (int i = 0; i < oa.Length; i++) { oo[j++] = oa[i]; } for (int i = 0; i < ob.Length; i++) { oo[j++] = ob[i]; } return(oo); } if (oa != null) { return(oa); } return(ob); } }; var h = new TransactionHandler <TA> { Run = (trans, a) => @out.Send(trans, a) }; Listener l1 = ea.Listen_(@out.Node, h); Listener l2 = eb.Listen_(@out.Node, new TransactionHandler <TA> { Run = (trans1, a) => trans1.Prioritized(@out.Node, new Handler <Transaction> { Run = trans2 => { @out.Send(trans2, a); } }) }); return(@out.AddCleanup(l1).AddCleanup(l2)); }
public Listener Listen(Node target, Transaction trans, TransactionHandler <TA> action, bool suppressEarlierFirings) { lock (Transaction.ListenersLock) { if (Node.LinkTo(target)) { trans.ToRegen = true; } Listeners.Add(action); } trans.Prioritized(target, new Handler <Transaction> { Run = trans2 => { object[] aNow = SampleNow(); if (aNow != null) { // In cases like value(), we start with an initial value. foreach (object t in aNow) { action.Run(trans, (TA)t); // <-- unchecked warning is here } } if (!suppressEarlierFirings) { // Anything sent already in this transaction must be sent now so that // there's no order dependency between send and listen. foreach (TA a in Firings) { action.Run(trans, a); } } } }); return(new ListenerImplementation <TA>(this, action, target)); }
public Listener Listen_(Node target, TransactionHandler <TA> action) { return(Transaction.Apply(trans1 => Listen(target, trans1, action, false))); }