/// <summary>
        ///     Unwrap a stream inside a cell to give a time-varying stream implementation.
        ///     When the cell changes value, the output stream will fire the simultaneous firing (if one exists) from the stream
        ///     which the cell held at the beginning of the transaction.
        /// </summary>
        /// <typeparam name="T">The type of the stream.</typeparam>
        /// <param name="csa">The cell containing the stream.</param>
        /// <returns>The unwrapped stream.</returns>
        public static Stream <T> SwitchS <T>(this Cell <Stream <T> > csa)
        {
            return(Transaction.Apply(
                       trans1 =>
            {
                Stream <T> @out = new Stream <T>(csa.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, csa.SampleNoTransaction()));
                IListener l1 = csa.Updates(trans1).Listen(new Node <T>(), trans1, H, false);
                return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener);
            },
                       false));
        }
Example #2
0
        /// <summary>
        ///     Unwrap a stream inside a cell to give a time-varying stream implementation.
        ///     When the cell changes value, the output stream will fire the simultaneous firing (if one exists) from the stream which the cell held at the beginning of the transaction.
        /// </summary>
        /// <typeparam name="T">The type of the stream.</typeparam>
        /// <param name="csa">The cell containing the stream.</param>
        /// <returns>The unwrapped stream.</returns>
        public static Stream <T> SwitchS <T>(this Cell <Stream <T> > csa)
        {
            return(Transaction.Apply(trans1 =>
            {
                Stream <T> @out = new Stream <T>();
                IListener currentListener = null;
                Action <Transaction, Stream <T> > hInitial = (trans2, sa) =>
                {
                    currentListener?.Unlisten();

                    currentListener = sa.Listen(@out.Node, trans2, @out.Send, false);
                };
                Action <Transaction, Stream <T> > h = (trans2, sa) =>
                {
                    trans2.Last(() =>
                    {
                        currentListener?.Unlisten();

                        currentListener = sa.Listen(@out.Node, trans2, @out.Send, true);
                    });
                };
                trans1.Prioritized(new Node <T>(), trans2 => hInitial(trans2, csa.SampleNoTransaction()));
                IListener l1 = csa.Updates(trans1).Listen(@out.Node, trans1, h, false);
                return @out.UnsafeAttachListener(l1);
            }, false));
        }
Example #3
0
 /// <summary>
 ///     Resolve the loop to specify what the <see cref="CellLoop{T}" /> was a forward reference to.  This method
 ///     must be called inside the same transaction as the one in which this <see cref="CellLoop{T}" /> instance was
 ///     created and used.
 ///     This requires an explicit transaction to be created with <see cref="Transaction.Run{T}(Func{T})" /> or
 ///     <see cref="Transaction.RunVoid(Action)" />.
 /// </summary>
 /// <param name="c">The cell that was forward referenced.</param>
 public void Loop(Cell <T> c)
 {
     Transaction.Apply(trans =>
     {
         this.streamLoop.Loop(c.Updates(trans));
         this.LazyInitialValue = c.SampleLazy(trans);
         return(Unit.Value);
     }, false);
 }
Example #4
0
        /// <summary>
        ///     Unwrap a stream inside a cell to give a time-varying stream implementation.
        /// </summary>
        /// <typeparam name="T">The type of the stream.</typeparam>
        /// <param name="csa">The cell containing the stream.</param>
        /// <returns>The unwrapped stream.</returns>
        public static Stream <T> SwitchS <T>(this Cell <Stream <T> > csa)
        {
            return(Transaction.Apply(trans1 =>
            {
                Stream <T> @out = new Stream <T>();
                IListener currentListener = csa.SampleNoTransaction().Listen(@out.Node, trans1, @out.Send, false);
                Action <Transaction, Stream <T> > h = (trans2, sa) =>
                {
                    trans2.Last(() =>
                    {
                        using (currentListener)
                        {
                        }

                        currentListener = sa.Listen(@out.Node, trans2, @out.Send, true);
                    });
                };
                IListener l1 = csa.Updates(trans1).Listen(@out.Node, trans1, h, false);
                return @out.UnsafeAddCleanup(l1);
            }));
        }
Example #5
0
 /// <summary>
 ///     A stream that gives the updates/steps for a cell.
 /// </summary>
 /// <typeparam name="T">The type of the values in the cell.</typeparam>
 /// <param name="c"></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 cell 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 cell updates.
 /// </remarks>
 public static Stream <T> Updates <T>(Cell <T> c) => Transaction.Apply(trans => c.Updates(trans).Coalesce(trans, (left, right) => right), false);