Exemple #1
0
        public void Loop(Cell <T> c) =>
        TransactionInternal.Apply(
            (trans, _) =>
        {
            lock (this.isLoopedLock)
            {
                if (this.isLooped)
                {
                    throw new InvalidOperationException("Loop was looped more than once.");
                }

                this.isLooped = true;
            }

            if (trans != this.transaction)
            {
                this.transaction = null;

                throw new InvalidOperationException(
                    "Loop must be looped in the same transaction that it was created in.");
            }

            this.transaction = null;

            this.Loop(trans, c);

            return(UnitInternal.Value);
        },
            false);
        private static Stream <T> Merge <T>(
            TransactionInternal trans,
            IReadOnlyList <Stream <T> > e,
            int start,
            int end,
            Func <T, T, T> f)
        {
            int n = end - start;

            if (n == 0)
            {
                return(new Stream <T>());
            }

            if (n == 1)
            {
                return(e[start]);
            }

            if (n == 2)
            {
                return(e[start].Merge(trans, e[start + 1], f));
            }

            int mid = (start + end) / 2;

            return(Merge(trans, e, start, mid, f).Merge(trans, Merge(trans, e, mid, end, f), f));
        }
Exemple #3
0
        internal Behavior(Stream <T> stream, T initialValue)
        {
            this.stream            = stream;
            this.valueProperty     = initialValue;
            this.UsingInitialValue = true;

            this.streamListener = TransactionInternal.Apply(
                (trans1, _) =>
                this.stream.Listen(
                    Node <T> .Null,
                    trans1,
                    (trans2, a) =>
            {
                this.valueUpdate.MatchNone(
                    () =>
                {
                    trans2.Last(
                        () =>
                    {
                        this.valueUpdate.MatchSome(v => this.ValueProperty = v);
                        this.valueUpdate = MaybeInternal.None;
                    });
                });

                this.valueUpdate = MaybeInternal.Some(a);
            },
                    false),
                false);
        }
Exemple #4
0
 public static void RunVoid(Action action) =>
 TransactionInternal.RunImpl(
     () =>
 {
     action();
     return(Unit.Value);
 });
Exemple #5
0
        internal LazyBehavior(TransactionInternal trans, Stream <T> stream, Lazy <T> lazyInitialValue)
            : base(stream, default(T))
        {
            this.LazyInitialValue = new Lazy <T>(() => GuardAgainstSend(lazyInitialValue));

            trans.Sample(this.EnsureValueIsCreated);
        }
Exemple #6
0
        internal Cell(Behavior <T> behavior)
        {
            this.BehaviorImpl = behavior;

            this.updates = new Lazy <Stream <T> >(() => TransactionInternal.Apply(
                                                      (trans, _) => this.BehaviorImpl.Updates().Coalesce(trans, (left, right) => right),
                                                      false));
        }
Exemple #7
0
        internal Stream <T> Coalesce(TransactionInternal trans1, Func <T, T, T> f)
        {
            Stream <T> @out = new Stream <T>(this.KeepListenersAlive);
            Action <TransactionInternal, T> h = CoalesceHandler.Create(f, @out);
            IListener l = this.Listen(@out.Node, trans1, h, false);

            return(@out.UnsafeAttachListener(l));
        }
Exemple #8
0
        private static void EnsureElevated(TransactionInternal transaction)
        {
            if (transaction != null && !transaction.isElevated)
            {
                transaction.isElevated = true;

                if (!transaction.hasParentTransaction)
                {
                    Monitor.Enter(TransactionLock);
                }

                RunStartHooks();
            }
        }
Exemple #9
0
        internal void Loop(TransactionInternal trans, Stream <T> stream)
        {
            lock (this.isAssignedLock)
            {
                if (this.isAssigned)
                {
                    throw new InvalidOperationException("Loop was looped more than once.");
                }

                this.isAssigned = true;
            }

            this.AttachListenerImpl(stream.Listen(this.Node, this.Send));

            lock (stream.KeepListenersAlive)
            {
                stream.KeepListenersAlive.Use(this.KeepListenersAlive);
            }
        }
