/// <summary>
        ///     Unwrap a stream inside a behavior to give a time-varying stream implementation.
        ///     When the behavior changes value, the output stream will fire the simultaneous firing (if one exists) from the stream
        ///     which the behavior held at the beginning of the transaction.
        /// </summary>
        /// <typeparam name="T">The type of the stream.</typeparam>
        /// <param name="bsa">The behavior containing the stream.</param>
        /// <returns>The unwrapped stream.</returns>
        public static Stream <T> SwitchS <T>(this Behavior <Stream <T> > bsa)
        {
            return(Transaction.Apply(
                       (trans1, _) =>
            {
                Stream <T> @out = new Stream <T>(bsa.KeepListenersAlive);
                MutableListener currentListener = new MutableListener();

                void HInitial(Transaction trans2, Stream <T> sa)
                {
                    currentListener.Unlisten();

                    currentListener.SetListener(sa.Listen(@out.Node, trans2, @out.Send, false));
                }

                void H(Transaction trans2, Stream <T> sa)
                {
                    trans2.Last(
                        () =>
                    {
                        currentListener.Unlisten();

                        currentListener.SetListener(sa.Listen(@out.Node, trans2, @out.Send, true));
                    });
                }

                trans1.Prioritized(new Node <T>(), trans2 => HInitial(trans2, bsa.SampleNoTransaction()));
                IListener l1 = bsa.Updates().Listen(new Node <T>(), trans1, H, false);
                return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener);
            },
                       false));
        }
Esempio n. 2
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));
        }
Esempio n. 3
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())));
        }
Esempio n. 4
0
 /// <summary>
 ///     A stream that gives the updates/steps for a behavior.
 /// </summary>
 /// <typeparam name="T">The type of the values in the behavior.</typeparam>
 /// <param name="b"></param>
 /// <returns></returns>
 /// <remarks>
 ///     This is an OPERATIONAL primitive, which is not part of the main Sodium
 ///     API.  It breaks the property of non-detectability of behavior steps/updates.
 ///     The rule with this primitive is that you should only use it in functions
 ///     that do not allow the caller to detect the behavior updates.
 /// </remarks>
 public static Stream <T> Updates <T>(Behavior <T> b) => Transaction.Apply(
     trans => b.Updates().Coalesce(trans, (left, right) => right),
     false);
Esempio n. 5
0
 public void Loop(Behavior <TA> aOut)
 {
     ((EventLoop <TA>)Event).Loop(aOut.Updates());
     EventValue = aOut.Sample();
 }