UniRx 에셋 추가
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
public struct CollectionAddEvent<T> : IEquatable<CollectionAddEvent<T>>
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
public T Value { get; private set; }
|
||||
|
||||
public CollectionAddEvent(int index, T value)
|
||||
:this()
|
||||
{
|
||||
Index = index;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Index:{0} Value:{1}", Index, Value);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(Value) << 2;
|
||||
}
|
||||
|
||||
public bool Equals(CollectionAddEvent<T> other)
|
||||
{
|
||||
return Index.Equals(other.Index) && EqualityComparer<T>.Default.Equals(Value, other.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public struct CollectionRemoveEvent<T> : IEquatable<CollectionRemoveEvent<T>>
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
public T Value { get; private set; }
|
||||
|
||||
public CollectionRemoveEvent(int index, T value)
|
||||
: this()
|
||||
{
|
||||
Index = index;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Index:{0} Value:{1}", Index, Value);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(Value) << 2;
|
||||
}
|
||||
|
||||
public bool Equals(CollectionRemoveEvent<T> other)
|
||||
{
|
||||
return Index.Equals(other.Index) && EqualityComparer<T>.Default.Equals(Value, other.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public struct CollectionMoveEvent<T> : IEquatable<CollectionMoveEvent<T>>
|
||||
{
|
||||
public int OldIndex { get; private set; }
|
||||
public int NewIndex { get; private set; }
|
||||
public T Value { get; private set; }
|
||||
|
||||
public CollectionMoveEvent(int oldIndex, int newIndex, T value)
|
||||
: this()
|
||||
{
|
||||
OldIndex = oldIndex;
|
||||
NewIndex = newIndex;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("OldIndex:{0} NewIndex:{1} Value:{2}", OldIndex, NewIndex, Value);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return OldIndex.GetHashCode() ^ NewIndex.GetHashCode() << 2 ^ EqualityComparer<T>.Default.GetHashCode(Value) >> 2;
|
||||
}
|
||||
|
||||
public bool Equals(CollectionMoveEvent<T> other)
|
||||
{
|
||||
return OldIndex.Equals(other.OldIndex) && NewIndex.Equals(other.NewIndex) && EqualityComparer<T>.Default.Equals(Value, other.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public struct CollectionReplaceEvent<T> : IEquatable<CollectionReplaceEvent<T>>
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
public T OldValue { get; private set; }
|
||||
public T NewValue { get; private set; }
|
||||
|
||||
public CollectionReplaceEvent(int index, T oldValue, T newValue)
|
||||
: this()
|
||||
{
|
||||
Index = index;
|
||||
OldValue = oldValue;
|
||||
NewValue = newValue;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Index:{0} OldValue:{1} NewValue:{2}", Index, OldValue, NewValue);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(OldValue) << 2 ^ EqualityComparer<T>.Default.GetHashCode(NewValue) >> 2;
|
||||
}
|
||||
|
||||
public bool Equals(CollectionReplaceEvent<T> other)
|
||||
{
|
||||
return Index.Equals(other.Index)
|
||||
&& EqualityComparer<T>.Default.Equals(OldValue, other.OldValue)
|
||||
&& EqualityComparer<T>.Default.Equals(NewValue, other.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
// IReadOnlyList<out T> is from .NET 4.5
|
||||
public interface IReadOnlyReactiveCollection<T> : IEnumerable<T>
|
||||
{
|
||||
int Count { get; }
|
||||
T this[int index] { get; }
|
||||
IObservable<CollectionAddEvent<T>> ObserveAdd();
|
||||
IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false);
|
||||
IObservable<CollectionMoveEvent<T>> ObserveMove();
|
||||
IObservable<CollectionRemoveEvent<T>> ObserveRemove();
|
||||
IObservable<CollectionReplaceEvent<T>> ObserveReplace();
|
||||
IObservable<Unit> ObserveReset();
|
||||
}
|
||||
|
||||
public interface IReactiveCollection<T> : IList<T>, IReadOnlyReactiveCollection<T>
|
||||
{
|
||||
new int Count { get; }
|
||||
new T this[int index] { get; set; }
|
||||
void Move(int oldIndex, int newIndex);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ReactiveCollection<T> : Collection<T>, IReactiveCollection<T>, IDisposable
|
||||
{
|
||||
[NonSerialized]
|
||||
bool isDisposed = false;
|
||||
|
||||
public ReactiveCollection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ReactiveCollection(IEnumerable<T> collection)
|
||||
{
|
||||
if (collection == null) throw new ArgumentNullException("collection");
|
||||
|
||||
foreach (var item in collection)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public ReactiveCollection(List<T> list)
|
||||
: base(list != null ? new List<T>(list) : null)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
var beforeCount = Count;
|
||||
base.ClearItems();
|
||||
|
||||
if (collectionReset != null) collectionReset.OnNext(Unit.Default);
|
||||
if (beforeCount > 0)
|
||||
{
|
||||
if (countChanged != null) countChanged.OnNext(Count);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InsertItem(int index, T item)
|
||||
{
|
||||
base.InsertItem(index, item);
|
||||
|
||||
if (collectionAdd != null) collectionAdd.OnNext(new CollectionAddEvent<T>(index, item));
|
||||
if (countChanged != null) countChanged.OnNext(Count);
|
||||
}
|
||||
|
||||
public void Move(int oldIndex, int newIndex)
|
||||
{
|
||||
MoveItem(oldIndex, newIndex);
|
||||
}
|
||||
|
||||
protected virtual void MoveItem(int oldIndex, int newIndex)
|
||||
{
|
||||
T item = this[oldIndex];
|
||||
base.RemoveItem(oldIndex);
|
||||
base.InsertItem(newIndex, item);
|
||||
|
||||
if (collectionMove != null) collectionMove.OnNext(new CollectionMoveEvent<T>(oldIndex, newIndex, item));
|
||||
}
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
T item = this[index];
|
||||
base.RemoveItem(index);
|
||||
|
||||
if (collectionRemove != null) collectionRemove.OnNext(new CollectionRemoveEvent<T>(index, item));
|
||||
if (countChanged != null) countChanged.OnNext(Count);
|
||||
}
|
||||
|
||||
protected override void SetItem(int index, T item)
|
||||
{
|
||||
T oldItem = this[index];
|
||||
base.SetItem(index, item);
|
||||
|
||||
if (collectionReplace != null) collectionReplace.OnNext(new CollectionReplaceEvent<T>(index, oldItem, item));
|
||||
}
|
||||
|
||||
|
||||
[NonSerialized]
|
||||
Subject<int> countChanged = null;
|
||||
public IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false)
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<int>();
|
||||
|
||||
var subject = countChanged ?? (countChanged = new Subject<int>());
|
||||
if (notifyCurrentCount)
|
||||
{
|
||||
return subject.StartWith(() => this.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
Subject<Unit> collectionReset = null;
|
||||
public IObservable<Unit> ObserveReset()
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<Unit>();
|
||||
return collectionReset ?? (collectionReset = new Subject<Unit>());
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
Subject<CollectionAddEvent<T>> collectionAdd = null;
|
||||
public IObservable<CollectionAddEvent<T>> ObserveAdd()
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<CollectionAddEvent<T>>();
|
||||
return collectionAdd ?? (collectionAdd = new Subject<CollectionAddEvent<T>>());
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
Subject<CollectionMoveEvent<T>> collectionMove = null;
|
||||
public IObservable<CollectionMoveEvent<T>> ObserveMove()
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<CollectionMoveEvent<T>>();
|
||||
return collectionMove ?? (collectionMove = new Subject<CollectionMoveEvent<T>>());
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
Subject<CollectionRemoveEvent<T>> collectionRemove = null;
|
||||
public IObservable<CollectionRemoveEvent<T>> ObserveRemove()
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<CollectionRemoveEvent<T>>();
|
||||
return collectionRemove ?? (collectionRemove = new Subject<CollectionRemoveEvent<T>>());
|
||||
}
|
||||
|
||||
[NonSerialized]
|
||||
Subject<CollectionReplaceEvent<T>> collectionReplace = null;
|
||||
public IObservable<CollectionReplaceEvent<T>> ObserveReplace()
|
||||
{
|
||||
if (isDisposed) return Observable.Empty<CollectionReplaceEvent<T>>();
|
||||
return collectionReplace ?? (collectionReplace = new Subject<CollectionReplaceEvent<T>>());
|
||||
}
|
||||
|
||||
void DisposeSubject<TSubject>(ref Subject<TSubject> subject)
|
||||
{
|
||||
if (subject != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
subject.OnCompleted();
|
||||
}
|
||||
finally
|
||||
{
|
||||
subject.Dispose();
|
||||
subject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
|
||||
private bool disposedValue = false;
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
DisposeSubject(ref collectionReset);
|
||||
DisposeSubject(ref collectionAdd);
|
||||
DisposeSubject(ref collectionMove);
|
||||
DisposeSubject(ref collectionRemove);
|
||||
DisposeSubject(ref collectionReplace);
|
||||
DisposeSubject(ref countChanged);
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static partial class ReactiveCollectionExtensions
|
||||
{
|
||||
public static ReactiveCollection<T> ToReactiveCollection<T>(this IEnumerable<T> source)
|
||||
{
|
||||
return new ReactiveCollection<T>(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user