Exemple #10
0
        internal IWeakListener Listen(
            Node target,
            TransactionInternal trans,
            Action <TransactionInternal, T> action,
            bool suppressEarlierFirings)
        {
            (bool changed, Node <T> .Target nodeTarget) = this.Node.Link(trans, action, target);
            if (changed)
            {
                trans.SetNeedsRegenerating();
            }

            // ReSharper disable once LocalVariableHidesMember
            List <T> firings = this.firings.ToList();

            if (!suppressEarlierFirings && firings.Count > 0)
            {
                trans.Prioritized(
                    target,
                    trans2 =>
                {
                    // Anything sent already in this transaction must be sent now so that
                    // there's no order dependency between send and listen.
                    foreach (T a in firings)
                    {
                        TransactionInternal.InCallback++;
                        try
                        {
                            // Don't allow transactions to interfere with Sodium
                            // internals.
                            action(trans2, a);
                        }
                        finally
                        {
                            TransactionInternal.InCallback--;
                        }
                    }
                });
            }

            return(new ListenerImplementation(this, action, nodeTarget));
        }
Exemple #11
0
        private Stream <T> Merge(TransactionInternal trans, Stream <T> s)
        {
            Stream <T> @out  = new Stream <T>(this.KeepListenersAlive);
            Node <T>   left  = new Node <T>();
            Node <T>   right = @out.Node;

            (bool changed, Node <T> .Target nodeTarget) = left.Link(trans, (t, v) => { }, right);
            if (changed)
            {
                trans.SetNeedsRegenerating();
            }

            Action <TransactionInternal, T> h = @out.Send;
            IListener l1 = this.Listen(left, h);
            IListener l2 = s.Listen(right, h);

            return(@out.UnsafeAttachListener(l1)
                   .UnsafeAttachListener(l2)
                   .UnsafeAttachListener(ListenerInternal.CreateFromNodeAndTarget(left, nodeTarget)));
        }
Exemple #12
0
        public CellLoop()
        {
            this.transaction = TransactionInternal.GetCurrentTransaction();

            if (this.transaction == null)
            {
                throw new InvalidOperationException("Loop must be created within an explicit transaction.");
            }

            this.transaction.Last(
                () =>
            {
                if (this.transaction != null)
                {
                    this.transaction = null;

                    throw new InvalidOperationException("Loop was not looped.");
                }
            });
        }
Exemple #13
0
 public static void Post(Action action) => TransactionInternal.PostImpl(action);
Exemple #14
0
 public static void OnStart(Action action) => TransactionInternal.OnStartImpl(action);
Exemple #15
0
 public static T Run <T>(Func <T> f) => TransactionInternal.RunImpl(f);
Exemple #16
0
 public static bool IsActive() => TransactionInternal.HasCurrentTransaction();
Exemple #17
0
 internal Stream <T> MergeImpl(Stream <T> s, Func <T, T, T> f) => TransactionInternal.Apply((trans, _) => this.Merge(trans, s, f), false);
Exemple #18
0
 internal IWeakListener ListenWeakImpl(Action <T> handler) => TransactionInternal.Apply(
     (trans, _) => this.BehaviorImpl.Value(trans).ListenWeakImpl(handler),
     false);
Exemple #19
0
 internal Cell <T> HoldLazyImpl(Lazy <T> initialValue) =>
 TransactionInternal.Apply((trans, _) => new Cell <T>(this.HoldLazyInternal(trans, initialValue)), false);
Exemple #20
0
        internal void Close()
        {
            EnsureElevated(this);

            foreach (Node.Target target in this.TargetsToActivate)
            {
                target.IsActivated = true;
            }

            this.ActivatedTargets = true;

            // ReSharper disable once ForCanBeConvertedToForeach
            for (int i = 0; i < this.sendQueue.Count; i++)
            {
                this.sendQueue[i](this);
            }

            this.sendQueue.Clear();

            while (this.prioritizedQueue.Count > 0 || this.sampleQueue.Count > 0)
            {
                while (this.prioritizedQueue.Count > 0)
                {
                    this.CheckRegen();

                    Entry e = this.prioritizedQueue.Dequeue();
                    e.IsRemoved = true;
                    e.Action(this);
                }

                List <Action> sq = this.sampleQueue;
                this.sampleQueue = new List <Action>();
                foreach (Action s in sq)
                {
                    s();
                }
            }

            while (this.lastQueue.Count > 0)
            {
                this.lastQueue.Dequeue()();
            }

            if (!this.hasParentTransaction)
            {
                void ExecuteInNewTransaction(Action <TransactionInternal> action, bool runStartHooks)
                {
                    try
                    {
                        TransactionInternal transaction = new TransactionInternal(this.postQueue, this.splitQueue);

                        if (!runStartHooks)
                        {
                            // this will ensure we don't run start hooks
                            transaction.isElevated = true;
                        }

                        LocalTransaction.Value = transaction;
                        try
                        {
                            action(transaction);
                        }
                        finally
                        {
                            transaction.Close();
                        }
                    }
                    finally
                    {
                        LocalTransaction.Value = this;
                    }
                }

                while (this.postQueue.Count > 0 || this.splitQueue.Count > 0)
                {
                    while (this.postQueue.Count > 0)
                    {
                        ExecuteInNewTransaction(this.postQueue.Dequeue(), true);
                    }

                    Dictionary <int, Action <TransactionInternal> > sq = this.splitQueue;
                    this.splitQueue = new Dictionary <int, Action <TransactionInternal> >();
                    foreach (int n in sq.Keys.OrderBy(n => n))
                    {
                        ExecuteInNewTransaction(sq[n], false);
                    }
                }
            }
        }
