UniRx 에셋 추가

This commit is contained in:
Mingu Kim
2025-06-02 00:27:36 +09:00
parent 915f292d7d
commit 8a54d47b56
510 changed files with 42973 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections;
namespace UniRx
{
public sealed class BooleanDisposable : IDisposable, ICancelable
{
public bool IsDisposed { get; private set; }
public BooleanDisposable()
{
}
internal BooleanDisposable(bool isDisposed)
{
IsDisposed = isDisposed;
}
public void Dispose()
{
if (!IsDisposed) IsDisposed = true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4ff95c6eb380ca248984d8c27c1244d0
timeCreated: 1455373899
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
// original code from GitHub Reactive-Extensions/Rx.NET
// some modified.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
#if (NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0)
using System;
using System.Threading;
namespace UniRx
{
/// <summary>
/// Represents a disposable resource that has an associated <seealso cref="T:System.Threading.CancellationToken"/> that will be set to the cancellation requested state upon disposal.
/// </summary>
public sealed class CancellationDisposable : ICancelable
{
private readonly CancellationTokenSource _cts;
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CancellationDisposable"/> class that uses an existing <seealso cref="T:System.Threading.CancellationTokenSource"/>.
/// </summary>
/// <param name="cts"><seealso cref="T:System.Threading.CancellationTokenSource"/> used for cancellation.</param>
/// <exception cref="ArgumentNullException"><paramref name="cts"/> is null.</exception>
public CancellationDisposable(CancellationTokenSource cts)
{
if (cts == null)
throw new ArgumentNullException("cts");
_cts = cts;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CancellationDisposable"/> class that uses a new <seealso cref="T:System.Threading.CancellationTokenSource"/>.
/// </summary>
public CancellationDisposable()
: this(new CancellationTokenSource())
{
}
/// <summary>
/// Gets the <see cref="T:System.Threading.CancellationToken"/> used by this CancellationDisposable.
/// </summary>
public CancellationToken Token
{
get { return _cts.Token; }
}
/// <summary>
/// Cancels the underlying <seealso cref="T:System.Threading.CancellationTokenSource"/>.
/// </summary>
public void Dispose()
{
_cts.Cancel();
}
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed
{
get { return _cts.IsCancellationRequested; }
}
}
}
#endif

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6c675907554bfa24d8bd411f386e410d
timeCreated: 1475137543
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
// using System.Linq; do not use LINQ
using System.Text;
namespace UniRx
{
// copy, modified from Rx Official
public sealed class CompositeDisposable : ICollection<IDisposable>, IDisposable, ICancelable
{
private readonly object _gate = new object();
private bool _disposed;
private List<IDisposable> _disposables;
private int _count;
private const int SHRINK_THRESHOLD = 64;
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class with no disposables contained by it initially.
/// </summary>
public CompositeDisposable()
{
_disposables = new List<IDisposable>();
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class with the specified number of disposables.
/// </summary>
/// <param name="capacity">The number of disposables that the new CompositeDisposable can initially store.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than zero.</exception>
public CompositeDisposable(int capacity)
{
if (capacity < 0)
throw new ArgumentOutOfRangeException("capacity");
_disposables = new List<IDisposable>(capacity);
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class from a group of disposables.
/// </summary>
/// <param name="disposables">Disposables that will be disposed together.</param>
/// <exception cref="ArgumentNullException"><paramref name="disposables"/> is null.</exception>
public CompositeDisposable(params IDisposable[] disposables)
{
if (disposables == null)
throw new ArgumentNullException("disposables");
_disposables = new List<IDisposable>(disposables);
_count = _disposables.Count;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class from a group of disposables.
/// </summary>
/// <param name="disposables">Disposables that will be disposed together.</param>
/// <exception cref="ArgumentNullException"><paramref name="disposables"/> is null.</exception>
public CompositeDisposable(IEnumerable<IDisposable> disposables)
{
if (disposables == null)
throw new ArgumentNullException("disposables");
_disposables = new List<IDisposable>(disposables);
_count = _disposables.Count;
}
/// <summary>
/// Gets the number of disposables contained in the CompositeDisposable.
/// </summary>
public int Count
{
get
{
return _count;
}
}
/// <summary>
/// Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed.
/// </summary>
/// <param name="item">Disposable to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
public void Add(IDisposable item)
{
if (item == null)
throw new ArgumentNullException("item");
var shouldDispose = false;
lock (_gate)
{
shouldDispose = _disposed;
if (!_disposed)
{
_disposables.Add(item);
_count++;
}
}
if (shouldDispose)
item.Dispose();
}
/// <summary>
/// Removes and disposes the first occurrence of a disposable from the CompositeDisposable.
/// </summary>
/// <param name="item">Disposable to remove.</param>
/// <returns>true if found; false otherwise.</returns>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
public bool Remove(IDisposable item)
{
if (item == null)
throw new ArgumentNullException("item");
var shouldDispose = false;
lock (_gate)
{
if (!_disposed)
{
//
// List<T> doesn't shrink the size of the underlying array but does collapse the array
// by copying the tail one position to the left of the removal index. We don't need
// index-based lookup but only ordering for sequential disposal. So, instead of spending
// cycles on the Array.Copy imposed by Remove, we use a null sentinel value. We also
// do manual Swiss cheese detection to shrink the list if there's a lot of holes in it.
//
var i = _disposables.IndexOf(item);
if (i >= 0)
{
shouldDispose = true;
_disposables[i] = null;
_count--;
if (_disposables.Capacity > SHRINK_THRESHOLD && _count < _disposables.Capacity / 2)
{
var old = _disposables;
_disposables = new List<IDisposable>(_disposables.Capacity / 2);
foreach (var d in old)
if (d != null)
_disposables.Add(d);
}
}
}
}
if (shouldDispose)
item.Dispose();
return shouldDispose;
}
/// <summary>
/// Disposes all disposables in the group and removes them from the group.
/// </summary>
public void Dispose()
{
var currentDisposables = default(IDisposable[]);
lock (_gate)
{
if (!_disposed)
{
_disposed = true;
currentDisposables = _disposables.ToArray();
_disposables.Clear();
_count = 0;
}
}
if (currentDisposables != null)
{
foreach (var d in currentDisposables)
if (d != null)
d.Dispose();
}
}
/// <summary>
/// Removes and disposes all disposables from the CompositeDisposable, but does not dispose the CompositeDisposable.
/// </summary>
public void Clear()
{
var currentDisposables = default(IDisposable[]);
lock (_gate)
{
currentDisposables = _disposables.ToArray();
_disposables.Clear();
_count = 0;
}
foreach (var d in currentDisposables)
if (d != null)
d.Dispose();
}
/// <summary>
/// Determines whether the CompositeDisposable contains a specific disposable.
/// </summary>
/// <param name="item">Disposable to search for.</param>
/// <returns>true if the disposable was found; otherwise, false.</returns>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
public bool Contains(IDisposable item)
{
if (item == null)
throw new ArgumentNullException("item");
lock (_gate)
{
return _disposables.Contains(item);
}
}
/// <summary>
/// Copies the disposables contained in the CompositeDisposable to an array, starting at a particular array index.
/// </summary>
/// <param name="array">Array to copy the contained disposables to.</param>
/// <param name="arrayIndex">Target index at which to copy the first disposable of the group.</param>
/// <exception cref="ArgumentNullException"><paramref name="array"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than zero. -or - <paramref name="arrayIndex"/> is larger than or equal to the array length.</exception>
public void CopyTo(IDisposable[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0 || arrayIndex >= array.Length)
throw new ArgumentOutOfRangeException("arrayIndex");
lock (_gate)
{
var disArray = new List<IDisposable>();
foreach (var item in _disposables)
{
if (item != null) disArray.Add(item);
}
Array.Copy(disArray.ToArray(), 0, array, arrayIndex, array.Length - arrayIndex);
}
}
/// <summary>
/// Always returns false.
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// Returns an enumerator that iterates through the CompositeDisposable.
/// </summary>
/// <returns>An enumerator to iterate over the disposables.</returns>
public IEnumerator<IDisposable> GetEnumerator()
{
var res = new List<IDisposable>();
lock (_gate)
{
foreach (var d in _disposables)
{
if (d != null) res.Add(d);
}
}
return res.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through the CompositeDisposable.
/// </summary>
/// <returns>An enumerator to iterate over the disposables.</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed
{
get { return _disposed; }
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a0f9d923bd5f4cd47b39bdd83125de27
timeCreated: 1455373900
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,255 @@
using System;
using System.Collections.Generic;
namespace UniRx
{
public sealed class DictionaryDisposable<TKey, TValue> : IDisposable, IDictionary<TKey, TValue>
where TValue : IDisposable
{
bool isDisposed = false;
readonly Dictionary<TKey, TValue> inner;
public DictionaryDisposable()
{
inner = new Dictionary<TKey, TValue>();
}
public DictionaryDisposable(IEqualityComparer<TKey> comparer)
{
inner = new Dictionary<TKey, TValue>(comparer);
}
public TValue this[TKey key]
{
get
{
lock (inner)
{
return inner[key];
}
}
set
{
lock (inner)
{
if (isDisposed) value.Dispose();
TValue oldValue;
if (TryGetValue(key, out oldValue))
{
oldValue.Dispose();
inner[key] = value;
}
else
{
inner[key] = value;
}
}
}
}
public int Count
{
get
{
lock (inner)
{
return inner.Count;
}
}
}
public Dictionary<TKey, TValue>.KeyCollection Keys
{
get
{
throw new NotSupportedException("please use .Select(x => x.Key).ToArray()");
}
}
public Dictionary<TKey, TValue>.ValueCollection Values
{
get
{
throw new NotSupportedException("please use .Select(x => x.Value).ToArray()");
}
}
public void Add(TKey key, TValue value)
{
lock (inner)
{
if (isDisposed)
{
value.Dispose();
return;
}
inner.Add(key, value);
}
}
public void Clear()
{
lock (inner)
{
foreach (var item in inner)
{
item.Value.Dispose();
}
inner.Clear();
}
}
public bool Remove(TKey key)
{
lock (inner)
{
TValue oldValue;
if (inner.TryGetValue(key, out oldValue))
{
var isSuccessRemove = inner.Remove(key);
if (isSuccessRemove)
{
oldValue.Dispose();
}
return isSuccessRemove;
}
else
{
return false;
}
}
}
public bool ContainsKey(TKey key)
{
lock (inner)
{
return inner.ContainsKey(key);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
lock (inner)
{
return inner.TryGetValue(key, out value);
}
}
public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
{
lock (inner)
{
return new Dictionary<TKey, TValue>(inner).GetEnumerator();
}
}
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
{
get
{
return ((ICollection<KeyValuePair<TKey, TValue>>)inner).IsReadOnly;
}
}
ICollection<TKey> IDictionary<TKey, TValue>.Keys
{
get
{
lock (inner)
{
return new List<TKey>(inner.Keys);
}
}
}
ICollection<TValue> IDictionary<TKey, TValue>.Values
{
get
{
lock (inner)
{
return new List<TValue>(inner.Values);
}
}
}
#if !UNITY_METRO
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
lock (inner)
{
((System.Runtime.Serialization.ISerializable)inner).GetObjectData(info, context);
}
}
public void OnDeserialization(object sender)
{
lock (inner)
{
((System.Runtime.Serialization.IDeserializationCallback)inner).OnDeserialization(sender);
}
}
#endif
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
Add((TKey)item.Key, (TValue)item.Value);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
lock (inner)
{
return ((ICollection<KeyValuePair<TKey, TValue>>)inner).Contains(item);
}
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
lock (inner)
{
((ICollection<KeyValuePair<TKey, TValue>>)inner).CopyTo(array, arrayIndex);
}
}
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
lock (inner)
{
return new List<KeyValuePair<TKey, TValue>>((ICollection<KeyValuePair<TKey, TValue>>)inner).GetEnumerator();
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
throw new NotSupportedException();
}
public void Dispose()
{
lock (inner)
{
if (isDisposed) return;
isDisposed = true;
foreach (var item in inner)
{
item.Value.Dispose();
}
inner.Clear();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 702939929fc84d544b12076b76aa73b5
timeCreated: 1455373899
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections;
namespace UniRx
{
public static class Disposable
{
public static readonly IDisposable Empty = EmptyDisposable.Singleton;
public static IDisposable Create(Action disposeAction)
{
return new AnonymousDisposable(disposeAction);
}
public static IDisposable CreateWithState<TState>(TState state, Action<TState> disposeAction)
{
return new AnonymousDisposable<TState>(state, disposeAction);
}
class EmptyDisposable : IDisposable
{
public static EmptyDisposable Singleton = new EmptyDisposable();
private EmptyDisposable()
{
}
public void Dispose()
{
}
}
class AnonymousDisposable : IDisposable
{
bool isDisposed = false;
readonly Action dispose;
public AnonymousDisposable(Action dispose)
{
this.dispose = dispose;
}
public void Dispose()
{
if (!isDisposed)
{
isDisposed = true;
dispose();
}
}
}
class AnonymousDisposable<T> : IDisposable
{
bool isDisposed = false;
readonly T state;
readonly Action<T> dispose;
public AnonymousDisposable(T state, Action<T> dispose)
{
this.state = state;
this.dispose = dispose;
}
public void Dispose()
{
if (!isDisposed)
{
isDisposed = true;
dispose(state);
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 958f291bb8f434740a6d2c08ad5182a0
timeCreated: 1455373900
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
namespace UniRx
{
public static partial class DisposableExtensions
{
/// <summary>Add disposable(self) to CompositeDisposable(or other ICollection). Return value is self disposable.</summary>
public static T AddTo<T>(this T disposable, ICollection<IDisposable> container)
where T : IDisposable
{
if (disposable == null) throw new ArgumentNullException("disposable");
if (container == null) throw new ArgumentNullException("container");
container.Add(disposable);
return disposable;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9c4757265ae105441bae71007cbd0184
timeCreated: 1455373900
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace UniRx
{
public interface ICancelable : IDisposable
{
bool IsDisposed { get; }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b5cd5b0b304c78345a49757b1f6f8ba8
timeCreated: 1455373900
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections;
namespace UniRx
{
public sealed class MultipleAssignmentDisposable : IDisposable, ICancelable
{
static readonly BooleanDisposable True = new BooleanDisposable(true);
object gate = new object();
IDisposable current;
public bool IsDisposed
{
get
{
lock (gate)
{
return current == True;
}
}
}
public IDisposable Disposable
{
get
{
lock (gate)
{
return (current == True)
? UniRx.Disposable.Empty
: current;
}
}
set
{
var shouldDispose = false;
lock (gate)
{
shouldDispose = (current == True);
if (!shouldDispose)
{
current = value;
}
}
if (shouldDispose && value != null)
{
value.Dispose();
}
}
}
public void Dispose()
{
IDisposable old = null;
lock (gate)
{
if (current != True)
{
old = current;
current = True;
}
}
if (old != null) old.Dispose();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bb959083576ace749afd55c1e54b02d9
timeCreated: 1455373901
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,152 @@
// This code is borrwed from Rx Official and some modified.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace UniRx
{
/// <summary>
/// Represents a disposable resource that only disposes its underlying disposable resource when all <see cref="GetDisposable">dependent disposable objects</see> have been disposed.
/// </summary>
public sealed class RefCountDisposable : ICancelable
{
private readonly object _gate = new object();
private IDisposable _disposable;
private bool _isPrimaryDisposed;
private int _count;
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.RefCountDisposable"/> class with the specified disposable.
/// </summary>
/// <param name="disposable">Underlying disposable.</param>
/// <exception cref="ArgumentNullException"><paramref name="disposable"/> is null.</exception>
public RefCountDisposable(IDisposable disposable)
{
if (disposable == null)
throw new ArgumentNullException("disposable");
_disposable = disposable;
_isPrimaryDisposed = false;
_count = 0;
}
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed
{
get { return _disposable == null; }
}
/// <summary>
/// Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.
/// </summary>
/// <returns>A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Backward compat + non-trivial work for a property getter.")]
public IDisposable GetDisposable()
{
lock (_gate)
{
if (_disposable == null)
{
return Disposable.Empty;
}
else
{
_count++;
return new InnerDisposable(this);
}
}
}
/// <summary>
/// Disposes the underlying disposable only when all dependent disposables have been disposed.
/// </summary>
public void Dispose()
{
var disposable = default(IDisposable);
lock (_gate)
{
if (_disposable != null)
{
if (!_isPrimaryDisposed)
{
_isPrimaryDisposed = true;
if (_count == 0)
{
disposable = _disposable;
_disposable = null;
}
}
}
}
if (disposable != null)
disposable.Dispose();
}
private void Release()
{
var disposable = default(IDisposable);
lock (_gate)
{
if (_disposable != null)
{
_count--;
if (_isPrimaryDisposed)
{
if (_count == 0)
{
disposable = _disposable;
_disposable = null;
}
}
}
}
if (disposable != null)
disposable.Dispose();
}
sealed class InnerDisposable : IDisposable
{
private RefCountDisposable _parent;
object parentLock = new object();
public InnerDisposable(RefCountDisposable parent)
{
_parent = parent;
}
public void Dispose()
{
RefCountDisposable parent;
lock (parentLock)
{
parent = _parent;
_parent = null;
}
if (parent != null)
parent.Release();
}
}
}
public partial class Observable
{
static IObservable<T> AddRef<T>(IObservable<T> xs, RefCountDisposable r)
{
return Observable.Create<T>((IObserver<T> observer) => new CompositeDisposable(new IDisposable[]
{
r.GetDisposable(),
xs.Subscribe(observer)
}));
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2fb5a2cdb138579498eb20d8b7818ad8
timeCreated: 1455373898
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using System;
using System.Threading;
namespace UniRx
{
public sealed class ScheduledDisposable : ICancelable
{
private readonly IScheduler scheduler;
private volatile IDisposable disposable;
private int isDisposed = 0;
public ScheduledDisposable(IScheduler scheduler, IDisposable disposable)
{
this.scheduler = scheduler;
this.disposable = disposable;
}
public IScheduler Scheduler
{
get { return scheduler; }
}
public IDisposable Disposable
{
get { return disposable; }
}
public bool IsDisposed
{
get { return isDisposed != 0; }
}
public void Dispose()
{
Scheduler.Schedule(DisposeInner);
}
private void DisposeInner()
{
if (Interlocked.Increment(ref isDisposed) == 1)
{
disposable.Dispose();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: db98ce742e859bd4e81db434c3ca3663
timeCreated: 1455373901
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections;
namespace UniRx
{
public sealed class SerialDisposable : IDisposable, ICancelable
{
readonly object gate = new object();
IDisposable current;
bool disposed;
public bool IsDisposed { get { lock (gate) { return disposed; } } }
public IDisposable Disposable
{
get
{
return current;
}
set
{
var shouldDispose = false;
var old = default(IDisposable);
lock (gate)
{
shouldDispose = disposed;
if (!shouldDispose)
{
old = current;
current = value;
}
}
if (old != null)
{
old.Dispose();
}
if (shouldDispose && value != null)
{
value.Dispose();
}
}
}
public void Dispose()
{
var old = default(IDisposable);
lock (gate)
{
if (!disposed)
{
disposed = true;
old = current;
current = null;
}
}
if (old != null)
{
old.Dispose();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 06fb064ad9e4d354ab15ff89f6343243
timeCreated: 1455373897
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections;
namespace UniRx
{
// should be use Interlocked.CompareExchange for Threadsafe?
// but CompareExchange cause ExecutionEngineException on iOS.
// AOT...
// use lock instead
public sealed class SingleAssignmentDisposable : IDisposable, ICancelable
{
readonly object gate = new object();
IDisposable current;
bool disposed;
public bool IsDisposed { get { lock (gate) { return disposed; } } }
public IDisposable Disposable
{
get
{
return current;
}
set
{
var old = default(IDisposable);
bool alreadyDisposed;
lock (gate)
{
alreadyDisposed = disposed;
old = current;
if (!alreadyDisposed)
{
if (value == null) return;
current = value;
}
}
if (alreadyDisposed && value != null)
{
value.Dispose();
return;
}
if (old != null) throw new InvalidOperationException("Disposable is already set");
}
}
public void Dispose()
{
IDisposable old = null;
lock (gate)
{
if (!disposed)
{
disposed = true;
old = current;
current = null;
}
}
if (old != null) old.Dispose();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7ec869f7548c62748ad57a5c86b2f6ba
timeCreated: 1455373899
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,277 @@
using System;
using System.Collections.Generic;
using System.Threading;
namespace UniRx
{
/// <summary>
/// Represents a group of disposable resources that are disposed together.
/// </summary>
public abstract class StableCompositeDisposable : ICancelable
{
/// <summary>
/// Creates a new group containing two disposable resources that are disposed together.
/// </summary>
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
return new Binary(disposable1, disposable2);
}
/// <summary>
/// Creates a new group containing three disposable resources that are disposed together.
/// </summary>
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
/// <param name="disposable3">The third disposable resoruce to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
if (disposable3 == null) throw new ArgumentNullException("disposable3");
return new Trinary(disposable1, disposable2, disposable3);
}
/// <summary>
/// Creates a new group containing four disposable resources that are disposed together.
/// </summary>
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
/// <param name="disposable3">The three disposable resoruce to add to the group.</param>
/// <param name="disposable4">The four disposable resoruce to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
if (disposable3 == null) throw new ArgumentNullException("disposable3");
if (disposable4 == null) throw new ArgumentNullException("disposable4");
return new Quaternary(disposable1, disposable2, disposable3, disposable4);
}
/// <summary>
/// Creates a new group of disposable resources that are disposed together.
/// </summary>
/// <param name="disposables">Disposable resources to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable Create(params IDisposable[] disposables)
{
if (disposables == null) throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
/// <summary>
/// Creates a new group of disposable resources that are disposed together. Array is not copied, it's unsafe but optimized.
/// </summary>
/// <param name="disposables">Disposable resources to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable CreateUnsafe(IDisposable[] disposables)
{
return new NAryUnsafe(disposables);
}
/// <summary>
/// Creates a new group of disposable resources that are disposed together.
/// </summary>
/// <param name="disposables">Disposable resources to add to the group.</param>
/// <returns>Group of disposable resources that are disposed together.</returns>
public static ICancelable Create(IEnumerable<IDisposable> disposables)
{
if (disposables == null) throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
/// <summary>
/// Disposes all disposables in the group.
/// </summary>
public abstract void Dispose();
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public abstract bool IsDisposed
{
get;
}
class Binary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
public Binary(IDisposable disposable1, IDisposable disposable2)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
}
}
}
class Trinary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
private volatile IDisposable _disposable3;
public Trinary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
_disposable3 = disposable3;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
_disposable3.Dispose();
}
}
}
class Quaternary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
private volatile IDisposable _disposable3;
private volatile IDisposable _disposable4;
public Quaternary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
_disposable3 = disposable3;
_disposable4 = disposable4;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
_disposable3.Dispose();
_disposable4.Dispose();
}
}
}
class NAry : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile List<IDisposable> _disposables;
public NAry(IDisposable[] disposables)
: this((IEnumerable<IDisposable>)disposables)
{
}
public NAry(IEnumerable<IDisposable> disposables)
{
_disposables = new List<IDisposable>(disposables);
//
// Doing this on the list to avoid duplicate enumeration of disposables.
//
if (_disposables.Contains(null)) throw new ArgumentException("Disposables can't contains null", "disposables");
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
foreach (var d in _disposables)
{
d.Dispose();
}
}
}
}
class NAryUnsafe : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable[] _disposables;
public NAryUnsafe(IDisposable[] disposables)
{
_disposables = disposables;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
var len = _disposables.Length;
for (int i = 0; i < len; i++)
{
_disposables[i].Dispose();
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3a9cd9fa22bc6a5439484581f5049cf8
timeCreated: 1455373898
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: