| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751 | // Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the MIT License.// See the LICENSE file in the project root for more information. #nullable disableusing System.Collections.Generic;using System.Reactive.Concurrency;using System.Reactive.Disposables;using System.Reactive.Subjects;namespace System.Reactive.Linq.ObservableImpl{    internal static class Window<TSource>    {        internal sealed class Count : Producer<IObservable<TSource>, Count._>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            private readonly int _skip;            public Count(IObservable<TSource> source, int count, int skip)            {                _source = source;                _count = count;                _skip = skip;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(_source);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly Queue<ISubject<TSource>> _queue = new Queue<ISubject<TSource>>();                private readonly SingleAssignmentDisposable _m = new SingleAssignmentDisposable();                private readonly RefCountDisposable _refCountDisposable;                private readonly int _count;                private readonly int _skip;                public _(Count parent, IObserver<IObservable<TSource>> observer)                    : base(observer)                {                    _refCountDisposable = new RefCountDisposable(_m);                    _count = parent._count;                    _skip = parent._skip;                }                private int _n;                public override void Run(IObservable<TSource> source)                {                    var firstWindow = CreateWindow();                    ForwardOnNext(firstWindow);                    _m.Disposable = source.SubscribeSafe(this);                    SetUpstream(_refCountDisposable);                }                private IObservable<TSource> CreateWindow()                {                    var s = new Subject<TSource>();                    _queue.Enqueue(s);                    return new WindowObservable<TSource>(s, _refCountDisposable);                }                public override void OnNext(TSource value)                {                    foreach (var s in _queue)                    {                        s.OnNext(value);                    }                    var c = _n - _count + 1;                    if (c >= 0 && c % _skip == 0)                    {                        var s = _queue.Dequeue();                        s.OnCompleted();                    }                    _n++;                    if (_n % _skip == 0)                    {                        var newWindow = CreateWindow();                        ForwardOnNext(newWindow);                    }                }                public override void OnError(Exception error)                {                    while (_queue.Count > 0)                    {                        _queue.Dequeue().OnError(error);                    }                    ForwardOnError(error);                }                public override void OnCompleted()                {                    while (_queue.Count > 0)                    {                        _queue.Dequeue().OnCompleted();                    }                    ForwardOnCompleted();                }            }        }        internal sealed class TimeSliding : Producer<IObservable<TSource>, TimeSliding._>        {            private readonly IObservable<TSource> _source;            private readonly TimeSpan _timeSpan;            private readonly TimeSpan _timeShift;            private readonly IScheduler _scheduler;            public TimeSliding(IObservable<TSource> source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _timeShift = timeShift;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly object _gate = new object();                private readonly Queue<ISubject<TSource>> _q = new Queue<ISubject<TSource>>();                private readonly SerialDisposable _timerD = new SerialDisposable();                private readonly IScheduler _scheduler;                private readonly TimeSpan _timeShift;                public _(TimeSliding parent, IObserver<IObservable<TSource>> observer)                    : base(observer)                {                    _scheduler = parent._scheduler;                    _timeShift = parent._timeShift;                }                private RefCountDisposable _refCountDisposable;                private TimeSpan _totalTime;                private TimeSpan _nextShift;                private TimeSpan _nextSpan;                public void Run(TimeSliding parent)                {                    _totalTime = TimeSpan.Zero;                    _nextShift = parent._timeShift;                    _nextSpan = parent._timeSpan;                    var groupDisposable = new CompositeDisposable(2) { _timerD };                    _refCountDisposable = new RefCountDisposable(groupDisposable);                    CreateWindow();                    CreateTimer();                    groupDisposable.Add(parent._source.SubscribeSafe(this));                    SetUpstream(_refCountDisposable);                }                private void CreateWindow()                {                    var s = new Subject<TSource>();                    _q.Enqueue(s);                    ForwardOnNext(new WindowObservable<TSource>(s, _refCountDisposable));                }                private void CreateTimer()                {                    var m = new SingleAssignmentDisposable();                    _timerD.Disposable = m;                    var isSpan = false;                    var isShift = false;                    if (_nextSpan == _nextShift)                    {                        isSpan = true;                        isShift = true;                    }                    else if (_nextSpan < _nextShift)                    {                        isSpan = true;                    }                    else                    {                        isShift = true;                    }                    var newTotalTime = isSpan ? _nextSpan : _nextShift;                    var ts = newTotalTime - _totalTime;                    _totalTime = newTotalTime;                    if (isSpan)                    {                        _nextSpan += _timeShift;                    }                    if (isShift)                    {                        _nextShift += _timeShift;                    }                    m.Disposable = _scheduler.ScheduleAction((@this: this, isSpan, isShift), ts, tuple => [email protected](tuple.isSpan, tuple.isShift));                }                private void Tick(bool isSpan, bool isShift)                {                    lock (_gate)                    {                        //                        // BREAKING CHANGE v2 > v1.x - Making behavior of sending OnCompleted to the window                        //                             before sending out a new window consistent across all                        //                             overloads of Window and Buffer. Before v2, the two                        //                             operations below were reversed.                        //                        if (isSpan)                        {                            var s = _q.Dequeue();                            s.OnCompleted();                        }                        if (isShift)                        {                            CreateWindow();                        }                    }                    CreateTimer();                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        foreach (var s in _q)                        {                            s.OnNext(value);                        }                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        foreach (var s in _q)                        {                            s.OnError(error);                        }                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        foreach (var s in _q)                        {                            s.OnCompleted();                        }                        ForwardOnCompleted();                    }                }            }        }        internal sealed class TimeHopping : Producer<IObservable<TSource>, TimeHopping._>        {            private readonly IObservable<TSource> _source;            private readonly TimeSpan _timeSpan;            private readonly IScheduler _scheduler;            public TimeHopping(IObservable<TSource> source, TimeSpan timeSpan, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly object _gate = new object();                public _(IObserver<IObservable<TSource>> observer)                    : base(observer)                {                }                private Subject<TSource> _subject;                private RefCountDisposable _refCountDisposable;                public void Run(TimeHopping parent)                {                    var groupDisposable = new CompositeDisposable(2);                    _refCountDisposable = new RefCountDisposable(groupDisposable);                    CreateWindow();                    groupDisposable.Add(parent._scheduler.SchedulePeriodic(this, parent._timeSpan, @this => @this.Tick()));                    groupDisposable.Add(parent._source.SubscribeSafe(this));                    SetUpstream(_refCountDisposable);                }                private void Tick()                {                    lock (_gate)                    {                        _subject.OnCompleted();                        CreateWindow();                    }                }                private void CreateWindow()                {                    _subject = new Subject<TSource>();                    ForwardOnNext(new WindowObservable<TSource>(_subject, _refCountDisposable));                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _subject.OnNext(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _subject.OnError(error);                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        _subject.OnCompleted();                        ForwardOnCompleted();                    }                }            }        }        internal sealed class Ferry : Producer<IObservable<TSource>, Ferry._>        {            private readonly IObservable<TSource> _source;            private readonly int _count;            private readonly TimeSpan _timeSpan;            private readonly IScheduler _scheduler;            public Ferry(IObservable<TSource> source, TimeSpan timeSpan, int count, IScheduler scheduler)            {                _source = source;                _timeSpan = timeSpan;                _count = count;                _scheduler = scheduler;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(_source);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly object _gate = new object();                private readonly SerialDisposable _timerD = new SerialDisposable();                private readonly int _count;                private readonly TimeSpan _timeSpan;                private readonly IScheduler _scheduler;                public _(Ferry parent, IObserver<IObservable<TSource>> observer)                    : base(observer)                {                    _count = parent._count;                    _timeSpan = parent._timeSpan;                    _scheduler = parent._scheduler;                }                private Subject<TSource> _s;                private int _n;                private RefCountDisposable _refCountDisposable;                public override void Run(IObservable<TSource> source)                {                    var groupDisposable = new CompositeDisposable(2) { _timerD };                    _refCountDisposable = new RefCountDisposable(groupDisposable);                    _s = new Subject<TSource>();                    ForwardOnNext(new WindowObservable<TSource>(_s, _refCountDisposable));                    CreateTimer(_s);                    groupDisposable.Add(source.SubscribeSafe(this));                    SetUpstream(_refCountDisposable);                }                private void CreateTimer(Subject<TSource> window)                {                    var m = new SingleAssignmentDisposable();                    _timerD.Disposable = m;                    m.Disposable = _scheduler.ScheduleAction((@this: this, window), _timeSpan, tuple => [email protected](tuple.window));                }                private void Tick(Subject<TSource> window)                {                    Subject<TSource> newWindow;                    lock (_gate)                    {                        if (window != _s)                        {                            return;                        }                        _n = 0;                        newWindow = new Subject<TSource>();                        _s.OnCompleted();                        _s = newWindow;                        ForwardOnNext(new WindowObservable<TSource>(_s, _refCountDisposable));                    }                    CreateTimer(newWindow);                }                public override void OnNext(TSource value)                {                    Subject<TSource> newWindow = null;                    lock (_gate)                    {                        _s.OnNext(value);                        _n++;                        if (_n == _count)                        {                            _n = 0;                            newWindow = new Subject<TSource>();                            _s.OnCompleted();                            _s = newWindow;                            ForwardOnNext(new WindowObservable<TSource>(_s, _refCountDisposable));                        }                    }                    if (newWindow != null)                    {                        CreateTimer(newWindow);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _s.OnError(error);                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        _s.OnCompleted();                        ForwardOnCompleted();                    }                }            }        }    }    internal static class Window<TSource, TWindowClosing>    {        internal sealed class Selector : Producer<IObservable<TSource>, Selector._>        {            private readonly IObservable<TSource> _source;            private readonly Func<IObservable<TWindowClosing>> _windowClosingSelector;            public Selector(IObservable<TSource> source, Func<IObservable<TWindowClosing>> windowClosingSelector)            {                _source = source;                _windowClosingSelector = windowClosingSelector;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(this, observer);            protected override void Run(_ sink) => sink.Run(_source);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly object _gate = new object();                private readonly AsyncLock _windowGate = new AsyncLock();                private readonly SerialDisposable _m = new SerialDisposable();                private readonly Func<IObservable<TWindowClosing>> _windowClosingSelector;                public _(Selector parent, IObserver<IObservable<TSource>> observer)                    : base(observer)                {                    _windowClosingSelector = parent._windowClosingSelector;                }                private ISubject<TSource> _window;                private RefCountDisposable _refCountDisposable;                public override void Run(IObservable<TSource> source)                {                    _window = new Subject<TSource>();                    var groupDisposable = new CompositeDisposable(2) { _m };                    _refCountDisposable = new RefCountDisposable(groupDisposable);                    var window = new WindowObservable<TSource>(_window, _refCountDisposable);                    ForwardOnNext(window);                    groupDisposable.Add(source.SubscribeSafe(this));                    _windowGate.Wait(this, @this => @this.CreateWindowClose());                    SetUpstream(_refCountDisposable);                }                private void CreateWindowClose()                {                    IObservable<TWindowClosing> windowClose;                    try                    {                        windowClose = _windowClosingSelector();                    }                    catch (Exception exception)                    {                        lock (_gate)                        {                            ForwardOnError(exception);                        }                        return;                    }                    var observer = new WindowClosingObserver(this);                    _m.Disposable = observer;                    observer.SetResource(windowClose.SubscribeSafe(observer));                }                private void CloseWindow(IDisposable closingSubscription)                {                    closingSubscription.Dispose();                    lock (_gate)                    {                        _window.OnCompleted();                        _window = new Subject<TSource>();                        var window = new WindowObservable<TSource>(_window, _refCountDisposable);                        ForwardOnNext(window);                    }                    _windowGate.Wait(this, @this => @this.CreateWindowClose());                }                private sealed class WindowClosingObserver : SafeObserver<TWindowClosing>                {                    private readonly _ _parent;                    public WindowClosingObserver(_ parent)                    {                        _parent = parent;                    }                    public override void OnNext(TWindowClosing value)                    {                        _parent.CloseWindow(this);                    }                    public override void OnError(Exception error)                    {                        _parent.OnError(error);                    }                    public override void OnCompleted()                    {                        _parent.CloseWindow(this);                    }                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _window.OnNext(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _window.OnError(error);                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        _window.OnCompleted();                        ForwardOnCompleted();                    }                }            }        }        internal sealed class Boundaries : Producer<IObservable<TSource>, Boundaries._>        {            private readonly IObservable<TSource> _source;            private readonly IObservable<TWindowClosing> _windowBoundaries;            public Boundaries(IObservable<TSource> source, IObservable<TWindowClosing> windowBoundaries)            {                _source = source;                _windowBoundaries = windowBoundaries;            }            protected override _ CreateSink(IObserver<IObservable<TSource>> observer) => new _(observer);            protected override void Run(_ sink) => sink.Run(this);            internal sealed class _ : Sink<TSource, IObservable<TSource>>            {                private readonly object _gate = new object();                public _(IObserver<IObservable<TSource>> observer)                    : base(observer)                {                }                private ISubject<TSource> _window;                private RefCountDisposable _refCountDisposable;                public void Run(Boundaries parent)                {                    _window = new Subject<TSource>();                    var d = new CompositeDisposable(2);                    _refCountDisposable = new RefCountDisposable(d);                    var window = new WindowObservable<TSource>(_window, _refCountDisposable);                    ForwardOnNext(window);                    d.Add(parent._source.SubscribeSafe(this));                    d.Add(parent._windowBoundaries.SubscribeSafe(new WindowClosingObserver(this)));                    SetUpstream(_refCountDisposable);                }                private sealed class WindowClosingObserver : IObserver<TWindowClosing>                {                    private readonly _ _parent;                    public WindowClosingObserver(_ parent)                    {                        _parent = parent;                    }                    public void OnNext(TWindowClosing value)                    {                        lock (_parent._gate)                        {                            _parent._window.OnCompleted();                            _parent._window = new Subject<TSource>();                            var window = new WindowObservable<TSource>(_parent._window, _parent._refCountDisposable);                            _parent.ForwardOnNext(window);                        }                    }                    public void OnError(Exception error)                    {                        _parent.OnError(error);                    }                    public void OnCompleted()                    {                        _parent.OnCompleted();                    }                }                public override void OnNext(TSource value)                {                    lock (_gate)                    {                        _window.OnNext(value);                    }                }                public override void OnError(Exception error)                {                    lock (_gate)                    {                        _window.OnError(error);                        ForwardOnError(error);                    }                }                public override void OnCompleted()                {                    lock (_gate)                    {                        _window.OnCompleted();                        ForwardOnCompleted();                    }                }            }        }    }    internal sealed class WindowObservable<TSource> : AddRef<TSource>    {        public WindowObservable(IObservable<TSource> source, RefCountDisposable refCount)            : base(source, refCount)        {        }    }}
 |