Exemple #21
0
 internal Behavior <T> HoldLazyInternal(TransactionInternal trans, Lazy <T> initialValue) =>
 new LazyBehavior <T>(trans, this, initialValue);
Exemple #22
0
 /// <summary>
 ///     Clean up the output by discarding any firing other than the last one.
 /// </summary>
 /// <param name="trans">The transaction to get the last firing from.</param>
 /// <returns>A stream containing only the last event firing from the specified transaction.</returns>
 internal Stream <T> LastFiringOnly(TransactionInternal trans) => this.Coalesce(trans, (first, second) => second);
Exemple #23
0
 internal IWeakListener Listen(Node target, Action <TransactionInternal, T> action) => TransactionInternal.Apply(
     (trans1, _) => this.Listen(target, trans1, action, false),
     false);
Exemple #24
0
 internal static Stream <T> ValueImpl <T>(Behavior <T> b) => TransactionInternal.Apply((trans, _) => b.Value(trans), false);
Exemple #25
0
        internal static T Apply <T>(Func <TransactionInternal, bool, T> code, bool ensureElevated)
        {
            TransactionInternal transaction = LocalTransaction.Value;

            T                   returnValue    = default(T);
            Exception           exception      = null;
            TransactionInternal newTransaction = transaction;

            try
            {
                bool createdNewTransaction = newTransaction == null;
                if (newTransaction == null)
                {
                    newTransaction = new TransactionInternal();

                    LocalTransaction.Value = newTransaction;
                }

                if (ensureElevated)
                {
                    EnsureElevated(newTransaction);
                }

                returnValue = code(newTransaction, createdNewTransaction);
            }
            catch (Exception e)
            {
                exception = e;
            }

            try
            {
                try
                {
                    if (transaction == null)
                    {
                        newTransaction?.Close();
                    }
                }
                catch (Exception e)
                {
                    if (exception == null)
                    {
                        throw;
                    }

                    throw new AggregateException(exception, e);
                }

                if (exception != null)
                {
                    ExceptionDispatchInfo.Capture(exception).Throw();
                }

                return(returnValue);
            }
            finally
            {
                if (transaction == null)
                {
                    if (newTransaction != null && newTransaction.isElevated && !newTransaction.hasParentTransaction)
                    {
                        Monitor.Exit(TransactionLock);
                    }

                    LocalTransaction.Value = null;
                }
            }
        }
Exemple #26
0
 internal static Stream <T> UpdatesImpl <T>(Behavior <T> b) => TransactionInternal.Apply(
     (trans, _) => b.Updates().Coalesce(trans, (left, right) => right),
     false);
Exemple #27
0
 internal static Cell <T> ConstantLazyImpl <T>(Lazy <T> value) =>
 TransactionInternal.Apply((trans, _) => new Cell <T>(StreamInternal.NeverImpl <T>().HoldLazyInternal(trans, value)), false);
Exemple #28
0
 internal Stream <T> Merge(TransactionInternal trans, Stream <T> s, Func <T, T, T> f) =>
 this.Merge(trans, s).Coalesce(trans, f);
Exemple #29
0
 internal static Behavior <T> ConstantLazyImpl <T>(Lazy <T> value) =>
 TransactionInternal.Apply((trans, _) => StreamInternal.NeverImpl <T>().HoldLazyInternal(trans, value), false);
        internal static Stream <T> MergeImpl <T, T2>(this IEnumerable <T2> s, Func <T, T, T> f) where T2 : Stream <T>
        {
            IReadOnlyList <Stream <T> > v = s.ToArray();

            return(TransactionInternal.Apply((trans, _) => Merge(trans, v, 0, v.Count, f), false));
        }