Example #1
0
                public override void OnNext(TLeft value)
                {
                    var s       = new Subject <TRight>();
                    var id      = 0;
                    var rightID = 0;

                    lock (_parent._gate)
                    {
                        id      = _parent._leftID++;
                        rightID = _parent._rightID;
                        _parent._leftMap.Add(id, s);
                    }

                    var window = new WindowObservable <TRight>(s, _parent._refCount);

                    // BREAKING CHANGE v2 > v1.x - Order of evaluation or the _leftDurationSelector and _resultSelector now consistent with Join.

                    var duration = default(IObservable <TLeftDuration>);

                    try
                    {
                        duration = _parent._leftDurationSelector(value);
                    }
                    catch (Exception exception)
                    {
                        OnError(exception);
                        return;
                    }

                    var durationObserver = new DurationObserver(this, id, s);

                    _parent._group.Add(durationObserver);
                    // BREAKING CHANGE v2 > v1.x - The duration sequence is subscribed to before the result sequence is evaluated.
                    durationObserver.SetResource(duration.SubscribeSafe(durationObserver));

                    TResult result;

                    try
                    {
                        result = _parent._resultSelector(value, window);
                    }
                    catch (Exception exception)
                    {
                        OnError(exception);
                        return;
                    }

                    lock (_parent._gate)
                    {
                        _parent.ForwardOnNext(result);

                        foreach (var rightValue in _parent._rightMap)
                        {
                            if (rightValue.Key < rightID)
                            {
                                s.OnNext(rightValue.Value);
                            }
                        }
                    }
                }
Example #2
0
                public override void OnNext(TLeft value)
                {
                    var id      = 0;
                    var rightID = 0;

                    lock (_parent._gate)
                    {
                        id      = _parent._leftID++;
                        rightID = _parent._rightID;
                        _parent._leftMap.Add(id, value);
                    }


                    var duration = default(IObservable <TLeftDuration>);

                    try
                    {
                        duration = _parent._leftDurationSelector(value);
                    }
                    catch (Exception exception)
                    {
                        _parent.ForwardOnError(exception);
                        return;
                    }

                    var durationObserver = new DurationObserver(this, id);

                    _parent._group.Add(durationObserver);

                    durationObserver.SetResource(duration.SubscribeSafe(durationObserver));

                    lock (_parent._gate)
                    {
                        foreach (var rightValue in _parent._rightMap)
                        {
                            if (rightValue.Key < rightID)
                            {
                                var result = default(TResult);
                                try
                                {
                                    result = _parent._resultSelector(value, rightValue.Value);
                                }
                                catch (Exception exception)
                                {
                                    _parent.ForwardOnError(exception);
                                    return;
                                }

                                _parent.ForwardOnNext(result);
                            }
                        }
                    }
                }
Example #3
0
                public override void OnNext(TRight value)
                {
                    int id;
                    int leftID;

                    lock (_parent._gate)
                    {
                        id     = _parent._rightID++;
                        leftID = _parent._leftID;
                        _parent._rightMap.Add(id, value);
                    }

                    IObservable <TRightDuration> duration;

                    try
                    {
                        duration = _parent._rightDurationSelector(value);
                    }
                    catch (Exception exception)
                    {
                        _parent.ForwardOnError(exception);
                        return;
                    }

                    var durationObserver = new DurationObserver(this, id);

                    _parent._group.Add(durationObserver);
                    durationObserver.SetResource(duration.SubscribeSafe(durationObserver));

                    lock (_parent._gate)
                    {
                        foreach (var leftValue in _parent._leftMap)
                        {
                            if (leftValue.Key < leftID)
                            {
                                TResult result;
                                try
                                {
                                    result = _parent._resultSelector(leftValue.Value, value);
                                }
                                catch (Exception exception)
                                {
                                    _parent.ForwardOnError(exception);
                                    return;
                                }

                                _parent.ForwardOnNext(result);
                            }
                        }
                    }
                }
