public static IObservable <TSource> ThrottleFirstFrame <TSource>(this IObservable <TSource> source, int frameCount,
                                                                         FrameCountType frameCountType = FrameCountType.Update)
        {
            return(Observable.Create <TSource>(observer =>
            {
                var gate = new object();
                var open = true;
                var cancelable = new SerialDisposable();

                var subscription = source.Subscribe(x =>
                {
                    lock (gate)
                    {
                        if (!open)
                        {
                            return;
                        }
                        observer.OnNext(x);
                        open = false;
                    }

                    var d = new SingleAssignmentDisposable();
                    cancelable.Disposable = d;

                    d.Disposable = TimerFrame(frameCount, frameCountType)
                                   .Subscribe(_ =>
                    {
                        lock (gate)
                        {
                            open = true;
                        }
                    });
                },
                                                    exception =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnError(exception);
                    }
                },
                                                    () =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnCompleted();
                    }
                });

                return new CompositeDisposable(subscription, cancelable);
            }));
        }
        public static IObservable <TSource> ThrottleFirst <TSource>(this IObservable <TSource> source, TimeSpan dueTime, IScheduler scheduler)
        {
            return(Observable.Create <TSource>(observer =>
            {
                var gate = new object();
                var open = true;
                var cancelable = new SerialDisposable();

                var subscription = source.Subscribe(x =>
                {
                    lock (gate)
                    {
                        if (!open)
                        {
                            return;
                        }
                        observer.OnNext(x);
                        open = false;
                    }

                    var d = new SingleAssignmentDisposable();
                    cancelable.Disposable = d;
                    d.Disposable = scheduler.Schedule(dueTime, () =>
                    {
                        lock (gate)
                        {
                            open = true;
                        }
                    });
                },
                                                    exception =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnError(exception);
                    }
                },
                                                    () =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnCompleted();
                    }
                });

                return new CompositeDisposable(subscription, cancelable);
            }));
        }
        public static IObservable <TSource> Throttle <TSource>(this IObservable <TSource> source, TimeSpan dueTime, IScheduler scheduler)
        {
            // this code is borrowed from Rx Official(rx.codeplex.com)
            return(new AnonymousObservable <TSource>(observer =>
            {
                var gate = new object();
                var value = default(TSource);
                var hasValue = false;
                var cancelable = new SerialDisposable();
                var id = 0UL;

                var subscription = source.Subscribe(x =>
                {
                    ulong currentid;
                    lock (gate)
                    {
                        hasValue = true;
                        value = x;
                        id = unchecked (id + 1);
                        currentid = id;
                    }
                    var d = new SingleAssignmentDisposable();
                    cancelable.Disposable = d;
                    d.Disposable = scheduler.Schedule(dueTime, () =>
                    {
                        lock (gate)
                        {
                            if (hasValue && id == currentid)
                            {
                                observer.OnNext(value);
                            }
                            hasValue = false;
                        }
                    });
                },
                                                    exception =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnError(exception);
                        hasValue = false;
                        id = unchecked (id + 1);
                    }
                },
                                                    () =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        if (hasValue)
                        {
                            observer.OnNext(value);
                        }
                        observer.OnCompleted();
                        hasValue = false;
                        id = unchecked (id + 1);
                    }
                });

                return new CompositeDisposable(subscription, cancelable);
            }));
        }
