예제 #1
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));
        }
예제 #2
0
        /// <summary>
        ///     Unwrap a behavior inside another behavior to give a time-varying behavior implementation.
        /// </summary>
        /// <typeparam name="T">The type of the behavior.</typeparam>
        /// <param name="bba">The behavior containing another behavior.</param>
        /// <returns>The unwrapped behavior.</returns>
        public static Behavior <T> SwitchC <T>(this Behavior <Behavior <T> > bba)
        {
            return(Transaction.Apply(
                       trans1 =>
            {
                Lazy <T> za = bba.SampleLazy().Map(ba => ba.Sample());
                Stream <T> @out = new Stream <T>(bba.KeepListenersAlive);
                MutableListener currentListener = new MutableListener();

                void H(Transaction trans2, Behavior <T> ba)
                {
                    currentListener.Unlisten();

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

                IListener l1 = bba.Value(trans1).Listen(@out.Node, trans1, H, false);
                return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener).HoldLazyInternal(trans1, za);
            },
                       false));
        }
예제 #3
0
 /// <summary>
 ///     A stream that is guaranteed to fire once upon listening, giving the current
 ///     value of a behavior, and thereafter gives the updates/steps for the 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> Value <T>(Behavior <T> b) => Transaction.Apply((trans, _) => b.Value(trans), false);