Example #4
0
                public override void OnNext(TRight value)
                {
                    var id     = 0;
                    var leftID = 0;

                    lock (_parent._gate)
                    {
                        id     = _parent._rightID++;
                        leftID = _parent._leftID;
                        _parent._rightMap.Add(id, value);
                    }

                    var duration = default(IObservable <TRightDuration>);

                    try
                    {
                        duration = _parent._rightDurationSelector(value);
                    }
                    catch (Exception exception)
                    {
                        OnError(exception);
                        return;
                    }

                    var durationObserver = new DurationObserver(this, id);

                    _parent._group.Add(durationObserver);
                    durationObserver.SetResource(duration.SubscribeSafe(durationObserver));

                    lock (_parent._gate)
                    {
                        foreach (var o in _parent._leftMap)
                        {
                            if (o.Key < leftID)
                            {
                                o.Value.OnNext(value);
                            }
                        }
                    }
                }
Example #5
0
            public override void OnNext(TSource value)
            {
                TKey key;

                try
                {
                    key = _keySelector(value);
                }
                catch (Exception exception)
                {
                    Error(exception);
                    return;
                }

                var fireNewMapEntry = false;
                ISubject <TElement> writer;

                try
                {
                    //
                    // Note: The box instruction in the IL will be erased by the JIT in case T is
                    //       a value type. In fact, the whole if block will go away and we'll end
                    //       up with nothing but the GetOrAdd call below.
                    //
                    //       See GroupBy for more information and confirmation of this fact using
                    //       the SOS debugger extension.
                    //
                    if (key == null)
                    {
                        lock (_nullGate)
                        {
                            if (_null == null)
                            {
                                _null           = NewSubject();
                                fireNewMapEntry = true;
                            }

                            writer = _null;
                        }
                    }
                    else
                    {
                        writer = _map.GetOrAdd(key, NewSubject, out fireNewMapEntry);
                    }
                }
                catch (Exception exception)
                {
                    Error(exception);
                    return;
                }

                if (fireNewMapEntry)
                {
                    var group = new GroupedObservable <TKey, TElement>(key, writer, _refCountDisposable);

                    var durationGroup = new GroupedObservable <TKey, TElement>(key, writer);

                    IObservable <TDuration> duration;
                    try
                    {
                        duration = _durationSelector(durationGroup);
                    }
                    catch (Exception exception)
                    {
                        Error(exception);
                        return;
                    }

                    lock (_gate)
                    {
                        ForwardOnNext(group);
                    }

                    var durationObserver = new DurationObserver(this, key, writer);
                    _groupDisposable.Add(durationObserver);
                    durationObserver.SetResource(duration.SubscribeSafe(durationObserver));
                }

                TElement element;

                try
                {
                    element = _elementSelector(value);
                }
                catch (Exception exception)
                {
                    Error(exception);
                    return;
                }

                //
                // ISSUE: Rx v1.x shipped without proper handling of the case where the duration
                //        sequence fires concurrently with the OnNext code path here. In such a
                //        case, the subject can be completed before we get a chance to send out
                //        a new element. However, a resurrected group for the same key won't get
                //        to see the element either. To guard against this case, we'd have to
                //        check whether the OnNext call below lost the race, and resurrect a new
                //        group if needed. Unfortunately, this complicates matters when the
                //        duration selector triggers synchronously (e.g. Return or Empty), which
                //        causes the group to terminate immediately. We should not get stuck in
                //        this case, repeatedly trying to resurrect a group that always ends
                //        before we can send the element into it. Also, users may expect this
                //        base case to mean no elements will ever be produced, so sending the
                //        element into the group before starting the duration sequence may not
                //        be a good idea either. For the time being, we'll leave this as-is and
                //        revisit the behavior for vNext. Nonetheless, we'll add synchronization
                //        to ensure no concurrent calls to the subject are made.
                //
                writer.OnNext(element);
            }