Exemple #4
0
 public void Serial()
 {
     SetScehdulerForImport();
     var d = new SerialDisposable();
     d.IsDisposed.IsFalse();
     var id1 = new IdDisp(1);
     var id2 = new IdDisp(2);
     var id3 = new IdDisp(3);
     // dispose first
     d.Dispose();
     d.IsDisposed.IsTrue();
     d.Disposable = id1; id1.IsDisposed.IsTrue();
     d.Disposable = id2; id2.IsDisposed.IsTrue();
     d.Disposable = id3; id3.IsDisposed.IsTrue();
     // normal flow
     d = new SerialDisposable();
     id1 = new IdDisp(1);
     id2 = new IdDisp(2);
     id3 = new IdDisp(3);
     d.Disposable = id1; id1.IsDisposed.IsFalse();
     d.Dispose();
     id1.IsDisposed.IsTrue();
     d.Disposable = id2; id2.IsDisposed.IsTrue();
     d.Disposable = id3; id3.IsDisposed.IsTrue();
     // exception flow
     d = new SerialDisposable();
     id1 = new IdDisp(1);
     id2 = new IdDisp(2);
     id3 = new IdDisp(3);
     d.Disposable = id1;
     id1.IsDisposed.IsFalse();
     d.Disposable = id2;
     id1.IsDisposed.IsTrue();
     id2.IsDisposed.IsFalse();
     d.Disposable = id3;
     id2.IsDisposed.IsTrue();
     id3.IsDisposed.IsFalse();
     d.Dispose();
     
     id3.IsDisposed.IsTrue();
     // null
     d = new SerialDisposable();
     id1 = new IdDisp(1);
     d.Disposable = null;
     d.Dispose();
     d.Disposable = null;
     UniRx.Scheduler.SetDefaultForUnity();
 }
        static IObservable <T> RepeatUntilCore <T>(this IEnumerable <IObservable <T> > sources, IObservable <Unit> trigger, GameObject lifeTimeChecker)
        {
            return(Observable.Create <T>(observer =>
            {
                var isFirstSubscribe = true;
                var isDisposed = false;
                var isStopped = false;
                var e = sources.AsSafeEnumerable().GetEnumerator();
                var subscription = new SerialDisposable();
                var schedule = new SingleAssignmentDisposable();
                var gate = new object();

                var stopper = trigger.Subscribe(_ =>
                {
                    lock (gate)
                    {
                        isStopped = true;
                        e.Dispose();
                        subscription.Dispose();
                        schedule.Dispose();
                        observer.OnCompleted();
                    }
                }, observer.OnError);

                schedule.Disposable = Scheduler.CurrentThread.Schedule(self =>
                {
                    lock (gate)
                    {
                        if (isDisposed)
                        {
                            return;
                        }
                        if (isStopped)
                        {
                            return;
                        }

                        var current = default(IObservable <T>);
                        var hasNext = false;
                        var ex = default(Exception);

                        try
                        {
                            hasNext = e.MoveNext();
                            if (hasNext)
                            {
                                current = e.Current;
                                if (current == null)
                                {
                                    throw new InvalidOperationException("sequence is null.");
                                }
                            }
                            else
                            {
                                e.Dispose();
                            }
                        }
                        catch (Exception exception)
                        {
                            ex = exception;
                            e.Dispose();
                        }

                        if (ex != null)
                        {
                            stopper.Dispose();
                            observer.OnError(ex);
                            return;
                        }

                        if (!hasNext)
                        {
                            stopper.Dispose();
                            observer.OnCompleted();
                            return;
                        }

                        var source = e.Current;
                        var d = new SingleAssignmentDisposable();
                        subscription.Disposable = d;

                        var repeatObserver = Observer.Create <T>(observer.OnNext, observer.OnError, self);

                        if (isFirstSubscribe)
                        {
                            isFirstSubscribe = false;
                            d.Disposable = source.Subscribe(repeatObserver);
                        }
                        else
                        {
                            MainThreadDispatcher.SendStartCoroutine(SubscribeAfterEndOfFrame(d, source, repeatObserver, lifeTimeChecker));
                        }
                    }
                });

                return new CompositeDisposable(schedule, subscription, stopper, Disposable.Create(() =>
                {
                    lock (gate)
                    {
                        isDisposed = true;
                        e.Dispose();
                    }
                }));
            }));
        }
        public static IObservable <T> TimeoutFrame <T>(this IObservable <T> source, int frameCount, FrameCountType frameCountType = FrameCountType.Update)
        {
            return(Observable.Create <T>(observer =>
            {
                object gate = new object();
                var objectId = 0ul;
                var isTimeout = false;

                Func <ulong, IDisposable> runTimer = (timerId) =>
                {
                    return Observable.TimerFrame(frameCount, frameCountType)
                    .Subscribe(_ =>
                    {
                        lock (gate)
                        {
                            if (objectId == timerId)
                            {
                                isTimeout = true;
                            }
                        }
                        if (isTimeout)
                        {
                            observer.OnError(new TimeoutException());
                        }
                    });
                };

                var timerDisposable = new SerialDisposable();
                timerDisposable.Disposable = runTimer(objectId);

                var sourceSubscription = new SingleAssignmentDisposable();
                sourceSubscription.Disposable = source.Subscribe(x =>
                {
                    bool timeout;
                    lock (gate)
                    {
                        timeout = isTimeout;
                        objectId++;
                    }
                    if (timeout)
                    {
                        return;
                    }

                    timerDisposable.Disposable = Disposable.Empty; // cancel old timer
                    observer.OnNext(x);
                    timerDisposable.Disposable = runTimer(objectId);
                }, ex =>
                {
                    bool timeout;
                    lock (gate)
                    {
                        timeout = isTimeout;
                        objectId++;
                    }
                    if (timeout)
                    {
                        return;
                    }

                    timerDisposable.Dispose();
                    observer.OnError(ex);
                }, () =>
                {
                    bool timeout;
                    lock (gate)
                    {
                        timeout = isTimeout;
                        objectId++;
                    }
                    if (timeout)
                    {
                        return;
                    }

                    timerDisposable.Dispose();
                    observer.OnCompleted();
                });

                return new CompositeDisposable {
                    timerDisposable, sourceSubscription
                };
            }));
        }
        public static IObservable <TSource> ThrottleFrame <TSource>(this IObservable <TSource> source, int frameCount, FrameCountType frameCountType = FrameCountType.Update)
        {
            return(new AnonymousObservable <TSource>(observer =>
            {
                var gate = new object();
                var value = default(TSource);
                var hasValue = false;
                var cancelable = new SerialDisposable();
                var id = 0UL;

                var subscription = source.Subscribe(x =>
                {
                    ulong currentid;
                    lock (gate)
                    {
                        hasValue = true;
                        value = x;
                        id = unchecked (id + 1);
                        currentid = id;
                    }
                    var d = new SingleAssignmentDisposable();
                    cancelable.Disposable = d;
                    d.Disposable = Observable.TimerFrame(frameCount, frameCountType)
                                   .Subscribe(_ =>
                    {
                        lock (gate)
                        {
                            if (hasValue && id == currentid)
                            {
                                observer.OnNext(value);
                            }
                            hasValue = false;
                        }
                    });
                },
                                                    exception =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        observer.OnError(exception);
                        hasValue = false;
                        id = unchecked (id + 1);
                    }
                },
                                                    () =>
                {
                    cancelable.Dispose();

                    lock (gate)
                    {
                        if (hasValue)
                        {
                            observer.OnNext(value);
                        }
                        observer.OnCompleted();
                        hasValue = false;
                        id = unchecked (id + 1);
                    }
                });

                return new CompositeDisposable(subscription, cancelable);
            }));
        }