예제 #1
0
        ///
        ///Sample the behavior at the time of the event firing. Note that the 'current value'
        /// of the behavior that's sampled is the value as at the start of the transaction
        /// before any state changes of the current transaction are applied through 'hold's.
        ///
        public Event <TC> Snapshot <TB, TC>(Behavior <TB> b, Func <TA, TB, TC> f)
        {
            Event <TA> ev   = this;
            var        @out = new EventSink <TC>
            {
                SampleNow = () =>
                {
                    Object[] oi = ev.SampleNow();
                    if (oi != null)
                    {
                        var oo = new Object[oi.Length];
                        for (int i = 0; i < oo.Length; i++)
                        {
                            oo[i] = f((TA)oi[i], b.SampleNoTrans());
                        }
                        return(oo);
                    }
                    return(null);
                }
            };
            Listener l = Listen_(
                @out.Node,
                new TransactionHandler <TA>
            {
                Run = (trans2, a) => @out.Send(trans2, f(a, b.SampleNoTrans()))
            });

            return(@out.AddCleanup(l));
        }
예제 #2
0
        ///
        ///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));
        }
예제 #3
0
        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));
        }
예제 #4
0
        ///
        ///Apply a value inside a behavior to a function inside a behavior. This is the
        ///primitive for all function lifting.
        ///
        public static Behavior <TB> Apply <TA, TB>(Behavior <Func <TA, TB> > bf, Behavior <TA> ba)
        {
            var @out = new EventSink <TB>();

            var h = new Handler <Transaction>
            {
                Fired = false
            };

            h.Run = trans1 =>
            {
                if (h.Fired)
                {
                    return;
                }

                h.Fired = true;
                trans1.Prioritized(
                    @out.Node,
                    new Handler <Transaction>
                {
                    Run = trans2 =>
                    {
                        @out.Send(trans2, bf.NewValue()(ba.NewValue()));
                        h.Fired = false;
                    }
                });
            };

            Listener l1 = bf.Updates().Listen_(@out.Node, new TransactionHandler <Func <TA, TB> >
            {
                Run = (trans1, f) => h.Run(trans1)
            });
            Listener l2 = ba.Updates().Listen_(@out.Node, new TransactionHandler <TA>
            {
                Run = (trans1, a) => h.Run(trans1)
            });

            return(@out.AddCleanup(l1).AddCleanup(l2).HoldLazy(() => bf.SampleNoTrans()(ba.SampleNoTrans())));
        }