diff --git a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs index 460f690..6427519 100644 --- a/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs +++ b/src/ObservableCollections.R3/ObservableCollectionR3Extensions.cs @@ -36,6 +36,11 @@ public static class ObservableCollectionR3Extensions { return new ObservableCollectionReset(source, cancellationToken); } + + public static Observable ObserveCountChanged(this IObservableCollection source, bool notifyCurrentCount = false, CancellationToken cancellationToken = default) + { + return new ObservableCollectionCountChanged(source, notifyCurrentCount, cancellationToken); + } } sealed class ObservableCollectionAdd(IObservableCollection collection, CancellationToken cancellationToken) @@ -180,6 +185,49 @@ sealed class ObservableCollectionReset(IObservableCollection collection, C } } +sealed class ObservableCollectionCountChanged(IObservableCollection collection, bool notifyCurrentCount, CancellationToken cancellationToken) + : Observable +{ + protected override IDisposable SubscribeCore(Observer observer) + { + return new _ObservableCollectionCountChanged(collection, notifyCurrentCount, observer, cancellationToken); + } + + sealed class _ObservableCollectionCountChanged : ObservableCollectionObserverBase + { + readonly IObservableCollection collection; + int countPrev; + + public _ObservableCollectionCountChanged( + IObservableCollection collection, + bool notifyCurrentCount, + Observer observer, + CancellationToken cancellationToken) : base(collection, observer, cancellationToken) + { + this.collection = collection; + this.countPrev = collection.Count; + if (notifyCurrentCount) + { + observer.OnNext(collection.Count); + } + } + + protected override void Handler(in NotifyCollectionChangedEventArgs eventArgs) + { + switch (eventArgs.Action) + { + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Remove: + case NotifyCollectionChangedAction.Reset when countPrev != collection.Count: + observer.OnNext(collection.Count); + break; + } + countPrev = collection.Count; + } + } +} + + abstract class ObservableCollectionObserverBase : IDisposable { protected readonly IObservableCollection collection; diff --git a/src/ObservableCollections.Unity/Assets/Plugins/ObservableCollections/Runtime/Internal/CloneCollection.cs b/src/ObservableCollections.Unity/Assets/Plugins/ObservableCollections/Runtime/Internal/CloneCollection.cs index 0c830f6..1e3193b 100644 --- a/src/ObservableCollections.Unity/Assets/Plugins/ObservableCollections/Runtime/Internal/CloneCollection.cs +++ b/src/ObservableCollections.Unity/Assets/Plugins/ObservableCollections/Runtime/Internal/CloneCollection.cs @@ -49,7 +49,7 @@ namespace ObservableCollections.Internal } else { - var array = ArrayPool.Shared.Rent(count); + var array = ArrayPool.Shared.Rent(16); var i = 0; foreach (var item in source) @@ -75,8 +75,8 @@ namespace ObservableCollections.Internal if (array.Length == index) { ArrayPool.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences()); + array = ArrayPool.Shared.Rent(index * 2); } - array = ArrayPool.Shared.Rent(index * 2); } public void Dispose() diff --git a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs index b7044d4..a0885cc 100644 --- a/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs +++ b/tests/ObservableCollections.R3.Tests/ObservableCollectionExtensionsTest.cs @@ -132,4 +132,43 @@ public class ObservableCollectionExtensionsTest collection.Move(1, 2); events.Count.Should().Be(1); } + + [Fact] + public void ObserveCountChanged() + { + var events = new List(); + var collection = new ObservableList([111, 222, 333]); + + using var _ = collection.ObserveCountChanged().Subscribe(count => events.Add(count)); + + events.Should().BeEmpty(); + + collection.Add(444); + events[0].Should().Be(4); + + collection.Remove(111); + events[1].Should().Be(3); + + collection.Move(0, 1); + events.Count.Should().Be(2); + + collection[0] = 999; + events.Count.Should().Be(2); + + collection.Clear(); + events[2].Should().Be(0); + + collection.Clear(); + events.Count.Should().Be(3); + } + + [Fact] + public void ObserveCountChanged_NotifyCurrent() + { + var events = new List(); + var collection = new ObservableList([111, 222, 333]); + + var subscription = collection.ObserveCountChanged(notifyCurrentCount: true).Subscribe(count => events.Add(count)); + events[0].Should().Be(3); + } } \ No newline at end of file