/// <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 will hold at the end 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> SwitchEarlyS <T>(this Cell <Stream <T> > csa) { return(Transaction.Apply(trans1 => { Stream <T> @out = new Stream <T>(csa.KeepListenersAlive); Node <T> node = new Node <T>(); (bool changed, Node <T> .Target nodeTarget) = node.Link(trans1, (t, v) => { }, @out.Node); if (changed) { trans1.SetNeedsRegenerating(); } Guid listenerId; void SendIfNodeTargetMatches(Transaction t, (T Value, Guid ListenerId)v, Guid i) { if (v.ListenerId == i) { @out.Send(t, v.Value); } } MutableListener currentListener = new MutableListener(); void Handler(Transaction trans2, Stream <T> sa) { currentListener.Unlisten(); listenerId = Guid.NewGuid(); currentListener.SetListener(sa.Map(v => (Value: v, ListenerId: listenerId)).Listen(@out.Node, trans2, (t, v) => SendIfNodeTargetMatches(t, v, listenerId), false)); } IListener l1 = csa.Value(trans1).Listen(node, trans1, Handler, false); return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener).UnsafeAttachListener(Listener.Create(node, nodeTarget)); }, 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 will hold at the end 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> SwitchEarlyS <T>(this Cell <Stream <T> > csa) { return(Transaction.Apply(trans1 => { Stream <T> @out = new Stream <T>(); Node <T> node = new Node <T>(); Node <T> .Target nodeTarget = node.Link(trans1, (t, v) => { }, @out.Node).Item2; Guid listenerId; Action <Transaction, Tuple <T, Guid>, Guid> sendIfNodeTargetMatches = (t, v, i) => { if (v.Item2 == i) { @out.Send(t, v.Item1); } }; IListener currentListener = null; Action <Transaction, Stream <T> > h = (trans2, sa) => { currentListener?.Unlisten(); listenerId = Guid.NewGuid(); currentListener = sa.Map(v => Tuple.Create(v, listenerId)).Listen(@out.Node, trans2, (t, v) => sendIfNodeTargetMatches(t, v, listenerId), false); }; IListener l1 = csa.Value(trans1).Listen(node, trans1, h, false); return @out.UnsafeAttachListener(l1).UnsafeAttachListener(Listener.Create(node, nodeTarget)); }, 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 will hold at the end 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> SwitchEarlyS <T>(this Cell <Stream <T> > csa) { return(Transaction.Apply(trans1 => { Stream <T> @out = new Stream <T>(csa.KeepListenersAlive); Node <T> node = new Node <T>(); ValueTuple <bool, Node <T> .Target> r = node.Link(trans1, (t, v) => { }, @out.Node); Node <T> .Target nodeTarget = r.Item2; if (r.Item1) { trans1.SetNeedsRegenerating(); } Guid listenerId; Action <Transaction, ValueTuple <T, Guid>, Guid> sendIfNodeTargetMatches = (t, v, i) => { if (v.Item2 == i) { @out.Send(t, v.Item1); } }; MutableListener currentListener = new MutableListener(); Action <Transaction, Stream <T> > h = (trans2, sa) => { currentListener.Unlisten(); listenerId = Guid.NewGuid(); currentListener.SetListener(sa.Map(v => ValueTuple.Create(v, listenerId)).Listen(@out.Node, trans2, (t, v) => sendIfNodeTargetMatches(t, v, listenerId), false)); }; IListener l1 = csa.Value(trans1).Listen(node, trans1, h, false); return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener).UnsafeAttachListener(Listener.Create(node, nodeTarget)); }, false)); }
/// <summary> /// Unwrap a cell inside another cell to give a time-varying cell implementation. /// </summary> /// <typeparam name="T">The type of the cell.</typeparam> /// <param name="cca">The cell containing another cell.</param> /// <returns>The unwrapped cell.</returns> public static Cell <T> SwitchC <T>(this Cell <Cell <T> > cca) { return(Transaction.Apply(trans1 => { Lazy <T> za = cca.SampleLazy().Map(ca => ca.Sample()); Stream <T> @out = new Stream <T>(cca.KeepListenersAlive); MutableListener currentListener = new MutableListener(); Action <Transaction, Cell <T> > h = (trans2, ca) => { currentListener.Unlisten(); currentListener.SetListener(ca.Value(trans2).Listen(@out.Node, trans2, @out.Send, false)); }; IListener l1 = cca.Value(trans1).Listen(@out.Node, trans1, h, false); return @out.UnsafeAttachListener(l1).UnsafeAttachListener(currentListener).HoldLazyInternal(za); }, false)); }
/// <summary> /// Unwrap a cell inside another cell to give a time-varying cell implementation. /// </summary> /// <typeparam name="T">The type of the cell.</typeparam> /// <param name="cca">The cell containing another cell.</param> /// <returns>The unwrapped cell.</returns> public static Cell <T> SwitchC <T>(this Cell <Cell <T> > cca) { return(Transaction.Apply(trans1 => { Lazy <T> za = cca.SampleLazy().Map(ca => ca.Sample()); Stream <T> @out = new Stream <T>(); IListener currentListener = null; Action <Transaction, Cell <T> > h = (trans2, ca) => { using (currentListener) { } currentListener = ca.Value(trans2).Listen(@out.Node, trans2, (trans3, a) => @out.Send(trans3, a), false); }; IListener l1 = cca.Value(trans1).Listen(@out.Node, trans1, h, false); return @out.UnsafeAddCleanup(l1).HoldLazy(za); })); }