/// <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)); }
/// <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)); }
/// <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); }
/// <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); })); }
/// <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);