Skip to content

Commit

Permalink
Merge pull request #45 from TORISOUP/add_readonlyObservableDictionary
Browse files Browse the repository at this point in the history
Add IReadOnlyObservableDictionary interface and ObservableDictionaryR3Extensions
  • Loading branch information
neuecc authored Jun 10, 2024
2 parents 229ad89 + ecce6be commit 7e139dc
Show file tree
Hide file tree
Showing 4 changed files with 248 additions and 25 deletions.
132 changes: 132 additions & 0 deletions src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Threading;
using R3;
Expand All @@ -10,6 +11,13 @@ namespace ObservableCollections;
public readonly record struct CollectionReplaceEvent<T>(int Index, T OldValue, T NewValue);
public readonly record struct CollectionMoveEvent<T>(int OldIndex, int NewIndex, T Value);

public readonly record struct DictionaryAddEvent<TKey, TValue>(TKey Key, TValue Value);

public readonly record struct DictionaryRemoveEvent<TKey, TValue>(TKey Key, TValue Value);

public readonly record struct DictionaryReplaceEvent<TKey, TValue>(TKey Key, TValue OldValue, TValue NewValue);


public static class ObservableCollectionR3Extensions
{
public static Observable<CollectionAddEvent<T>> ObserveAdd<T>(this IObservableCollection<T> source, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -43,6 +51,26 @@ public static Observable<int> ObserveCountChanged<T>(this IObservableCollection<
}
}

public static class ObservableDictionaryR3Extensions
{
public static Observable<DictionaryAddEvent<TKey, TValue>> ObserveDictionaryAdd<TKey, TValue>(this IReadOnlyObservableDictionary<TKey, TValue> source,
CancellationToken cancellationToken = default)
{
return new ObservableDictionaryAdd<TKey, TValue>(source, cancellationToken);
}

public static Observable<DictionaryRemoveEvent<TKey, TValue>> ObserveDictionaryRemove<TKey, TValue>(this IReadOnlyObservableDictionary<TKey, TValue> source,
CancellationToken cancellationToken = default)
{
return new ObservableDictionaryRemove<TKey, TValue>(source, cancellationToken);
}
public static Observable<DictionaryReplaceEvent<TKey, TValue>> ObserveDictionaryReplace<TKey, TValue>(this IReadOnlyObservableDictionary<TKey, TValue> source,
CancellationToken cancellationToken = default)
{
return new ObservableDictionaryReplace<TKey, TValue>(source, cancellationToken);
}
}

sealed class ObservableCollectionAdd<T>(IObservableCollection<T> collection, CancellationToken cancellationToken)
: Observable<CollectionAddEvent<T>>
{
Expand Down Expand Up @@ -225,6 +253,110 @@ protected override void Handler(in NotifyCollectionChangedEventArgs<T> eventArgs
}
}

sealed class ObservableDictionaryAdd<TKey, TValue>(
IReadOnlyObservableDictionary<TKey, TValue> dictionary,
CancellationToken cancellationToken) : Observable<DictionaryAddEvent<TKey, TValue>>
{
protected override IDisposable SubscribeCore(Observer<DictionaryAddEvent<TKey, TValue>> observer)
{
return new _DictionaryCollectionAdd(dictionary, observer, cancellationToken);
}

sealed class _DictionaryCollectionAdd(
IObservableCollection<KeyValuePair<TKey, TValue>> collection,
Observer<DictionaryAddEvent<TKey, TValue>> observer,
CancellationToken cancellationToken) :
ObservableCollectionObserverBase<KeyValuePair<TKey, TValue>, DictionaryAddEvent<TKey, TValue>>(collection,
observer, cancellationToken)
{
protected override void Handler(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> eventArgs)
{
if (eventArgs.Action == NotifyCollectionChangedAction.Add)
{
if (eventArgs.IsSingleItem)
{
observer.OnNext(
new DictionaryAddEvent<TKey, TValue>(eventArgs.NewItem.Key, eventArgs.NewItem.Value));
}
else
{
var i = eventArgs.NewStartingIndex;
foreach (var item in eventArgs.NewItems)
{
observer.OnNext(new DictionaryAddEvent<TKey, TValue>(item.Key, item.Value));
}
}
}
}
}
}

sealed class ObservableDictionaryRemove<TKey, TValue>(
IReadOnlyObservableDictionary<TKey, TValue> dictionary,
CancellationToken cancellationToken) : Observable<DictionaryRemoveEvent<TKey, TValue>>
{
protected override IDisposable SubscribeCore(Observer<DictionaryRemoveEvent<TKey, TValue>> observer)
{
return new _DictionaryCollectionRemove(dictionary, observer, cancellationToken);
}

sealed class _DictionaryCollectionRemove(
IObservableCollection<KeyValuePair<TKey, TValue>> collection,
Observer<DictionaryRemoveEvent<TKey, TValue>> observer,
CancellationToken cancellationToken) :
ObservableCollectionObserverBase<KeyValuePair<TKey, TValue>, DictionaryRemoveEvent<TKey, TValue>>(collection,
observer, cancellationToken)
{
protected override void Handler(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> eventArgs)
{
if (eventArgs.Action == NotifyCollectionChangedAction.Remove)
{
if (eventArgs.IsSingleItem)
{
observer.OnNext(
new DictionaryRemoveEvent<TKey, TValue>(eventArgs.OldItem.Key, eventArgs.OldItem.Value));
}
else
{
var i = eventArgs.NewStartingIndex;
foreach (var item in eventArgs.NewItems)
{
observer.OnNext(new DictionaryRemoveEvent<TKey, TValue>(item.Key, item.Value));
}
}
}
}
}
}

sealed class ObservableDictionaryReplace<TKey, TValue>(
IReadOnlyObservableDictionary<TKey, TValue> dictionary,
CancellationToken cancellationToken) : Observable<DictionaryReplaceEvent<TKey, TValue>>
{
protected override IDisposable SubscribeCore(Observer<DictionaryReplaceEvent<TKey, TValue>> observer)
{
return new _DictionaryCollectionReplace(dictionary, observer, cancellationToken);
}

sealed class _DictionaryCollectionReplace(
IObservableCollection<KeyValuePair<TKey, TValue>> collection,
Observer<DictionaryReplaceEvent<TKey, TValue>> observer,
CancellationToken cancellationToken) :
ObservableCollectionObserverBase<KeyValuePair<TKey, TValue>, DictionaryReplaceEvent<TKey, TValue>>(collection,
observer, cancellationToken)
{
protected override void Handler(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> eventArgs)
{
if (eventArgs.Action == NotifyCollectionChangedAction.Replace)
{
observer.OnNext(new DictionaryReplaceEvent<TKey, TValue>(
eventArgs.NewItem.Key,
eventArgs.OldItem.Value,
eventArgs.NewItem.Value));
}
}
}
}

abstract class ObservableCollectionObserverBase<T, TEvent> : IDisposable
{
Expand Down
5 changes: 5 additions & 0 deletions src/ObservableCollections/IObservableCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public interface IObservableCollection<T> : IReadOnlyCollection<T>
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
}

public interface IReadOnlyObservableDictionary<TKey, TValue> :
IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
{
}

public interface IFreezedCollection<T>
{
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
Expand Down
4 changes: 2 additions & 2 deletions src/ObservableCollections/ObservableDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

namespace ObservableCollections
{
public sealed partial class ObservableDictionary<TKey, TValue>
: IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>, IObservableCollection<KeyValuePair<TKey, TValue>>
public sealed partial class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>,
IReadOnlyObservableDictionary<TKey, TValue>
where TKey : notnull
{
readonly Dictionary<TKey, TValue> dictionary;
Expand Down
Loading

0 comments on commit 7e139dc

Please sign in to comment.