public void OnNext(DictionaryModification <TKey, TValue> value)
            {
                if (DictionaryModification <TKey, TValue> .Initialised == value)
                {
                    _dictionary._subject.OnNext(DictionaryNotification.Initialised <TKey, TValue>());
                }
                else
                {
                    switch (value.Type)
                    {
                    case DictionaryModificationType.Upsert:
                        Upsert(value);
                        break;

                    case DictionaryModificationType.Replace:
                        Replace(value);
                        break;

                    case DictionaryModificationType.Remove:
                        Remove(value);
                        break;

                    case DictionaryModificationType.Clear:
                        Clear();
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
        public IDisposable Subscribe(IObserver <DictionaryNotification <TKey, TValue> > observer)
        {
            var futureDisposable = new SingleAssignmentDisposable();

            var scheduledWorkDisposable = _scheduler.Schedule(() =>
            {
                if (_isDisposed)
                {
                    futureDisposable.Disposable =
                        Observable.Throw <DictionaryNotification <TKey, TValue> >(
                            new ObjectDisposedException(this.GetType().Name)).Subscribe(observer);
                }

                if (_error != null)
                {
                    futureDisposable.Disposable = Observable.Throw <DictionaryNotification <TKey, TValue> >(_error).Subscribe(observer);
                }

                var existingValues = _state.ToList();

                foreach (var existingValue in existingValues)
                {
                    observer.OnNext(DictionaryNotification.Existing(existingValue.Key, existingValue.Value));
                }
                observer.OnNext(DictionaryNotification.Initialised <TKey, TValue>());

                futureDisposable.Disposable = new CompositeDisposable(_subject.Subscribe(observer), Connect());
            });

            return(new CompositeDisposable(scheduledWorkDisposable, futureDisposable));
        }
            private void Upsert(DictionaryModification <TKey, TValue> modification)
            {
                TValue existingValue;

                if (_dictionary._state.TryGetValue(modification.Key, out existingValue))
                {
                    try
                    {
                        var newValue = _dictionary._updateFunction(modification.Key, existingValue, modification.Value);

                        _dictionary._state[modification.Key] = newValue;
                        _dictionary._subject.OnNext(DictionaryNotification.Updated(modification.Key, newValue,
                                                                                   modification.Value, existingValue));
                    }
                    catch (Exception ex)
                    {
                        _dictionary._error = ex;
                        _dictionary._subject.OnError(
                            new ObservableDictionaryUpdateException("Exception thrown when updating " + modification, ex));
                    }
                }
                else
                {
                    _dictionary._state[modification.Key] = modification.Value;
                    _dictionary._subject.OnNext(DictionaryNotification.Inserted(modification.Key, modification.Value));
                }
            }
Beispiel #4
0
        public IDisposable Subscribe(IObserver <DictionaryNotification <TKey, TValue> > observer)
        {
            lock (_lock)
            {
                if (_isDisposed)
                {
                    return
                        (Observable.Throw <DictionaryNotification <TKey, TValue> >(
                             new ObjectDisposedException(this.GetType().Name)).Subscribe(observer));
                }

                if (_error != null)
                {
                    return(Observable.Throw <DictionaryNotification <TKey, TValue> >(_error).Subscribe(observer));
                }

                var existingValues = _state.ToList();

                foreach (var existingValue in existingValues)
                {
                    observer.OnNext(DictionaryNotification.Existing(existingValue.Key, existingValue.Value));
                }
                observer.OnNext(DictionaryNotification.Initialised <TKey, TValue>());

                return(new CompositeDisposable(_subject.Subscribe(observer), Connect()));
            }
        }
Beispiel #5
0
 private void Clear()
 {
     // todo emit a Removed<> for each item in the DB, rather than just clearing?
     // todo not atomic without locks.
     _dictionary._state.Clear();
     _dictionary._subject.OnNext(DictionaryNotification.Cleared <TKey, TValue>());
 }
Beispiel #6
0
            private void Upsert(DictionaryModification <TKey, TValue> modification)
            {
                TValue existingValue;

                if (_dictionary._state.TryGetValue(modification.Key, out existingValue))
                {
                    try
                    {
                        // TODO Check order is correct here.
                        var newValue = _dictionary._updateFunction.Invoke(modification.Key, existingValue,
                                                                          modification.Value);

                        _dictionary._state[modification.Key] = newValue;
                        _dictionary._subject.OnNext(DictionaryNotification.Updated(modification.Key, newValue,
                                                                                   modification.Value, existingValue));
                    }
                    catch (Exception ex)
                    {
                        // TODO Check that this errors the whole stream.
                        _dictionary._error = ex;
                        _dictionary._subject.OnError(
                            new ObservableDictionaryUpdateException("Exception thrown when updating " + modification, ex));
                    }
                }
                else
                {
                    _dictionary._state[modification.Key] = modification.Value;
                    _dictionary._subject.OnNext(DictionaryNotification.Inserted(modification.Key, modification.Value));
                }
            }
 private void Clear()
 {
     foreach (var kvp in _dictionary._state)
     {
         _dictionary._subject.OnNext(DictionaryNotification.KeyCleared(kvp.Key, kvp.Value));
     }
     _dictionary._subject.OnNext(DictionaryNotification.DictionaryCleared <TKey, TValue>());
     _dictionary._state.Clear();
 }
            private void Remove(DictionaryModification <TKey, TValue> modification)
            {
                TValue removedValue;

                if (_dictionary._state.TryGetValue(modification.Key, out removedValue))
                {
                    _dictionary._state.Remove(modification.Key);
                    _dictionary._subject.OnNext(DictionaryNotification.Removed(modification.Key, removedValue));
                }
                // Design decision: We don't signal 'removed' for a value that didn't exist.
            }
Beispiel #9
0
            private void Remove(DictionaryModification <TKey, TValue> modification)
            {
                TValue removedValue;

                if (_dictionary._state.TryGetValue(modification.Key, out removedValue))
                {
                    _dictionary._state.Remove(modification.Key);
                    // TODO Should we signal 'removed' for a value that didn't exist..?
                    _dictionary._subject.OnNext(DictionaryNotification.Removed(modification.Key, removedValue));
                }
            }
Beispiel #10
0
            private void Replace(DictionaryModification <TKey, TValue> modification)
            {
                TValue existingValue;

                if (_dictionary._state.TryGetValue(modification.Key, out existingValue))
                {
                    _dictionary._subject.OnNext(DictionaryNotification.Replaced(modification.Key, modification.Value,
                                                                                existingValue));
                }
                else
                {
                    // TODO Should we do an upsert when the item to be replaced doesn't exist, or signal replaced with a missing value?
                    Upsert(modification);
                }
            }
            private void Replace(DictionaryModification <TKey, TValue> modification)
            {
                TValue existingValue;

                if (_dictionary._state.TryGetValue(modification.Key, out existingValue))
                {
                    _dictionary._state[modification.Key] = modification.Value;
                    _dictionary._subject.OnNext(DictionaryNotification.Replaced(modification.Key, modification.Value,
                                                                                existingValue));
                }
                else
                {
                    // Design decision: we do an upsert when the item to be replaced doesn't exist, rather than signal replaced with a missing value.
                    Upsert(modification);
                }
            }
 public IObservable <DictionaryNotification <TKey, TValue> > Get(TKey key)
 {
     return(Observable.Create <DictionaryNotification <TKey, TValue> >(observer =>
     {
         TValue existingValue;
         if (_state.TryGetValue(key, out existingValue))
         {
             observer.OnNext(DictionaryNotification.Existing(key, existingValue));
         }
         else
         {
             observer.OnNext(DictionaryNotification.Missing <TKey, TValue>(key));
         }
         return new CompositeDisposable(_subject
                                        .Where(dn => dn.Type == DictionaryNotificationType.KeyCleared || Equals(dn.Key, key))
                                        .Subscribe(observer), Connect());
     })
            .SubscribeOn(_scheduler));
 }
Beispiel #13
0
 public IObservable <DictionaryNotification <TKey, TValue> > Get(TKey key)
 {
     return(Observable.Create <DictionaryNotification <TKey, TValue> >(observer =>
     {
         lock (_lock)
         {
             TValue existingValue;
             if (_state.TryGetValue(key, out existingValue))
             {
                 observer.OnNext(DictionaryNotification.Existing(key, existingValue));
             }
             else
             {
                 observer.OnNext(DictionaryNotification.Missing <TKey, TValue>(key));
             }
             return new CompositeDisposable(_subject.Subscribe(observer), Connect());
         }
     }));
 }