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