diff --git a/popcorn/Assets/Plugins.meta b/popcorn/Assets/Plugins.meta new file mode 100644 index 00000000..f7e8d9af --- /dev/null +++ b/popcorn/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21bd5b215a9024c7fbc4194157a98646 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx.meta b/popcorn/Assets/Plugins/UniRx.meta new file mode 100644 index 00000000..3ec5efc3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c17c7c4f119c849bba18e745029554ff +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/ReadMe.txt b/popcorn/Assets/Plugins/UniRx/ReadMe.txt new file mode 100644 index 00000000..f32cbda3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/ReadMe.txt @@ -0,0 +1,29 @@ +UniRx - Reactive Extensions for Unity / Ver 6.2.2 +=== +Created by Yoshifumi Kawai(neuecc) + +UniRx (Reactive Extensions for Unity) is a reimplementation of the .NET Reactive Extensions. +UniRx is Core Library (Port of Rx) + Platform Adaptor (MainThreadScheduler/FromCoroutine/etc) + Framework (ObservableTriggers/ReactiveProeperty/etc) + async/await integration(UniRx.Async) + +Please read Official Site's ReadMe(Manual) - https://github.com/neuecc/UniRx/ + +UniRx is available on the Unity Asset Store (FREE) - http://u3d.as/content/neuecc/uni-rx-reactive-extensions-for-unity/7tT +Blog for update info - https://medium.com/@neuecc + +Support thread on the Unity Forums: Ask me any question - http://forum.unity3d.com/threads/248535-UniRx-Reactive-Extensions-for-Unity +Release Notes, see [UniRx/releases](https://github.com/neuecc/UniRx/releases) + +Author Info +--- +Yoshifumi Kawai(a.k.a. neuecc) is a software developer in Japan. +He is awarding Microsoft MVP for Visual C# since 2011. + +Blog: https://medium.com/@neuecc (English) +Blog: http://neue.cc/ (Japanese) +Twitter: https://twitter.com/neuecc (Japanese) + +License +--- +This library is under the [MIT License](https://github.com/neuecc/UniRx/blob/master/LICENSE). + +Some code is borrowed from [Rx.NET](https://rx.codeplex.com/) and [mono/mcs](https://github.com/mono/mono). diff --git a/popcorn/Assets/Plugins/UniRx/ReadMe.txt.meta b/popcorn/Assets/Plugins/UniRx/ReadMe.txt.meta new file mode 100644 index 00000000..60cd9d4a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/ReadMe.txt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52d665ea30c2a3a49a6fa4b3b5a0349a +timeCreated: 1455373909 +licenseType: Store +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts.meta b/popcorn/Assets/Plugins/UniRx/Scripts.meta new file mode 100644 index 00000000..03bcf149 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: eaf9ac9937118834c86197511fd5317f +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous.meta new file mode 100644 index 00000000..5fdf854a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c490b3110ff2a524ea963382652a378f +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs new file mode 100644 index 00000000..e5bba8c1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; + +namespace UniRx +{ + public static class WebRequestExtensions + { + static IObservable AbortableDeferredAsyncRequest(Func begin, Func end, WebRequest request) + { + var result = Observable.Create(observer => + { + var isCompleted = -1; + var subscription = Observable.FromAsyncPattern(begin, + ar => + { + try + { + Interlocked.Increment(ref isCompleted); + return end(ar); + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.RequestCanceled) return default(TResult); + throw; + } + })() + .Subscribe(observer); + return Disposable.Create(() => + { + if (Interlocked.Increment(ref isCompleted) == 0) + { + subscription.Dispose(); + request.Abort(); + } + }); + }); + + return result; + } + + public static IObservable GetResponseAsObservable(this WebRequest request) + { + return AbortableDeferredAsyncRequest(request.BeginGetResponse, request.EndGetResponse, request); + } + + public static IObservable GetResponseAsObservable(this HttpWebRequest request) + { + return AbortableDeferredAsyncRequest(request.BeginGetResponse, ar => (HttpWebResponse)request.EndGetResponse(ar), request); + } + + public static IObservable GetRequestStreamAsObservable(this WebRequest request) + { + return AbortableDeferredAsyncRequest(request.BeginGetRequestStream, request.EndGetRequestStream, request); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs.meta new file mode 100644 index 00000000..c46e0e37 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Asynchronous/WebRequestExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 457f0007b2c70e34e9929ec8f0e2c4e6 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables.meta new file mode 100644 index 00000000..dc32975a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d061218ef48281148bb1a996d971bdbe +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs new file mode 100644 index 00000000..db54b8e3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs.meta new file mode 100644 index 00000000..952d4d8c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/BooleanDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4ff95c6eb380ca248984d8c27c1244d0 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs new file mode 100644 index 00000000..435215fc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs @@ -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 +{ + /// + /// Represents a disposable resource that has an associated that will be set to the cancellation requested state upon disposal. + /// + public sealed class CancellationDisposable : ICancelable + { + private readonly CancellationTokenSource _cts; + + /// + /// Initializes a new instance of the class that uses an existing . + /// + /// used for cancellation. + /// is null. + public CancellationDisposable(CancellationTokenSource cts) + { + if (cts == null) + throw new ArgumentNullException("cts"); + + _cts = cts; + } + + /// + /// Initializes a new instance of the class that uses a new . + /// + public CancellationDisposable() + : this(new CancellationTokenSource()) + { + } + + /// + /// Gets the used by this CancellationDisposable. + /// + public CancellationToken Token + { + get { return _cts.Token; } + } + + /// + /// Cancels the underlying . + /// + public void Dispose() + { + _cts.Cancel(); + } + + /// + /// Gets a value that indicates whether the object is disposed. + /// + public bool IsDisposed + { + get { return _cts.IsCancellationRequested; } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs.meta new file mode 100644 index 00000000..3de8b891 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CancellationDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6c675907554bfa24d8bd411f386e410d +timeCreated: 1475137543 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs new file mode 100644 index 00000000..a1735d5c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs @@ -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, ICancelable + { + private readonly object _gate = new object(); + + private bool _disposed; + private List _disposables; + private int _count; + private const int SHRINK_THRESHOLD = 64; + + /// + /// Initializes a new instance of the class with no disposables contained by it initially. + /// + public CompositeDisposable() + { + _disposables = new List(); + } + + /// + /// Initializes a new instance of the class with the specified number of disposables. + /// + /// The number of disposables that the new CompositeDisposable can initially store. + /// is less than zero. + public CompositeDisposable(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity"); + + _disposables = new List(capacity); + } + + /// + /// Initializes a new instance of the class from a group of disposables. + /// + /// Disposables that will be disposed together. + /// is null. + public CompositeDisposable(params IDisposable[] disposables) + { + if (disposables == null) + throw new ArgumentNullException("disposables"); + + _disposables = new List(disposables); + _count = _disposables.Count; + } + + /// + /// Initializes a new instance of the class from a group of disposables. + /// + /// Disposables that will be disposed together. + /// is null. + public CompositeDisposable(IEnumerable disposables) + { + if (disposables == null) + throw new ArgumentNullException("disposables"); + + _disposables = new List(disposables); + _count = _disposables.Count; + } + + /// + /// Gets the number of disposables contained in the CompositeDisposable. + /// + public int Count + { + get + { + return _count; + } + } + + /// + /// Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed. + /// + /// Disposable to add. + /// is null. + 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(); + } + + /// + /// Removes and disposes the first occurrence of a disposable from the CompositeDisposable. + /// + /// Disposable to remove. + /// true if found; false otherwise. + /// is null. + public bool Remove(IDisposable item) + { + if (item == null) + throw new ArgumentNullException("item"); + + var shouldDispose = false; + + lock (_gate) + { + if (!_disposed) + { + // + // List 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(_disposables.Capacity / 2); + + foreach (var d in old) + if (d != null) + _disposables.Add(d); + } + } + } + } + + if (shouldDispose) + item.Dispose(); + + return shouldDispose; + } + + /// + /// Disposes all disposables in the group and removes them from the group. + /// + 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(); + } + } + + /// + /// Removes and disposes all disposables from the CompositeDisposable, but does not dispose the CompositeDisposable. + /// + 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(); + } + + /// + /// Determines whether the CompositeDisposable contains a specific disposable. + /// + /// Disposable to search for. + /// true if the disposable was found; otherwise, false. + /// is null. + public bool Contains(IDisposable item) + { + if (item == null) + throw new ArgumentNullException("item"); + + lock (_gate) + { + return _disposables.Contains(item); + } + } + + /// + /// Copies the disposables contained in the CompositeDisposable to an array, starting at a particular array index. + /// + /// Array to copy the contained disposables to. + /// Target index at which to copy the first disposable of the group. + /// is null. + /// is less than zero. -or - is larger than or equal to the array length. + 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(); + foreach (var item in _disposables) + { + if (item != null) disArray.Add(item); + } + + Array.Copy(disArray.ToArray(), 0, array, arrayIndex, array.Length - arrayIndex); + } + } + + /// + /// Always returns false. + /// + public bool IsReadOnly + { + get { return false; } + } + + /// + /// Returns an enumerator that iterates through the CompositeDisposable. + /// + /// An enumerator to iterate over the disposables. + public IEnumerator GetEnumerator() + { + var res = new List(); + + lock (_gate) + { + foreach (var d in _disposables) + { + if (d != null) res.Add(d); + } + } + + return res.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the CompositeDisposable. + /// + /// An enumerator to iterate over the disposables. + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Gets a value that indicates whether the object is disposed. + /// + public bool IsDisposed + { + get { return _disposed; } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs.meta new file mode 100644 index 00000000..3003d45e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/CompositeDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a0f9d923bd5f4cd47b39bdd83125de27 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs new file mode 100644 index 00000000..fe42783e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; + +namespace UniRx +{ + public sealed class DictionaryDisposable : IDisposable, IDictionary + where TValue : IDisposable + { + bool isDisposed = false; + readonly Dictionary inner; + + public DictionaryDisposable() + { + inner = new Dictionary(); + } + + public DictionaryDisposable(IEqualityComparer comparer) + { + inner = new Dictionary(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.KeyCollection Keys + { + get + { + throw new NotSupportedException("please use .Select(x => x.Key).ToArray()"); + } + } + + public Dictionary.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.Enumerator GetEnumerator() + { + lock (inner) + { + return new Dictionary(inner).GetEnumerator(); + } + } + + bool ICollection>.IsReadOnly + { + get + { + return ((ICollection>)inner).IsReadOnly; + } + } + + ICollection IDictionary.Keys + { + get + { + lock (inner) + { + return new List(inner.Keys); + } + } + } + + ICollection IDictionary.Values + { + get + { + lock (inner) + { + return new List(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>.Add(KeyValuePair item) + { + Add((TKey)item.Key, (TValue)item.Value); + } + + bool ICollection>.Contains(KeyValuePair item) + { + lock (inner) + { + return ((ICollection>)inner).Contains(item); + } + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + lock (inner) + { + ((ICollection>)inner).CopyTo(array, arrayIndex); + } + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + lock (inner) + { + return new List>((ICollection>)inner).GetEnumerator(); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + bool ICollection>.Remove(KeyValuePair item) + { + throw new NotSupportedException(); + } + + public void Dispose() + { + lock (inner) + { + if (isDisposed) return; + isDisposed = true; + + foreach (var item in inner) + { + item.Value.Dispose(); + } + inner.Clear(); + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs.meta new file mode 100644 index 00000000..a3fc33c5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DictionaryDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 702939929fc84d544b12076b76aa73b5 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs new file mode 100644 index 00000000..9ffd1033 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs @@ -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 state, Action disposeAction) + { + return new AnonymousDisposable(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 : IDisposable + { + bool isDisposed = false; + readonly T state; + readonly Action dispose; + + public AnonymousDisposable(T state, Action dispose) + { + this.state = state; + this.dispose = dispose; + } + + public void Dispose() + { + if (!isDisposed) + { + isDisposed = true; + dispose(state); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs.meta new file mode 100644 index 00000000..07cf9427 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/Disposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 958f291bb8f434740a6d2c08ad5182a0 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs new file mode 100644 index 00000000..f32f7c27 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace UniRx +{ + public static partial class DisposableExtensions + { + /// Add disposable(self) to CompositeDisposable(or other ICollection). Return value is self disposable. + public static T AddTo(this T disposable, ICollection container) + where T : IDisposable + { + if (disposable == null) throw new ArgumentNullException("disposable"); + if (container == null) throw new ArgumentNullException("container"); + + container.Add(disposable); + + return disposable; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs.meta new file mode 100644 index 00000000..f16486dd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/DisposableExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9c4757265ae105441bae71007cbd0184 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs new file mode 100644 index 00000000..6d489ae7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx +{ + public interface ICancelable : IDisposable + { + bool IsDisposed { get; } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs.meta new file mode 100644 index 00000000..f28aaa6b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ICancelable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b5cd5b0b304c78345a49757b1f6f8ba8 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs new file mode 100644 index 00000000..78e78d64 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs.meta new file mode 100644 index 00000000..9771f006 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/MultipleAssignmentDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bb959083576ace749afd55c1e54b02d9 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs new file mode 100644 index 00000000..05374a1f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs @@ -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 +{ + /// + /// Represents a disposable resource that only disposes its underlying disposable resource when all dependent disposable objects have been disposed. + /// + public sealed class RefCountDisposable : ICancelable + { + private readonly object _gate = new object(); + private IDisposable _disposable; + private bool _isPrimaryDisposed; + private int _count; + + /// + /// Initializes a new instance of the class with the specified disposable. + /// + /// Underlying disposable. + /// is null. + public RefCountDisposable(IDisposable disposable) + { + if (disposable == null) + throw new ArgumentNullException("disposable"); + + _disposable = disposable; + _isPrimaryDisposed = false; + _count = 0; + } + + /// + /// Gets a value that indicates whether the object is disposed. + /// + public bool IsDisposed + { + get { return _disposable == null; } + } + + /// + /// Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable. + /// + /// A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime. + [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); + } + } + } + + /// + /// Disposes the underlying disposable only when all dependent disposables have been disposed. + /// + 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 AddRef(IObservable xs, RefCountDisposable r) + { + return Observable.Create((IObserver observer) => new CompositeDisposable(new IDisposable[] + { + r.GetDisposable(), + xs.Subscribe(observer) + })); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs.meta new file mode 100644 index 00000000..2fdc97a0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/RefCountDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2fb5a2cdb138579498eb20d8b7818ad8 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs new file mode 100644 index 00000000..22aa1948 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs @@ -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(); + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs.meta new file mode 100644 index 00000000..7a0ff248 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/ScheduledDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: db98ce742e859bd4e81db434c3ca3663 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs new file mode 100644 index 00000000..f00eca80 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs @@ -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(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs.meta new file mode 100644 index 00000000..4038bd0c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SerialDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 06fb064ad9e4d354ab15ff89f6343243 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs new file mode 100644 index 00000000..6f3f10ea --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs.meta new file mode 100644 index 00000000..a92ded8d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/SingleAssignmentDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7ec869f7548c62748ad57a5c86b2f6ba +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs new file mode 100644 index 00000000..49baed03 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace UniRx +{ + /// + /// Represents a group of disposable resources that are disposed together. + /// + public abstract class StableCompositeDisposable : ICancelable + { + /// + /// Creates a new group containing two disposable resources that are disposed together. + /// + /// The first disposable resoruce to add to the group. + /// The second disposable resoruce to add to the group. + /// Group of disposable resources that are disposed together. + 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); + } + + /// + /// Creates a new group containing three disposable resources that are disposed together. + /// + /// The first disposable resoruce to add to the group. + /// The second disposable resoruce to add to the group. + /// The third disposable resoruce to add to the group. + /// Group of disposable resources that are disposed together. + 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); + } + + /// + /// Creates a new group containing four disposable resources that are disposed together. + /// + /// The first disposable resoruce to add to the group. + /// The second disposable resoruce to add to the group. + /// The three disposable resoruce to add to the group. + /// The four disposable resoruce to add to the group. + /// Group of disposable resources that are disposed together. + 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); + } + + /// + /// Creates a new group of disposable resources that are disposed together. + /// + /// Disposable resources to add to the group. + /// Group of disposable resources that are disposed together. + public static ICancelable Create(params IDisposable[] disposables) + { + if (disposables == null) throw new ArgumentNullException("disposables"); + + return new NAry(disposables); + } + + /// + /// Creates a new group of disposable resources that are disposed together. Array is not copied, it's unsafe but optimized. + /// + /// Disposable resources to add to the group. + /// Group of disposable resources that are disposed together. + public static ICancelable CreateUnsafe(IDisposable[] disposables) + { + return new NAryUnsafe(disposables); + } + + /// + /// Creates a new group of disposable resources that are disposed together. + /// + /// Disposable resources to add to the group. + /// Group of disposable resources that are disposed together. + public static ICancelable Create(IEnumerable disposables) + { + if (disposables == null) throw new ArgumentNullException("disposables"); + + return new NAry(disposables); + } + + /// + /// Disposes all disposables in the group. + /// + public abstract void Dispose(); + + /// + /// Gets a value that indicates whether the object is disposed. + /// + 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 _disposables; + + public NAry(IDisposable[] disposables) + : this((IEnumerable)disposables) + { + } + + public NAry(IEnumerable disposables) + { + _disposables = new List(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(); + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs.meta new file mode 100644 index 00000000..b35e6fb5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Disposables/StableCompositeDisposable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3a9cd9fa22bc6a5439484581f5049cf8 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs b/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs new file mode 100644 index 00000000..48a9a85d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs @@ -0,0 +1,140 @@ +// original code from rx.codeplex.com +// 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; + +namespace UniRx +{ + /// + /// Represents a .NET event invocation consisting of the strongly typed object that raised the event and the data that was generated by the event. + /// + /// + /// The type of the sender that raised the event. + /// This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics. + /// + /// + /// The type of the event data generated by the event. + /// This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics. + /// + public interface IEventPattern + { + /// + /// Gets the sender object that raised the event. + /// + TSender Sender { get; } + + /// + /// Gets the event data that was generated by the event. + /// + TEventArgs EventArgs { get; } + } + + /// + /// Represents a .NET event invocation consisting of the weakly typed object that raised the event and the data that was generated by the event. + /// + /// The type of the event data generated by the event. + public class EventPattern : EventPattern + { + /// + /// Creates a new data representation instance of a .NET event invocation with the given sender and event data. + /// + /// The sender object that raised the event. + /// The event data that was generated by the event. + public EventPattern(object sender, TEventArgs e) + : base(sender, e) + { + } + } + + /// + /// Represents a .NET event invocation consisting of the strongly typed object that raised the event and the data that was generated by the event. + /// + /// The type of the sender that raised the event. + /// The type of the event data generated by the event. + public class EventPattern : IEquatable>, IEventPattern + { + /// + /// Creates a new data representation instance of a .NET event invocation with the given sender and event data. + /// + /// The sender object that raised the event. + /// The event data that was generated by the event. + public EventPattern(TSender sender, TEventArgs e) + { + Sender = sender; + EventArgs = e; + } + + /// + /// Gets the sender object that raised the event. + /// + public TSender Sender { get; private set; } + + /// + /// Gets the event data that was generated by the event. + /// + public TEventArgs EventArgs { get; private set; } + + /// + /// Determines whether the current EventPattern<TSender, TEventArgs> object represents the same event as a specified EventPattern<TSender, TEventArgs> object. + /// + /// An object to compare to the current EventPattern<TSender, TEventArgs> object. + /// true if both EventPattern<TSender, TEventArgs> objects represent the same event; otherwise, false. + public bool Equals(EventPattern other) + { + if (object.ReferenceEquals(null, other)) + return false; + if (object.ReferenceEquals(this, other)) + return true; + + return EqualityComparer.Default.Equals(Sender, other.Sender) && EqualityComparer.Default.Equals(EventArgs, other.EventArgs); + } + + /// + /// Determines whether the specified System.Object is equal to the current EventPattern<TSender, TEventArgs>. + /// + /// The System.Object to compare with the current EventPattern<TSender, TEventArgs>. + /// true if the specified System.Object is equal to the current EventPattern<TSender, TEventArgs>; otherwise, false. + public override bool Equals(object obj) + { + return Equals(obj as EventPattern); + } + + /// + /// Returns the hash code for the current EventPattern<TSender, TEventArgs> instance. + /// + /// A hash code for the current EventPattern<TSender, TEventArgs> instance. + public override int GetHashCode() + { + var x = EqualityComparer.Default.GetHashCode(Sender); + var y = EqualityComparer.Default.GetHashCode(EventArgs); + return (x << 5) + (x ^ y); + } + + /// + /// Determines whether two specified EventPattern<TSender, TEventArgs> objects represent the same event. + /// + /// The first EventPattern<TSender, TEventArgs> to compare, or null. + /// The second EventPattern<TSender, TEventArgs> to compare, or null. + /// true if both EventPattern<TSender, TEventArgs> objects represent the same event; otherwise, false. + public static bool operator ==(EventPattern first, EventPattern second) + { + return object.Equals(first, second); + } + + /// + /// Determines whether two specified EventPattern<TSender, TEventArgs> objects represent a different event. + /// + /// The first EventPattern<TSender, TEventArgs> to compare, or null. + /// The second EventPattern<TSender, TEventArgs> to compare, or null. + /// true if both EventPattern<TSender, TEventArgs> objects don't represent the same event; otherwise, false. + public static bool operator !=(EventPattern first, EventPattern second) + { + return !object.Equals(first, second); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs.meta new file mode 100644 index 00000000..d29299e7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/EventPattern.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e4b797bfea1999a499309068b7d7a97e +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil.meta new file mode 100644 index 00000000..8dfdafb5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7147cf40e45d9b7468957f2d28b1f2f0 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs new file mode 100644 index 00000000..39f0565c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs @@ -0,0 +1,85 @@ +// this code is borrowed from RxOfficial(rx.codeplex.com) and modified + +using System; +using System.Collections.Generic; + +namespace UniRx.InternalUtil +{ + /// + /// Asynchronous lock. + /// + internal sealed class AsyncLock : IDisposable + { + private readonly Queue queue = new Queue(); + private bool isAcquired = false; + private bool hasFaulted = false; + + /// + /// Queues the action for execution. If the caller acquires the lock and becomes the owner, + /// the queue is processed. If the lock is already owned, the action is queued and will get + /// processed by the owner. + /// + /// Action to queue for execution. + /// is null. + public void Wait(Action action) + { + if (action == null) + throw new ArgumentNullException("action"); + + var isOwner = false; + lock (queue) + { + if (!hasFaulted) + { + queue.Enqueue(action); + isOwner = !isAcquired; + isAcquired = true; + } + } + + if (isOwner) + { + while (true) + { + var work = default(Action); + lock (queue) + { + if (queue.Count > 0) + work = queue.Dequeue(); + else + { + isAcquired = false; + break; + } + } + + try + { + work(); + } + catch + { + lock (queue) + { + queue.Clear(); + hasFaulted = true; + } + throw; + } + } + } + } + + /// + /// Clears the work items in the queue and drops further work being queued. + /// + public void Dispose() + { + lock (queue) + { + queue.Clear(); + hasFaulted = true; + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs.meta new file mode 100644 index 00000000..e2555117 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/AscynLock.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 23dbd656cfe9c5e47b02c3c263e476aa +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs new file mode 100644 index 00000000..ae323315 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs @@ -0,0 +1,23 @@ +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace UniRx.InternalUtil +{ + internal interface ICancellableTaskCompletionSource + { + bool TrySetException(Exception exception); + bool TrySetCanceled(); + } + + internal class CancellableTaskCompletionSource : TaskCompletionSource, ICancellableTaskCompletionSource + { + + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs.meta new file mode 100644 index 00000000..3c07bb61 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/CancellableTaskCompletionSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 622c7ba8630c25b4c911cd1612ee0887 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs new file mode 100644 index 00000000..1a93773b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs @@ -0,0 +1,15 @@ +namespace UniRx.InternalUtil +{ + using System; + + internal static class ExceptionExtensions + { + public static void Throw(this Exception exception) + { +#if (NET_4_6 || NET_STANDARD_2_0) + System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exception).Throw(); +#endif + throw exception; + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs.meta new file mode 100644 index 00000000..e2f2bd24 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ExceptionExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 94d5d10805124b34c8b488ebf3f893eb +timeCreated: 1509016318 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs new file mode 100644 index 00000000..65d7b2da --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs @@ -0,0 +1,61 @@ +using System; + +namespace UniRx.InternalUtil +{ + // ImmutableList is sometimes useful, use for public. + public class ImmutableList + { + public static readonly ImmutableList Empty = new ImmutableList(); + + T[] data; + + public T[] Data + { + get { return data; } + } + + ImmutableList() + { + data = new T[0]; + } + + public ImmutableList(T[] data) + { + this.data = data; + } + + public ImmutableList Add(T value) + { + var newData = new T[data.Length + 1]; + Array.Copy(data, newData, data.Length); + newData[data.Length] = value; + return new ImmutableList(newData); + } + + public ImmutableList Remove(T value) + { + var i = IndexOf(value); + if (i < 0) return this; + + var length = data.Length; + if (length == 1) return Empty; + + var newData = new T[length - 1]; + + Array.Copy(data, 0, newData, 0, i); + Array.Copy(data, i + 1, newData, i, length - i - 1); + + return new ImmutableList(newData); + } + + public int IndexOf(T value) + { + for (var i = 0; i < data.Length; ++i) + { + // ImmutableList only use for IObserver(no worry for boxed) + if (object.Equals(data[i], value)) return i; + } + return -1; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs.meta new file mode 100644 index 00000000..7e9dd00d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ImmutableList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dbafd8a41f556ec40b4bbd46fca2e85c +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs new file mode 100644 index 00000000..4e560b64 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx.InternalUtil +{ + public class ListObserver : IObserver + { + private readonly ImmutableList> _observers; + + public ListObserver(ImmutableList> observers) + { + _observers = observers; + } + + public void OnCompleted() + { + var targetObservers = _observers.Data; + for (int i = 0; i < targetObservers.Length; i++) + { + targetObservers[i].OnCompleted(); + } + } + + public void OnError(Exception error) + { + var targetObservers = _observers.Data; + for (int i = 0; i < targetObservers.Length; i++) + { + targetObservers[i].OnError(error); + } + } + + public void OnNext(T value) + { + var targetObservers = _observers.Data; + for (int i = 0; i < targetObservers.Length; i++) + { + targetObservers[i].OnNext(value); + } + } + + internal IObserver Add(IObserver observer) + { + return new ListObserver(_observers.Add(observer)); + } + + internal IObserver Remove(IObserver observer) + { + var i = Array.IndexOf(_observers.Data, observer); + if (i < 0) + return this; + + if (_observers.Data.Length == 2) + { + return _observers.Data[1 - i]; + } + else + { + return new ListObserver(_observers.Remove(observer)); + } + } + } + + public class EmptyObserver : IObserver + { + public static readonly EmptyObserver Instance = new EmptyObserver(); + + EmptyObserver() + { + + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(T value) + { + } + } + + public class ThrowObserver : IObserver + { + public static readonly ThrowObserver Instance = new ThrowObserver(); + + ThrowObserver() + { + + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + error.Throw(); + } + + public void OnNext(T value) + { + } + } + + public class DisposedObserver : IObserver + { + public static readonly DisposedObserver Instance = new DisposedObserver(); + + DisposedObserver() + { + + } + + public void OnCompleted() + { + throw new ObjectDisposedException(""); + } + + public void OnError(Exception error) + { + throw new ObjectDisposedException(""); + } + + public void OnNext(T value) + { + throw new ObjectDisposedException(""); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs.meta new file mode 100644 index 00000000..12c62777 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ListObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 889dc2f3c5f44d24a98a2c25510b4346 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs new file mode 100644 index 00000000..ed49f828 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UniRx.InternalUtil +{ + /// + /// Simple supports(only yield return null) lightweight, threadsafe coroutine dispatcher. + /// + public class MicroCoroutine + { + const int InitialSize = 16; + + readonly object runningAndQueueLock = new object(); + readonly object arrayLock = new object(); + readonly Action unhandledExceptionCallback; + + int tail = 0; + bool running = false; + IEnumerator[] coroutines = new IEnumerator[InitialSize]; + Queue waitQueue = new Queue(); + + public MicroCoroutine(Action unhandledExceptionCallback) + { + this.unhandledExceptionCallback = unhandledExceptionCallback; + } + + public void AddCoroutine(IEnumerator enumerator) + { + lock (runningAndQueueLock) + { + if (running) + { + waitQueue.Enqueue(enumerator); + return; + } + } + + // worst case at multi threading, wait lock until finish Run() but it is super rarely. + lock (arrayLock) + { + // Ensure Capacity + if (coroutines.Length == tail) + { + Array.Resize(ref coroutines, checked(tail * 2)); + } + coroutines[tail++] = enumerator; + } + } + + public void Run() + { + lock (runningAndQueueLock) + { + running = true; + } + + lock (arrayLock) + { + var j = tail - 1; + + // eliminate array-bound check for i + for (int i = 0; i < coroutines.Length; i++) + { + var coroutine = coroutines[i]; + if (coroutine != null) + { + try + { + if (!coroutine.MoveNext()) + { + coroutines[i] = null; + } + else + { +#if UNITY_EDITOR + // validation only on Editor. + if (coroutine.Current != null) + { + UnityEngine.Debug.LogWarning("MicroCoroutine supports only yield return null. return value = " + coroutine.Current); + } +#endif + + continue; // next i + } + } + catch (Exception ex) + { + coroutines[i] = null; + try + { + unhandledExceptionCallback(ex); + } + catch { } + } + } + + // find null, loop from tail + while (i < j) + { + var fromTail = coroutines[j]; + if (fromTail != null) + { + try + { + if (!fromTail.MoveNext()) + { + coroutines[j] = null; + j--; + continue; // next j + } + else + { +#if UNITY_EDITOR + // validation only on Editor. + if (fromTail.Current != null) + { + UnityEngine.Debug.LogWarning("MicroCoroutine supports only yield return null. return value = " + coroutine.Current); + } +#endif + + // swap + coroutines[i] = fromTail; + coroutines[j] = null; + j--; + goto NEXT_LOOP; // next i + } + } + catch (Exception ex) + { + coroutines[j] = null; + j--; + try + { + unhandledExceptionCallback(ex); + } + catch { } + continue; // next j + } + } + else + { + j--; + } + } + + tail = i; // loop end + break; // LOOP END + + NEXT_LOOP: + continue; + } + + + lock (runningAndQueueLock) + { + running = false; + while (waitQueue.Count != 0) + { + if (coroutines.Length == tail) + { + Array.Resize(ref coroutines, checked(tail * 2)); + } + coroutines[tail++] = waitQueue.Dequeue(); + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs.meta new file mode 100644 index 00000000..f11dbf05 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/MicroCoroutine.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 108be6d634275c94a95eeb2a39de0792 +timeCreated: 1462599042 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs new file mode 100644 index 00000000..73b6ca57 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs @@ -0,0 +1,149 @@ +// this code is borrowed from RxOfficial(rx.codeplex.com) and modified + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace UniRx.InternalUtil +{ + internal class PriorityQueue where T : IComparable + { + private static long _count = long.MinValue; + + private IndexedItem[] _items; + private int _size; + + public PriorityQueue() + : this(16) + { + } + + public PriorityQueue(int capacity) + { + _items = new IndexedItem[capacity]; + _size = 0; + } + + private bool IsHigherPriority(int left, int right) + { + return _items[left].CompareTo(_items[right]) < 0; + } + + private void Percolate(int index) + { + if (index >= _size || index < 0) + return; + var parent = (index - 1) / 2; + if (parent < 0 || parent == index) + return; + + if (IsHigherPriority(index, parent)) + { + var temp = _items[index]; + _items[index] = _items[parent]; + _items[parent] = temp; + Percolate(parent); + } + } + + private void Heapify() + { + Heapify(0); + } + + private void Heapify(int index) + { + if (index >= _size || index < 0) + return; + + var left = 2 * index + 1; + var right = 2 * index + 2; + var first = index; + + if (left < _size && IsHigherPriority(left, first)) + first = left; + if (right < _size && IsHigherPriority(right, first)) + first = right; + if (first != index) + { + var temp = _items[index]; + _items[index] = _items[first]; + _items[first] = temp; + Heapify(first); + } + } + + public int Count { get { return _size; } } + + public T Peek() + { + if (_size == 0) + throw new InvalidOperationException("HEAP is Empty"); + + return _items[0].Value; + } + + private void RemoveAt(int index) + { + _items[index] = _items[--_size]; + _items[_size] = default(IndexedItem); + Heapify(); + if (_size < _items.Length / 4) + { + var temp = _items; + _items = new IndexedItem[_items.Length / 2]; + Array.Copy(temp, 0, _items, 0, _size); + } + } + + public T Dequeue() + { + var result = Peek(); + RemoveAt(0); + return result; + } + + public void Enqueue(T item) + { + if (_size >= _items.Length) + { + var temp = _items; + _items = new IndexedItem[_items.Length * 2]; + Array.Copy(temp, _items, temp.Length); + } + + var index = _size++; + _items[index] = new IndexedItem { Value = item, Id = Interlocked.Increment(ref _count) }; + Percolate(index); + } + + public bool Remove(T item) + { + for (var i = 0; i < _size; ++i) + { + if (EqualityComparer.Default.Equals(_items[i].Value, item)) + { + RemoveAt(i); + return true; + } + } + + return false; + } + + struct IndexedItem : IComparable + { + public T Value; + public long Id; + + public int CompareTo(IndexedItem other) + { + var c = Value.CompareTo(other.Value); + if (c == 0) + c = Id.CompareTo(other.Id); + return c; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs.meta new file mode 100644 index 00000000..67707f0c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PriorityQueue.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7956b408e24dc5a4884fe4f5a3d7c858 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs new file mode 100644 index 00000000..a5d67706 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs @@ -0,0 +1,26 @@ +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace UniRx.InternalUtil +{ + internal static class PromiseHelper + { + internal static void TrySetResultAll(IEnumerable> source, T value) + { + var rentArray = source.ToArray(); // better to use Arraypool. + var array = rentArray; + var len = rentArray.Length; + for (int i = 0; i < len; i++) + { + array[i].TrySetResult(value); + array[i] = null; + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs.meta new file mode 100644 index 00000000..4060444f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/PromiseHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: daa7aa90cece0fe40920a35e79f526dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs new file mode 100644 index 00000000..6f75d519 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs @@ -0,0 +1,257 @@ +// this code is borrowed from RxOfficial(rx.codeplex.com) and 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; + +namespace UniRx.InternalUtil +{ + /// + /// Abstract base class for scheduled work items. + /// + internal class ScheduledItem : IComparable + { + private readonly BooleanDisposable _disposable = new BooleanDisposable(); + private readonly TimeSpan _dueTime; + private readonly Action _action; + + /// + /// Creates a new scheduled work item to run at the specified time. + /// + /// Absolute time at which the work item has to be executed. + public ScheduledItem(Action action, TimeSpan dueTime) + { + _dueTime = dueTime; + _action = action; + } + + /// + /// Gets the absolute time at which the item is due for invocation. + /// + public TimeSpan DueTime + { + get { return _dueTime; } + } + + /// + /// Invokes the work item. + /// + public void Invoke() + { + if (!_disposable.IsDisposed) + { + _action(); + } + } + + #region Inequality + + /// + /// Compares the work item with another work item based on absolute time values. + /// + /// Work item to compare the current work item to. + /// Relative ordering between this and the specified work item. + /// The inequality operators are overloaded to provide results consistent with the IComparable implementation. Equality operators implement traditional reference equality semantics. + public int CompareTo(ScheduledItem other) + { + // MSDN: By definition, any object compares greater than null, and two null references compare equal to each other. + if (object.ReferenceEquals(other, null)) + return 1; + + return DueTime.CompareTo(other.DueTime); + } + + /// + /// Determines whether one specified ScheduledItem<TAbsolute> object is due before a second specified ScheduledItem<TAbsolute> object. + /// + /// The first object to compare. + /// The second object to compare. + /// true if the DueTime value of left is earlier than the DueTime value of right; otherwise, false. + /// This operator provides results consistent with the IComparable implementation. + public static bool operator <(ScheduledItem left, ScheduledItem right) + { + return left.CompareTo(right) < 0; + } + + /// + /// Determines whether one specified ScheduledItem<TAbsolute> object is due before or at the same of a second specified ScheduledItem<TAbsolute> object. + /// + /// The first object to compare. + /// The second object to compare. + /// true if the DueTime value of left is earlier than or simultaneous with the DueTime value of right; otherwise, false. + /// This operator provides results consistent with the IComparable implementation. + public static bool operator <=(ScheduledItem left, ScheduledItem right) + { + return left.CompareTo(right) <= 0; + } + + /// + /// Determines whether one specified ScheduledItem<TAbsolute> object is due after a second specified ScheduledItem<TAbsolute> object. + /// + /// The first object to compare. + /// The second object to compare. + /// true if the DueTime value of left is later than the DueTime value of right; otherwise, false. + /// This operator provides results consistent with the IComparable implementation. + public static bool operator >(ScheduledItem left, ScheduledItem right) + { + return left.CompareTo(right) > 0; + } + + /// + /// Determines whether one specified ScheduledItem<TAbsolute> object is due after or at the same time of a second specified ScheduledItem<TAbsolute> object. + /// + /// The first object to compare. + /// The second object to compare. + /// true if the DueTime value of left is later than or simultaneous with the DueTime value of right; otherwise, false. + /// This operator provides results consistent with the IComparable implementation. + public static bool operator >=(ScheduledItem left, ScheduledItem right) + { + return left.CompareTo(right) >= 0; + } + + #endregion + + #region Equality + + /// + /// Determines whether two specified ScheduledItem<TAbsolute, TValue> objects are equal. + /// + /// The first object to compare. + /// The second object to compare. + /// true if both ScheduledItem<TAbsolute, TValue> are equal; otherwise, false. + /// This operator does not provide results consistent with the IComparable implementation. Instead, it implements reference equality. + public static bool operator ==(ScheduledItem left, ScheduledItem right) + { + return object.ReferenceEquals(left, right); + } + + /// + /// Determines whether two specified ScheduledItem<TAbsolute, TValue> objects are inequal. + /// + /// The first object to compare. + /// The second object to compare. + /// true if both ScheduledItem<TAbsolute, TValue> are inequal; otherwise, false. + /// This operator does not provide results consistent with the IComparable implementation. Instead, it implements reference equality. + public static bool operator !=(ScheduledItem left, ScheduledItem right) + { + return !(left == right); + } + + /// + /// Determines whether a ScheduledItem<TAbsolute> object is equal to the specified object. + /// + /// The object to compare to the current ScheduledItem<TAbsolute> object. + /// true if the obj parameter is a ScheduledItem<TAbsolute> object and is equal to the current ScheduledItem<TAbsolute> object; otherwise, false. + public override bool Equals(object obj) + { + return object.ReferenceEquals(this, obj); + } + + /// + /// Returns the hash code for the current ScheduledItem<TAbsolute> object. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return base.GetHashCode(); + } + + #endregion + + public IDisposable Cancellation + { + get + { + return _disposable; + } + } + + /// + /// Gets whether the work item has received a cancellation request. + /// + public bool IsCanceled + { + get { return _disposable.IsDisposed; } + } + } + + /// + /// Efficient scheduler queue that maintains scheduled items sorted by absolute time. + /// + /// This type is not thread safe; users should ensure proper synchronization. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "But it *is* a queue!")] + internal class SchedulerQueue + { + private readonly PriorityQueue _queue; + + /// + /// Creates a new scheduler queue with a default initial capacity. + /// + public SchedulerQueue() + : this(1024) + { + } + + /// + /// Creats a new scheduler queue with the specified initial capacity. + /// + /// Initial capacity of the scheduler queue. + /// is less than zero. + public SchedulerQueue(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity"); + + _queue = new PriorityQueue(capacity); + } + + /// + /// Gets the number of scheduled items in the scheduler queue. + /// + public int Count + { + get + { + return _queue.Count; + } + } + + /// + /// Enqueues the specified work item to be scheduled. + /// + /// Work item to be scheduled. + public void Enqueue(ScheduledItem scheduledItem) + { + _queue.Enqueue(scheduledItem); + } + + /// + /// Removes the specified work item from the scheduler queue. + /// + /// Work item to be removed from the scheduler queue. + /// true if the item was found; false otherwise. + public bool Remove(ScheduledItem scheduledItem) + { + return _queue.Remove(scheduledItem); + } + + /// + /// Dequeues the next work item from the scheduler queue. + /// + /// Next work item in the scheduler queue (removed). + public ScheduledItem Dequeue() + { + return _queue.Dequeue(); + } + + /// + /// Peeks the next work item in the scheduler queue. + /// + /// Next work item in the scheduler queue (not removed). + public ScheduledItem Peek() + { + return _queue.Peek(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs.meta new file mode 100644 index 00000000..01892605 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ScheduledItem.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 45457ee4a77967347828238b7a52b851 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs new file mode 100644 index 00000000..68293264 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs @@ -0,0 +1,112 @@ +using System; + +namespace UniRx.InternalUtil +{ + public class ThreadSafeQueueWorker + { + const int MaxArrayLength = 0X7FEFFFFF; + const int InitialSize = 16; + + object gate = new object(); + bool dequing = false; + + int actionListCount = 0; + Action[] actionList = new Action[InitialSize]; + object[] actionStates = new object[InitialSize]; + + int waitingListCount = 0; + Action[] waitingList = new Action[InitialSize]; + object[] waitingStates = new object[InitialSize]; + + public void Enqueue(Action action, object state) + { + lock (gate) + { + if (dequing) + { + // Ensure Capacity + if (waitingList.Length == waitingListCount) + { + var newLength = waitingListCount * 2; + if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; + + var newArray = new Action[newLength]; + var newArrayState = new object[newLength]; + Array.Copy(waitingList, newArray, waitingListCount); + Array.Copy(waitingStates, newArrayState, waitingListCount); + waitingList = newArray; + waitingStates = newArrayState; + } + waitingList[waitingListCount] = action; + waitingStates[waitingListCount] = state; + waitingListCount++; + } + else + { + // Ensure Capacity + if (actionList.Length == actionListCount) + { + var newLength = actionListCount * 2; + if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; + + var newArray = new Action[newLength]; + var newArrayState = new object[newLength]; + Array.Copy(actionList, newArray, actionListCount); + Array.Copy(actionStates, newArrayState, actionListCount); + actionList = newArray; + actionStates = newArrayState; + } + actionList[actionListCount] = action; + actionStates[actionListCount] = state; + actionListCount++; + } + } + } + + public void ExecuteAll(Action unhandledExceptionCallback) + { + lock (gate) + { + if (actionListCount == 0) return; + + dequing = true; + } + + for (int i = 0; i < actionListCount; i++) + { + var action = actionList[i]; + var state = actionStates[i]; + try + { + action(state); + } + catch (Exception ex) + { + unhandledExceptionCallback(ex); + } + finally + { + // Clear + actionList[i] = null; + actionStates[i] = null; + } + } + + lock (gate) + { + dequing = false; + + var swapTempActionList = actionList; + var swapTempActionStates = actionStates; + + actionListCount = waitingListCount; + actionList = waitingList; + actionStates = waitingStates; + + waitingListCount = 0; + waitingList = swapTempActionList; + waitingStates = swapTempActionStates; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs.meta new file mode 100644 index 00000000..45bffab6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/ThreadSafeQueueWorker.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 768cbfcbe2a8e704a8953eea28cd33df +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs new file mode 100644 index 00000000..18e1c523 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs @@ -0,0 +1,271 @@ +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#endif + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace UniRx.InternalUtil +{ + internal static class UnityEqualityComparer + { + public static readonly IEqualityComparer Vector2 = new Vector2EqualityComparer(); + public static readonly IEqualityComparer Vector3 = new Vector3EqualityComparer(); + public static readonly IEqualityComparer Vector4 = new Vector4EqualityComparer(); + public static readonly IEqualityComparer Color = new ColorEqualityComparer(); + public static readonly IEqualityComparer Color32 = new Color32EqualityComparer(); + public static readonly IEqualityComparer Rect = new RectEqualityComparer(); + public static readonly IEqualityComparer Bounds = new BoundsEqualityComparer(); + public static readonly IEqualityComparer Quaternion = new QuaternionEqualityComparer(); + + static readonly RuntimeTypeHandle vector2Type = typeof(Vector2).TypeHandle; + static readonly RuntimeTypeHandle vector3Type = typeof(Vector3).TypeHandle; + static readonly RuntimeTypeHandle vector4Type = typeof(Vector4).TypeHandle; + static readonly RuntimeTypeHandle colorType = typeof(Color).TypeHandle; + static readonly RuntimeTypeHandle color32Type = typeof(Color32).TypeHandle; + static readonly RuntimeTypeHandle rectType = typeof(Rect).TypeHandle; + static readonly RuntimeTypeHandle boundsType = typeof(Bounds).TypeHandle; + static readonly RuntimeTypeHandle quaternionType = typeof(Quaternion).TypeHandle; + +#if UNITY_2017_2_OR_NEWER + + public static readonly IEqualityComparer Vector2Int = new Vector2IntEqualityComparer(); + public static readonly IEqualityComparer Vector3Int = new Vector3IntEqualityComparer(); + public static readonly IEqualityComparer RangeInt = new RangeIntEqualityComparer(); + public static readonly IEqualityComparer RectInt = new RectIntEqualityComparer(); + public static readonly IEqualityComparer BoundsInt = new BoundsIntEqualityComparer(); + + static readonly RuntimeTypeHandle vector2IntType = typeof(Vector2Int).TypeHandle; + static readonly RuntimeTypeHandle vector3IntType = typeof(Vector3Int).TypeHandle; + static readonly RuntimeTypeHandle rangeIntType = typeof(RangeInt).TypeHandle; + static readonly RuntimeTypeHandle rectIntType = typeof(RectInt).TypeHandle; + static readonly RuntimeTypeHandle boundsIntType = typeof(BoundsInt).TypeHandle; + +#endif + + static class Cache + { + public static readonly IEqualityComparer Comparer; + + static Cache() + { + var comparer = GetDefaultHelper(typeof(T)); + if (comparer == null) + { + Comparer = EqualityComparer.Default; + } + else + { + Comparer = (IEqualityComparer)comparer; + } + } + } + + public static IEqualityComparer GetDefault() + { + return Cache.Comparer; + } + + static object GetDefaultHelper(Type type) + { + var t = type.TypeHandle; + + if (t.Equals(vector2Type)) return (object)UnityEqualityComparer.Vector2; + if (t.Equals(vector3Type)) return (object)UnityEqualityComparer.Vector3; + if (t.Equals(vector4Type)) return (object)UnityEqualityComparer.Vector4; + if (t.Equals(colorType)) return (object)UnityEqualityComparer.Color; + if (t.Equals(color32Type)) return (object)UnityEqualityComparer.Color32; + if (t.Equals(rectType)) return (object)UnityEqualityComparer.Rect; + if (t.Equals(boundsType)) return (object)UnityEqualityComparer.Bounds; + if (t.Equals(quaternionType)) return (object)UnityEqualityComparer.Quaternion; + +#if UNITY_2017_2_OR_NEWER + + if (t.Equals(vector2IntType)) return (object)UnityEqualityComparer.Vector2Int; + if (t.Equals(vector3IntType)) return (object)UnityEqualityComparer.Vector3Int; + if (t.Equals(rangeIntType)) return (object)UnityEqualityComparer.RangeInt; + if (t.Equals(rectIntType)) return (object)UnityEqualityComparer.RectInt; + if (t.Equals(boundsIntType)) return (object)UnityEqualityComparer.BoundsInt; +#endif + + return null; + } + + sealed class Vector2EqualityComparer : IEqualityComparer + { + public bool Equals(Vector2 self, Vector2 vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y); + } + + public int GetHashCode(Vector2 obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2; + } + } + + sealed class Vector3EqualityComparer : IEqualityComparer + { + public bool Equals(Vector3 self, Vector3 vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z); + } + + public int GetHashCode(Vector3 obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2; + } + } + + sealed class Vector4EqualityComparer : IEqualityComparer + { + public bool Equals(Vector4 self, Vector4 vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z) && self.w.Equals(vector.w); + } + + public int GetHashCode(Vector4 obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2 ^ obj.w.GetHashCode() >> 1; + } + } + + sealed class ColorEqualityComparer : IEqualityComparer + { + public bool Equals(Color self, Color other) + { + return self.r.Equals(other.r) && self.g.Equals(other.g) && self.b.Equals(other.b) && self.a.Equals(other.a); + } + + public int GetHashCode(Color obj) + { + return obj.r.GetHashCode() ^ obj.g.GetHashCode() << 2 ^ obj.b.GetHashCode() >> 2 ^ obj.a.GetHashCode() >> 1; + } + } + + sealed class RectEqualityComparer : IEqualityComparer + { + public bool Equals(Rect self, Rect other) + { + return self.x.Equals(other.x) && self.width.Equals(other.width) && self.y.Equals(other.y) && self.height.Equals(other.height); + } + + public int GetHashCode(Rect obj) + { + return obj.x.GetHashCode() ^ obj.width.GetHashCode() << 2 ^ obj.y.GetHashCode() >> 2 ^ obj.height.GetHashCode() >> 1; + } + } + + sealed class BoundsEqualityComparer : IEqualityComparer + { + public bool Equals(Bounds self, Bounds vector) + { + return self.center.Equals(vector.center) && self.extents.Equals(vector.extents); + } + + public int GetHashCode(Bounds obj) + { + return obj.center.GetHashCode() ^ obj.extents.GetHashCode() << 2; + } + } + + sealed class QuaternionEqualityComparer : IEqualityComparer + { + public bool Equals(Quaternion self, Quaternion vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z) && self.w.Equals(vector.w); + } + + public int GetHashCode(Quaternion obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2 ^ obj.w.GetHashCode() >> 1; + } + } + + sealed class Color32EqualityComparer : IEqualityComparer + { + public bool Equals(Color32 self, Color32 vector) + { + return self.a.Equals(vector.a) && self.r.Equals(vector.r) && self.g.Equals(vector.g) && self.b.Equals(vector.b); + } + + public int GetHashCode(Color32 obj) + { + return obj.a.GetHashCode() ^ obj.r.GetHashCode() << 2 ^ obj.g.GetHashCode() >> 2 ^ obj.b.GetHashCode() >> 1; + } + } + +#if UNITY_2017_2_OR_NEWER + + sealed class Vector2IntEqualityComparer : IEqualityComparer + { + public bool Equals(Vector2Int self, Vector2Int vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y); + } + + public int GetHashCode(Vector2Int obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2; + } + } + + sealed class Vector3IntEqualityComparer : IEqualityComparer + { + public static readonly Vector3IntEqualityComparer Default = new Vector3IntEqualityComparer(); + + public bool Equals(Vector3Int self, Vector3Int vector) + { + return self.x.Equals(vector.x) && self.y.Equals(vector.y) && self.z.Equals(vector.z); + } + + public int GetHashCode(Vector3Int obj) + { + return obj.x.GetHashCode() ^ obj.y.GetHashCode() << 2 ^ obj.z.GetHashCode() >> 2; + } + } + + sealed class RangeIntEqualityComparer : IEqualityComparer + { + public bool Equals(RangeInt self, RangeInt vector) + { + return self.start.Equals(vector.start) && self.length.Equals(vector.length); + } + + public int GetHashCode(RangeInt obj) + { + return obj.start.GetHashCode() ^ obj.length.GetHashCode() << 2; + } + } + + sealed class RectIntEqualityComparer : IEqualityComparer + { + public bool Equals(RectInt self, RectInt other) + { + return self.x.Equals(other.x) && self.width.Equals(other.width) && self.y.Equals(other.y) && self.height.Equals(other.height); + } + + public int GetHashCode(RectInt obj) + { + return obj.x.GetHashCode() ^ obj.width.GetHashCode() << 2 ^ obj.y.GetHashCode() >> 2 ^ obj.height.GetHashCode() >> 1; + } + } + + sealed class BoundsIntEqualityComparer : IEqualityComparer + { + public bool Equals(BoundsInt self, BoundsInt vector) + { + return Vector3IntEqualityComparer.Default.Equals(self.position, vector.position) + && Vector3IntEqualityComparer.Default.Equals(self.size, vector.size); + } + + public int GetHashCode(BoundsInt obj) + { + return Vector3IntEqualityComparer.Default.GetHashCode(obj.position) ^ Vector3IntEqualityComparer.Default.GetHashCode(obj.size) << 2; + } + } + +#endif + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs.meta new file mode 100644 index 00000000..6f60150f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/InternalUtil/UnityEqualityComparer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 626a410137515ac45bb59d1ca91d8f3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs new file mode 100644 index 00000000..a0441625 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs @@ -0,0 +1,678 @@ +// original code from rx.codeplex.com +// some modified. + +/* ------------------ */ + +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System.Diagnostics; +using System.Globalization; +using System.Collections.Generic; +using System; +using UniRx.InternalUtil; + +#pragma warning disable 0659 +#pragma warning disable 0661 + +namespace UniRx +{ + /// + /// Provides a mechanism for receiving push-based notifications and returning a response. + /// + /// + /// The type of the elements received by the observer. + /// This type parameter is contravariant. That is, you can use either the type you specified or any type that is less derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics. + /// + /// + /// The type of the result returned from the observer's notification handlers. + /// This type parameter is covariant. That is, you can use either the type you specified or any type that is more derived. For more information about covariance and contravariance, see Covariance and Contravariance in Generics. + /// + public interface IObserver + { + /// + /// Notifies the observer of a new element in the sequence. + /// + /// The new element in the sequence. + /// Result returned upon observation of a new element. + TResult OnNext(TValue value); + + /// + /// Notifies the observer that an exception has occurred. + /// + /// The exception that occurred. + /// Result returned upon observation of an error. + TResult OnError(Exception exception); + + /// + /// Notifies the observer of the end of the sequence. + /// + /// Result returned upon observation of the sequence completion. + TResult OnCompleted(); + } + + /// + /// Indicates the type of a notification. + /// + public enum NotificationKind + { + /// + /// Represents an OnNext notification. + /// + OnNext, + + /// + /// Represents an OnError notification. + /// + OnError, + + /// + /// Represents an OnCompleted notification. + /// + OnCompleted + } + + /// + /// Represents a notification to an observer. + /// + /// The type of the elements received by the observer. + [Serializable] + public abstract class Notification : IEquatable> + { + /// + /// Default constructor used by derived types. + /// + protected internal Notification() + { + } + + /// + /// Returns the value of an OnNext notification or throws an exception. + /// + public abstract T Value + { + get; + } + + /// + /// Returns a value that indicates whether the notification has a value. + /// + public abstract bool HasValue + { + get; + } + + /// + /// Returns the exception of an OnError notification or returns null. + /// + public abstract Exception Exception + { + get; + } + + /// + /// Gets the kind of notification that is represented. + /// + public abstract NotificationKind Kind + { + get; + } + + /// + /// Represents an OnNext notification to an observer. + /// + [DebuggerDisplay("OnNext({Value})")] + [Serializable] + internal sealed class OnNextNotification : Notification + { + T value; + + /// + /// Constructs a notification of a new value. + /// + public OnNextNotification(T value) + { + this.value = value; + } + + /// + /// Returns the value of an OnNext notification. + /// + public override T Value { get { return value; } } + + /// + /// Returns null. + /// + public override Exception Exception { get { return null; } } + + /// + /// Returns true. + /// + public override bool HasValue { get { return true; } } + + /// + /// Returns NotificationKind.OnNext. + /// + public override NotificationKind Kind { get { return NotificationKind.OnNext; } } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(Value); + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + public override bool Equals(Notification other) + { + if (Object.ReferenceEquals(this, other)) + return true; + if (Object.ReferenceEquals(other, null)) + return false; + if (other.Kind != NotificationKind.OnNext) + return false; + return EqualityComparer.Default.Equals(Value, other.Value); + } + + /// + /// Returns a string representation of this instance. + /// + public override string ToString() + { + return String.Format(CultureInfo.CurrentCulture, "OnNext({0})", Value); + } + + /// + /// Invokes the observer's method corresponding to the notification. + /// + /// Observer to invoke the notification on. + public override void Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + observer.OnNext(Value); + } + + /// + /// Invokes the observer's method corresponding to the notification and returns the produced result. + /// + /// Observer to invoke the notification on. + /// Result produced by the observation. + public override TResult Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + return observer.OnNext(Value); + } + + /// + /// Invokes the delegate corresponding to the notification. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + public override void Accept(Action onNext, Action onError, Action onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + onNext(Value); + } + + /// + /// Invokes the delegate corresponding to the notification and returns the produced result. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + /// Result produced by the observation. + public override TResult Accept(Func onNext, Func onError, Func onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + return onNext(Value); + } + } + + /// + /// Represents an OnError notification to an observer. + /// +#if !NO_DEBUGGER_ATTRIBUTES + [DebuggerDisplay("OnError({Exception})")] +#endif +#if !NO_SERIALIZABLE + [Serializable] +#endif + internal sealed class OnErrorNotification : Notification + { + Exception exception; + + /// + /// Constructs a notification of an exception. + /// + public OnErrorNotification(Exception exception) + { + this.exception = exception; + } + + /// + /// Throws the exception. + /// + public override T Value { get { exception.Throw(); throw exception; } } + + /// + /// Returns the exception. + /// + public override Exception Exception { get { return exception; } } + + /// + /// Returns false. + /// + public override bool HasValue { get { return false; } } + + /// + /// Returns NotificationKind.OnError. + /// + public override NotificationKind Kind { get { return NotificationKind.OnError; } } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return Exception.GetHashCode(); + } + + /// + /// Indicates whether this instance and other are equal. + /// + public override bool Equals(Notification other) + { + if (Object.ReferenceEquals(this, other)) + return true; + if (Object.ReferenceEquals(other, null)) + return false; + if (other.Kind != NotificationKind.OnError) + return false; + return Object.Equals(Exception, other.Exception); + } + + /// + /// Returns a string representation of this instance. + /// + public override string ToString() + { + return String.Format(CultureInfo.CurrentCulture, "OnError({0})", Exception.GetType().FullName); + } + + /// + /// Invokes the observer's method corresponding to the notification. + /// + /// Observer to invoke the notification on. + public override void Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + observer.OnError(Exception); + } + + /// + /// Invokes the observer's method corresponding to the notification and returns the produced result. + /// + /// Observer to invoke the notification on. + /// Result produced by the observation. + public override TResult Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + return observer.OnError(Exception); + } + + /// + /// Invokes the delegate corresponding to the notification. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + public override void Accept(Action onNext, Action onError, Action onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + onError(Exception); + } + + /// + /// Invokes the delegate corresponding to the notification and returns the produced result. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + /// Result produced by the observation. + public override TResult Accept(Func onNext, Func onError, Func onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + return onError(Exception); + } + } + + /// + /// Represents an OnCompleted notification to an observer. + /// + [DebuggerDisplay("OnCompleted()")] + [Serializable] + internal sealed class OnCompletedNotification : Notification + { + /// + /// Constructs a notification of the end of a sequence. + /// + public OnCompletedNotification() + { + } + + /// + /// Throws an InvalidOperationException. + /// + public override T Value { get { throw new InvalidOperationException("No Value"); } } + + /// + /// Returns null. + /// + public override Exception Exception { get { return null; } } + + /// + /// Returns false. + /// + public override bool HasValue { get { return false; } } + + /// + /// Returns NotificationKind.OnCompleted. + /// + public override NotificationKind Kind { get { return NotificationKind.OnCompleted; } } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return typeof(T).GetHashCode() ^ 8510; + } + + /// + /// Indicates whether this instance and other are equal. + /// + public override bool Equals(Notification other) + { + if (Object.ReferenceEquals(this, other)) + return true; + if (Object.ReferenceEquals(other, null)) + return false; + return other.Kind == NotificationKind.OnCompleted; + } + + /// + /// Returns a string representation of this instance. + /// + public override string ToString() + { + return "OnCompleted()"; + } + + /// + /// Invokes the observer's method corresponding to the notification. + /// + /// Observer to invoke the notification on. + public override void Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + observer.OnCompleted(); + } + + /// + /// Invokes the observer's method corresponding to the notification and returns the produced result. + /// + /// Observer to invoke the notification on. + /// Result produced by the observation. + public override TResult Accept(IObserver observer) + { + if (observer == null) + throw new ArgumentNullException("observer"); + + return observer.OnCompleted(); + } + + /// + /// Invokes the delegate corresponding to the notification. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + public override void Accept(Action onNext, Action onError, Action onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + onCompleted(); + } + + /// + /// Invokes the delegate corresponding to the notification and returns the produced result. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + /// Result produced by the observation. + public override TResult Accept(Func onNext, Func onError, Func onCompleted) + { + if (onNext == null) + throw new ArgumentNullException("onNext"); + if (onError == null) + throw new ArgumentNullException("onError"); + if (onCompleted == null) + throw new ArgumentNullException("onCompleted"); + + return onCompleted(); + } + } + + /// + /// Determines whether the current Notification<T> object has the same observer message payload as a specified Notification<T> value. + /// + /// An object to compare to the current Notification<T> object. + /// true if both Notification<T> objects have the same observer message payload; otherwise, false. + /// + /// Equality of Notification<T> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any). + /// This means two Notification<T> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method. + /// In case one wants to determine whether two Notification<T> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead. + /// + public abstract bool Equals(Notification other); + + /// + /// Determines whether the two specified Notification<T> objects have the same observer message payload. + /// + /// The first Notification<T> to compare, or null. + /// The second Notification<T> to compare, or null. + /// true if the first Notification<T> value has the same observer message payload as the second Notification<T> value; otherwise, false. + /// + /// Equality of Notification<T> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any). + /// This means two Notification<T> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method. + /// In case one wants to determine whether two Notification<T> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead. + /// + public static bool operator ==(Notification left, Notification right) + { + if (object.ReferenceEquals(left, right)) + return true; + + if ((object)left == null || (object)right == null) + return false; + + return left.Equals(right); + } + + /// + /// Determines whether the two specified Notification<T> objects have a different observer message payload. + /// + /// The first Notification<T> to compare, or null. + /// The second Notification<T> to compare, or null. + /// true if the first Notification<T> value has a different observer message payload as the second Notification<T> value; otherwise, false. + /// + /// Equality of Notification<T> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any). + /// This means two Notification<T> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method. + /// In case one wants to determine whether two Notification<T> objects represent a different observer method call, use Object.ReferenceEquals identity equality instead. + /// + public static bool operator !=(Notification left, Notification right) + { + return !(left == right); + } + + /// + /// Determines whether the specified System.Object is equal to the current Notification<T>. + /// + /// The System.Object to compare with the current Notification<T>. + /// true if the specified System.Object is equal to the current Notification<T>; otherwise, false. + /// + /// Equality of Notification<T> objects is based on the equality of the observer message payload they represent, including the notification Kind and the Value or Exception (if any). + /// This means two Notification<T> objects can be equal even though they don't represent the same observer method call, but have the same Kind and have equal parameters passed to the observer method. + /// In case one wants to determine whether two Notification<T> objects represent the same observer method call, use Object.ReferenceEquals identity equality instead. + /// + public override bool Equals(object obj) + { + return Equals(obj as Notification); + } + + /// + /// Invokes the observer's method corresponding to the notification. + /// + /// Observer to invoke the notification on. + public abstract void Accept(IObserver observer); + + /// + /// Invokes the observer's method corresponding to the notification and returns the produced result. + /// + /// The type of the result returned from the observer's notification handlers. + /// Observer to invoke the notification on. + /// Result produced by the observation. + public abstract TResult Accept(IObserver observer); + + /// + /// Invokes the delegate corresponding to the notification. + /// + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + public abstract void Accept(Action onNext, Action onError, Action onCompleted); + + /// + /// Invokes the delegate corresponding to the notification and returns the produced result. + /// + /// The type of the result returned from the notification handler delegates. + /// Delegate to invoke for an OnNext notification. + /// Delegate to invoke for an OnError notification. + /// Delegate to invoke for an OnCompleted notification. + /// Result produced by the observation. + public abstract TResult Accept(Func onNext, Func onError, Func onCompleted); + + /// + /// Returns an observable sequence with a single notification, using the immediate scheduler. + /// + /// The observable sequence that surfaces the behavior of the notification upon subscription. + public IObservable ToObservable() + { + return this.ToObservable(Scheduler.Immediate); + } + + /// + /// Returns an observable sequence with a single notification. + /// + /// Scheduler to send out the notification calls on. + /// The observable sequence that surfaces the behavior of the notification upon subscription. + public IObservable ToObservable(IScheduler scheduler) + { + if (scheduler == null) + throw new ArgumentNullException("scheduler"); + + return Observable.Create(observer => scheduler.Schedule(() => + { + this.Accept(observer); + if (this.Kind == NotificationKind.OnNext) + observer.OnCompleted(); + })); + } + } + + /// + /// Provides a set of static methods for constructing notifications. + /// + public static class Notification + { + /// + /// Creates an object that represents an OnNext notification to an observer. + /// + /// The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence. + /// The value contained in the notification. + /// The OnNext notification containing the value. + public static Notification CreateOnNext(T value) + { + return new Notification.OnNextNotification(value); + } + + /// + /// Creates an object that represents an OnError notification to an observer. + /// + /// The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence. + /// The exception contained in the notification. + /// The OnError notification containing the exception. + /// is null. + public static Notification CreateOnError(Exception error) + { + if (error == null) + throw new ArgumentNullException("error"); + + return new Notification.OnErrorNotification(error); + } + + /// + /// Creates an object that represents an OnCompleted notification to an observer. + /// + /// The type of the elements received by the observer. Upon dematerialization of the notifications into an observable sequence, this type is used as the element type for the sequence. + /// The OnCompleted notification. + public static Notification CreateOnCompleted() + { + return new Notification.OnCompletedNotification(); + } + } +} + +#pragma warning restore 0659 +#pragma warning restore 0661 \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs.meta new file mode 100644 index 00000000..3d5e9f12 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notification.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 169d02559aa6b3e459fbae10f2acecd8 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers.meta new file mode 100644 index 00000000..c757d9fb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 63388f4f94a67e34590e2167d45e4046 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs new file mode 100644 index 00000000..77c98eaf --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx +{ + /// + /// Notify boolean flag. + /// + public class BooleanNotifier : IObservable + { + readonly Subject boolTrigger = new Subject(); + + bool boolValue; + /// Current flag value + public bool Value + { + get { return boolValue; } + set + { + boolValue = value; + boolTrigger.OnNext(value); + } + } + + /// + /// Setup initial flag. + /// + public BooleanNotifier(bool initialValue = false) + { + this.Value = initialValue; + } + + /// + /// Set and raise true if current value isn't true. + /// + public void TurnOn() + { + if (Value != true) + { + Value = true; + } + } + + /// + /// Set and raise false if current value isn't false. + /// + public void TurnOff() + { + if (Value != false) + { + Value = false; + } + } + + /// + /// Set and raise reverse value. + /// + public void SwitchValue() + { + Value = !Value; + } + + + /// + /// Subscribe observer. + /// + public IDisposable Subscribe(IObserver observer) + { + return boolTrigger.Subscribe(observer); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs.meta new file mode 100644 index 00000000..e175f5a5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/BooleanNotifier.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5ee30c0abdddd7241acbe24df0637678 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs new file mode 100644 index 00000000..9047b96c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx +{ + /// Event kind of CountNotifier. + public enum CountChangedStatus + { + /// Count incremented. + Increment, + /// Count decremented. + Decrement, + /// Count is zero. + Empty, + /// Count arrived max. + Max + } + + /// + /// Notify event of count flag. + /// + public class CountNotifier : IObservable + { + readonly object lockObject = new object(); + readonly Subject statusChanged = new Subject(); + readonly int max; + + public int Max { get { return max; } } + public int Count { get; private set; } + + /// + /// Setup max count of signal. + /// + public CountNotifier(int max = int.MaxValue) + { + if (max <= 0) + { + throw new ArgumentException("max"); + } + + this.max = max; + } + + /// + /// Increment count and notify status. + /// + public IDisposable Increment(int incrementCount = 1) + { + if (incrementCount < 0) + { + throw new ArgumentException("incrementCount"); + } + + lock (lockObject) + { + if (Count == Max) return Disposable.Empty; + else if (incrementCount + Count > Max) Count = Max; + else Count += incrementCount; + + statusChanged.OnNext(CountChangedStatus.Increment); + if (Count == Max) statusChanged.OnNext(CountChangedStatus.Max); + + return Disposable.Create(() => this.Decrement(incrementCount)); + } + } + + /// + /// Decrement count and notify status. + /// + public void Decrement(int decrementCount = 1) + { + if (decrementCount < 0) + { + throw new ArgumentException("decrementCount"); + } + + lock (lockObject) + { + if (Count == 0) return; + else if (Count - decrementCount < 0) Count = 0; + else Count -= decrementCount; + + statusChanged.OnNext(CountChangedStatus.Decrement); + if (Count == 0) statusChanged.OnNext(CountChangedStatus.Empty); + } + } + + /// + /// Subscribe observer. + /// + public IDisposable Subscribe(IObserver observer) + { + return statusChanged.Subscribe(observer); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs.meta new file mode 100644 index 00000000..2184bcc8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/CountNotifier.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 503af1c1dc279164e83011be5110633e +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs new file mode 100644 index 00000000..69a4186f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using UniRx.InternalUtil; + +namespace UniRx +{ + public interface IMessagePublisher + { + /// + /// Send Message to all receiver. + /// + void Publish(T message); + } + + public interface IMessageReceiver + { + /// + /// Subscribe typed message. + /// + IObservable Receive(); + } + + public interface IMessageBroker : IMessagePublisher, IMessageReceiver + { + } + + public interface IAsyncMessagePublisher + { + /// + /// Send Message to all receiver and await complete. + /// + IObservable PublishAsync(T message); + } + + public interface IAsyncMessageReceiver + { + /// + /// Subscribe typed message. + /// + IDisposable Subscribe(Func> asyncMessageReceiver); + } + + public interface IAsyncMessageBroker : IAsyncMessagePublisher, IAsyncMessageReceiver + { + } + + /// + /// In-Memory PubSub filtered by Type. + /// + public class MessageBroker : IMessageBroker, IDisposable + { + /// + /// MessageBroker in Global scope. + /// + public static readonly IMessageBroker Default = new MessageBroker(); + + bool isDisposed = false; + readonly Dictionary notifiers = new Dictionary(); + + public void Publish(T message) + { + object notifier; + lock (notifiers) + { + if (isDisposed) return; + + if (!notifiers.TryGetValue(typeof(T), out notifier)) + { + return; + } + } + ((ISubject)notifier).OnNext(message); + } + + public IObservable Receive() + { + object notifier; + lock (notifiers) + { + if (isDisposed) throw new ObjectDisposedException("MessageBroker"); + + if (!notifiers.TryGetValue(typeof(T), out notifier)) + { + ISubject n = new Subject().Synchronize(); + notifier = n; + notifiers.Add(typeof(T), notifier); + } + } + + return ((IObservable)notifier).AsObservable(); + } + + public void Dispose() + { + lock (notifiers) + { + if (!isDisposed) + { + isDisposed = true; + notifiers.Clear(); + } + } + } + } + + /// + /// In-Memory PubSub filtered by Type. + /// + public class AsyncMessageBroker : IAsyncMessageBroker, IDisposable + { + /// + /// AsyncMessageBroker in Global scope. + /// + public static readonly IAsyncMessageBroker Default = new AsyncMessageBroker(); + + bool isDisposed = false; + readonly Dictionary notifiers = new Dictionary(); + + public IObservable PublishAsync(T message) + { + UniRx.InternalUtil.ImmutableList>> notifier; + lock (notifiers) + { + if (isDisposed) throw new ObjectDisposedException("AsyncMessageBroker"); + + object _notifier; + if (notifiers.TryGetValue(typeof(T), out _notifier)) + { + notifier = (UniRx.InternalUtil.ImmutableList>>)_notifier; + } + else + { + return Observable.ReturnUnit(); + } + } + + var data = notifier.Data; + var awaiter = new IObservable[data.Length]; + for (int i = 0; i < data.Length; i++) + { + awaiter[i] = data[i].Invoke(message); + } + return Observable.WhenAll(awaiter); + } + + public IDisposable Subscribe(Func> asyncMessageReceiver) + { + lock (notifiers) + { + if (isDisposed) throw new ObjectDisposedException("AsyncMessageBroker"); + + object _notifier; + if (!notifiers.TryGetValue(typeof(T), out _notifier)) + { + var notifier = UniRx.InternalUtil.ImmutableList>>.Empty; + notifier = notifier.Add(asyncMessageReceiver); + notifiers.Add(typeof(T), notifier); + } + else + { + var notifier = (ImmutableList>>)_notifier; + notifier = notifier.Add(asyncMessageReceiver); + notifiers[typeof(T)] = notifier; + } + } + + return new Subscription(this, asyncMessageReceiver); + } + + public void Dispose() + { + lock (notifiers) + { + if (!isDisposed) + { + isDisposed = true; + notifiers.Clear(); + } + } + } + + class Subscription : IDisposable + { + readonly AsyncMessageBroker parent; + readonly Func> asyncMessageReceiver; + + public Subscription(AsyncMessageBroker parent, Func> asyncMessageReceiver) + { + this.parent = parent; + this.asyncMessageReceiver = asyncMessageReceiver; + } + + public void Dispose() + { + lock (parent.notifiers) + { + object _notifier; + if (parent.notifiers.TryGetValue(typeof(T), out _notifier)) + { + var notifier = (ImmutableList>>)_notifier; + notifier = notifier.Remove(asyncMessageReceiver); + + parent.notifiers[typeof(T)] = notifier; + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs.meta new file mode 100644 index 00000000..bfb0d69b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/MessageBroker.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9dc5e3c48d083d4418ab67287f050267 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs new file mode 100644 index 00000000..c1108376 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs @@ -0,0 +1,72 @@ +using System; + +namespace UniRx +{ + /// + /// Notify value on setuped scheduler. + /// + public class ScheduledNotifier : IObservable, IProgress + { + readonly IScheduler scheduler; + readonly Subject trigger = new Subject(); + + /// + /// Use scheduler is Scheduler.DefaultSchedulers.ConstantTimeOperations. + /// + public ScheduledNotifier() + { + this.scheduler = Scheduler.DefaultSchedulers.ConstantTimeOperations; + } + /// + /// Use scheduler is argument's scheduler. + /// + public ScheduledNotifier(IScheduler scheduler) + { + if (scheduler == null) + { + throw new ArgumentNullException("scheduler"); + } + + this.scheduler = scheduler; + } + + /// + /// Push value to subscribers on setuped scheduler. + /// + public void Report(T value) + { + scheduler.Schedule(() => trigger.OnNext(value)); + } + + /// + /// Push value to subscribers on setuped scheduler. + /// + public IDisposable Report(T value, TimeSpan dueTime) + { + var cancel = scheduler.Schedule(dueTime, () => trigger.OnNext(value)); + return cancel; + } + + /// + /// Push value to subscribers on setuped scheduler. + /// + public IDisposable Report(T value, DateTimeOffset dueTime) + { + var cancel = scheduler.Schedule(dueTime, () => trigger.OnNext(value)); + return cancel; + } + + /// + /// Subscribe observer. + /// + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) + { + throw new ArgumentNullException("observer"); + } + + return trigger.Subscribe(observer); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs.meta new file mode 100644 index 00000000..7320ceda --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Notifiers/ScheduledNotifier.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e6f53242e655cbe4e889538216dc9e17 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs new file mode 100644 index 00000000..cb115ffc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IObservable Scan(this IObservable source, Func accumulator) + { + return new ScanObservable(source, accumulator); + } + + public static IObservable Scan(this IObservable source, TAccumulate seed, Func accumulator) + { + return new ScanObservable(source, seed, accumulator); + } + + public static IObservable Aggregate(this IObservable source, Func accumulator) + { + return new AggregateObservable(source, accumulator); + } + + public static IObservable Aggregate(this IObservable source, TAccumulate seed, Func accumulator) + { + return new AggregateObservable(source, seed, accumulator); + } + + public static IObservable Aggregate(this IObservable source, TAccumulate seed, Func accumulator, Func resultSelector) + { + return new AggregateObservable(source, seed, accumulator, resultSelector); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs.meta new file mode 100644 index 00000000..37910ed6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Aggregate.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 82339dddb2a9f944785f1555b83d667c +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs new file mode 100644 index 00000000..26dd07ae --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs @@ -0,0 +1,133 @@ +#if (NET_4_6 || NET_STANDARD_2_0) + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace UniRx +{ + public static partial class Observable + { + /// + /// Gets an awaiter that returns the last value of the observable sequence or throws an exception if the sequence is empty. + /// This operation subscribes to the observable sequence, making it hot. + /// + /// Source sequence to await. + public static AsyncSubject GetAwaiter(this IObservable source) + { + if (source == null) throw new ArgumentNullException("source"); + + return RunAsync(source, CancellationToken.None); + } + + /// + /// Gets an awaiter that returns the last value of the observable sequence or throws an exception if the sequence is empty. + /// This operation subscribes to the observable sequence, making it hot. + /// + /// Source sequence to await. + public static AsyncSubject GetAwaiter(this IConnectableObservable source) + { + if (source == null) throw new ArgumentNullException("source"); + + return RunAsync(source, CancellationToken.None); + } + + /// + /// Gets an awaiter that returns the last value of the observable sequence or throws an exception if the sequence is empty. + /// This operation subscribes to the observable sequence, making it hot. + /// + /// Source sequence to await. + /// Cancellation token. + public static AsyncSubject GetAwaiter(this IObservable source, CancellationToken cancellationToken) + { + if (source == null) throw new ArgumentNullException("source"); + + return RunAsync(source, cancellationToken); + } + + /// + /// Gets an awaiter that returns the last value of the observable sequence or throws an exception if the sequence is empty. + /// This operation subscribes to the observable sequence, making it hot. + /// + /// Source sequence to await. + /// Cancellation token. + public static AsyncSubject GetAwaiter(this IConnectableObservable source, CancellationToken cancellationToken) + { + if (source == null) throw new ArgumentNullException("source"); + + return RunAsync(source, cancellationToken); + } + + static AsyncSubject RunAsync(IObservable source, CancellationToken cancellationToken) + { + var s = new AsyncSubject(); + + if (cancellationToken.IsCancellationRequested) + { + return Cancel(s, cancellationToken); + } + + var d = source.Subscribe(s); + + if (cancellationToken.CanBeCanceled) + { + RegisterCancelation(s, d, cancellationToken); + } + + return s; + } + + static AsyncSubject RunAsync(IConnectableObservable source, CancellationToken cancellationToken) + { + var s = new AsyncSubject(); + + if (cancellationToken.IsCancellationRequested) + { + return Cancel(s, cancellationToken); + } + + var d = source.Subscribe(s); + var c = source.Connect(); + + if (cancellationToken.CanBeCanceled) + { + RegisterCancelation(s, StableCompositeDisposable.Create(d, c), cancellationToken); + } + + return s; + } + + static AsyncSubject Cancel(AsyncSubject subject, CancellationToken cancellationToken) + { + subject.OnError(new OperationCanceledException(cancellationToken)); + return subject; + } + + static void RegisterCancelation(AsyncSubject subject, IDisposable subscription, CancellationToken token) + { + // + // Separate method used to avoid heap allocation of closure when no cancellation is needed, + // e.g. when CancellationToken.None is provided to the RunAsync overloads. + // + + var ctr = token.Register(() => + { + subscription.Dispose(); + Cancel(subject, token); + }); + + // + // No null-check for ctr is needed: + // + // - CancellationTokenRegistration is a struct + // - Registration will succeed 99% of the time, no warranting an attempt to avoid spurious Subscribe calls + // + subject.Subscribe(Stubs.Ignore, _ => ctr.Dispose(), ctr.Dispose); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs.meta new file mode 100644 index 00000000..20543dd7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Awaiter.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ec3ea3f22d061964c8f06eb9ea78ec42 +timeCreated: 1475137543 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs new file mode 100644 index 00000000..56fcdc6d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs @@ -0,0 +1,76 @@ +using System; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IConnectableObservable Multicast(this IObservable source, ISubject subject) + { + return new ConnectableObservable(source, subject); + } + + public static IConnectableObservable Publish(this IObservable source) + { + return source.Multicast(new Subject()); + } + + public static IConnectableObservable Publish(this IObservable source, T initialValue) + { + return source.Multicast(new BehaviorSubject(initialValue)); + } + + public static IConnectableObservable PublishLast(this IObservable source) + { + return source.Multicast(new AsyncSubject()); + } + + public static IConnectableObservable Replay(this IObservable source) + { + return source.Multicast(new ReplaySubject()); + } + + public static IConnectableObservable Replay(this IObservable source, IScheduler scheduler) + { + return source.Multicast(new ReplaySubject(scheduler)); + } + + public static IConnectableObservable Replay(this IObservable source, int bufferSize) + { + return source.Multicast(new ReplaySubject(bufferSize)); + } + + public static IConnectableObservable Replay(this IObservable source, int bufferSize, IScheduler scheduler) + { + return source.Multicast(new ReplaySubject(bufferSize, scheduler)); + } + + public static IConnectableObservable Replay(this IObservable source, TimeSpan window) + { + return source.Multicast(new ReplaySubject(window)); + } + + public static IConnectableObservable Replay(this IObservable source, TimeSpan window, IScheduler scheduler) + { + return source.Multicast(new ReplaySubject(window, scheduler)); + } + + public static IConnectableObservable Replay(this IObservable source, int bufferSize, TimeSpan window, IScheduler scheduler) + { + return source.Multicast(new ReplaySubject(bufferSize, window, scheduler)); + } + + public static IObservable RefCount(this IConnectableObservable source) + { + return new RefCountObservable(source); + } + + /// + /// same as Publish().RefCount() + /// + public static IObservable Share(this IObservable source) + { + return source.Publish().RefCount(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs.meta new file mode 100644 index 00000000..491bae61 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Binding.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bb11a562e64264645b76ad3a8d15d966 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs new file mode 100644 index 00000000..1f203a04 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs @@ -0,0 +1,17 @@ +using System; + +namespace UniRx +{ + public static partial class Observable + { + public static T Wait(this IObservable source) + { + return new UniRx.Operators.Wait(source, InfiniteTimeSpan).Run(); + } + + public static T Wait(this IObservable source, TimeSpan timeout) + { + return new UniRx.Operators.Wait(source, timeout).Run(); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs.meta new file mode 100644 index 00000000..da9838f3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Blocking.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4a05ec8aabbdba24388b7b2ae6c4a474 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs new file mode 100644 index 00000000..5aff4dad --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using UniRx.Operators; + +namespace UniRx +{ + // concatenate multiple observable + // merge, concat, zip... + public static partial class Observable + { + static IEnumerable> CombineSources(IObservable first, IObservable[] seconds) + { + yield return first; + for (int i = 0; i < seconds.Length; i++) + { + yield return seconds[i]; + } + } + + public static IObservable Concat(params IObservable[] sources) + { + if (sources == null) throw new ArgumentNullException("sources"); + + return new ConcatObservable(sources); + } + + public static IObservable Concat(this IEnumerable> sources) + { + if (sources == null) throw new ArgumentNullException("sources"); + + return new ConcatObservable(sources); + } + + public static IObservable Concat(this IObservable> sources) + { + return sources.Merge(maxConcurrent: 1); + } + + public static IObservable Concat(this IObservable first, params IObservable[] seconds) + { + if (first == null) throw new ArgumentNullException("first"); + if (seconds == null) throw new ArgumentNullException("seconds"); + + var concat = first as ConcatObservable; + if (concat != null) + { + return concat.Combine(seconds); + } + + return Concat(CombineSources(first, seconds)); + } + + public static IObservable Merge(this IEnumerable> sources) + { + return Merge(sources, Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + public static IObservable Merge(this IEnumerable> sources, IScheduler scheduler) + { + return new MergeObservable(sources.ToObservable(scheduler), scheduler == Scheduler.CurrentThread); + } + + public static IObservable Merge(this IEnumerable> sources, int maxConcurrent) + { + return Merge(sources, maxConcurrent, Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + public static IObservable Merge(this IEnumerable> sources, int maxConcurrent, IScheduler scheduler) + { + return new MergeObservable(sources.ToObservable(scheduler), maxConcurrent, scheduler == Scheduler.CurrentThread); + } + + public static IObservable Merge(params IObservable[] sources) + { + return Merge(Scheduler.DefaultSchedulers.ConstantTimeOperations, sources); + } + + public static IObservable Merge(IScheduler scheduler, params IObservable[] sources) + { + return new MergeObservable(sources.ToObservable(scheduler), scheduler == Scheduler.CurrentThread); + } + + public static IObservable Merge(this IObservable first, params IObservable[] seconds) + { + return Merge(CombineSources(first, seconds)); + } + + public static IObservable Merge(this IObservable first, IObservable second, IScheduler scheduler) + { + return Merge(scheduler, new[] { first, second }); + } + + public static IObservable Merge(this IObservable> sources) + { + return new MergeObservable(sources, false); + } + + public static IObservable Merge(this IObservable> sources, int maxConcurrent) + { + return new MergeObservable(sources, maxConcurrent, false); + } + + public static IObservable Zip(this IObservable left, IObservable right, Func selector) + { + return new ZipObservable(left, right, selector); + } + + public static IObservable> Zip(this IEnumerable> sources) + { + return Zip(sources.ToArray()); + } + + public static IObservable> Zip(params IObservable[] sources) + { + return new ZipObservable(sources); + } + + public static IObservable Zip(this IObservable source1, IObservable source2, IObservable source3, ZipFunc resultSelector) + { + return new ZipObservable(source1, source2, source3, resultSelector); + } + + public static IObservable Zip(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, ZipFunc resultSelector) + { + return new ZipObservable(source1, source2, source3, source4, resultSelector); + } + + public static IObservable Zip(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, ZipFunc resultSelector) + { + return new ZipObservable(source1, source2, source3, source4, source5, resultSelector); + } + + public static IObservable Zip(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, ZipFunc resultSelector) + { + return new ZipObservable(source1, source2, source3, source4, source5, source6, resultSelector); + } + + public static IObservable Zip(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, ZipFunc resultSelector) + { + return new ZipObservable(source1, source2, source3, source4, source5, source6, source7, resultSelector); + } + + public static IObservable CombineLatest(this IObservable left, IObservable right, Func selector) + { + return new CombineLatestObservable(left, right, selector); + } + + public static IObservable> CombineLatest(this IEnumerable> sources) + { + return CombineLatest(sources.ToArray()); + } + + public static IObservable> CombineLatest(params IObservable[] sources) + { + return new CombineLatestObservable(sources); + } + + public static IObservable CombineLatest(this IObservable source1, IObservable source2, IObservable source3, CombineLatestFunc resultSelector) + { + return new CombineLatestObservable(source1, source2, source3, resultSelector); + } + + public static IObservable CombineLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, CombineLatestFunc resultSelector) + { + return new CombineLatestObservable(source1, source2, source3, source4, resultSelector); + } + + public static IObservable CombineLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, CombineLatestFunc resultSelector) + { + return new CombineLatestObservable(source1, source2, source3, source4, source5, resultSelector); + } + + public static IObservable CombineLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, CombineLatestFunc resultSelector) + { + return new CombineLatestObservable(source1, source2, source3, source4, source5, source6, resultSelector); + } + + public static IObservable CombineLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, CombineLatestFunc resultSelector) + { + return new CombineLatestObservable(source1, source2, source3, source4, source5, source6, source7, resultSelector); + } + + public static IObservable ZipLatest(this IObservable left, IObservable right, Func selector) + { + return new ZipLatestObservable(left, right, selector); + } + + public static IObservable> ZipLatest(this IEnumerable> sources) + { + return ZipLatest(sources.ToArray()); + } + + public static IObservable> ZipLatest(params IObservable[] sources) + { + return new ZipLatestObservable(sources); + } + + public static IObservable ZipLatest(this IObservable source1, IObservable source2, IObservable source3, ZipLatestFunc resultSelector) + { + return new ZipLatestObservable(source1, source2, source3, resultSelector); + } + + public static IObservable ZipLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, ZipLatestFunc resultSelector) + { + return new ZipLatestObservable(source1, source2, source3, source4, resultSelector); + } + + public static IObservable ZipLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, ZipLatestFunc resultSelector) + { + return new ZipLatestObservable(source1, source2, source3, source4, source5, resultSelector); + } + + public static IObservable ZipLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, ZipLatestFunc resultSelector) + { + return new ZipLatestObservable(source1, source2, source3, source4, source5, source6, resultSelector); + } + + public static IObservable ZipLatest(this IObservable source1, IObservable source2, IObservable source3, IObservable source4, IObservable source5, IObservable source6, IObservable source7, ZipLatestFunc resultSelector) + { + return new ZipLatestObservable(source1, source2, source3, source4, source5, source6, source7, resultSelector); + } + + public static IObservable Switch(this IObservable> sources) + { + return new SwitchObservable(sources); + } + + public static IObservable WithLatestFrom(this IObservable left, IObservable right, Func selector) + { + return new WithLatestFromObservable(left, right, selector); + } + + /// + /// Specialized for single async operations like Task.WhenAll, Zip.Take(1). + /// If sequence is empty, return T[0] array. + /// + public static IObservable WhenAll(params IObservable[] sources) + { + if (sources.Length == 0) return Observable.Return(new T[0]); + + return new WhenAllObservable(sources); + } + + /// + /// Specialized for single async operations like Task.WhenAll, Zip.Take(1). + /// + public static IObservable WhenAll(params IObservable[] sources) + { + if (sources.Length == 0) return Observable.ReturnUnit(); + + return new WhenAllObservable(sources); + } + + /// + /// Specialized for single async operations like Task.WhenAll, Zip.Take(1). + /// If sequence is empty, return T[0] array. + /// + public static IObservable WhenAll(this IEnumerable> sources) + { + var array = sources as IObservable[]; + if (array != null) return WhenAll(array); + + return new WhenAllObservable(sources); + } + + /// + /// Specialized for single async operations like Task.WhenAll, Zip.Take(1). + /// + public static IObservable WhenAll(this IEnumerable> sources) + { + var array = sources as IObservable[]; + if (array != null) return WhenAll(array); + + return new WhenAllObservable(sources); + } + + public static IObservable StartWith(this IObservable source, T value) + { + return new StartWithObservable(source, value); + } + + public static IObservable StartWith(this IObservable source, Func valueFactory) + { + return new StartWithObservable(source, valueFactory); + } + + public static IObservable StartWith(this IObservable source, params T[] values) + { + return StartWith(source, Scheduler.DefaultSchedulers.ConstantTimeOperations, values); + } + + public static IObservable StartWith(this IObservable source, IEnumerable values) + { + return StartWith(source, Scheduler.DefaultSchedulers.ConstantTimeOperations, values); + } + + public static IObservable StartWith(this IObservable source, IScheduler scheduler, T value) + { + return Observable.Return(value, scheduler).Concat(source); + } + + public static IObservable StartWith(this IObservable source, IScheduler scheduler, IEnumerable values) + { + var array = values as T[]; + if (array == null) + { + array = values.ToArray(); + } + + return StartWith(source, scheduler, array); + } + + public static IObservable StartWith(this IObservable source, IScheduler scheduler, params T[] values) + { + return values.ToObservable(scheduler).Concat(source); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs.meta new file mode 100644 index 00000000..dbce836a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concatenate.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 18c56bbfaaeedf445874f4246d42b509 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs new file mode 100644 index 00000000..6519c138 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IObservable Synchronize(this IObservable source) + { + return new SynchronizeObservable(source, new object()); + } + + public static IObservable Synchronize(this IObservable source, object gate) + { + return new SynchronizeObservable(source, gate); + } + + public static IObservable ObserveOn(this IObservable source, IScheduler scheduler) + { + return new ObserveOnObservable(source, scheduler); + } + + public static IObservable SubscribeOn(this IObservable source, IScheduler scheduler) + { + return new SubscribeOnObservable(source, scheduler); + } + + public static IObservable DelaySubscription(this IObservable source, TimeSpan dueTime) + { + return new DelaySubscriptionObservable(source, dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable DelaySubscription(this IObservable source, TimeSpan dueTime, IScheduler scheduler) + { + return new DelaySubscriptionObservable(source, dueTime, scheduler); + } + + public static IObservable DelaySubscription(this IObservable source, DateTimeOffset dueTime) + { + return new DelaySubscriptionObservable(source, dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable DelaySubscription(this IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + { + return new DelaySubscriptionObservable(source, dueTime, scheduler); + } + + public static IObservable Amb(params IObservable[] sources) + { + return Amb((IEnumerable>)sources); + } + + public static IObservable Amb(IEnumerable> sources) + { + var result = Observable.Never(); + foreach (var item in sources) + { + var second = item; + result = result.Amb(second); + } + return result; + } + + public static IObservable Amb(this IObservable source, IObservable second) + { + return new AmbObservable(source, second); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs.meta new file mode 100644 index 00000000..59c286b8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Concurrency.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a31d38ad13dc4644180647afc28c6045 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs new file mode 100644 index 00000000..1bd8a077 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IObservable AsObservable(this IObservable source) + { + if (source == null) throw new ArgumentNullException("source"); + + // optimize, don't double wrap + if (source is UniRx.Operators.AsObservableObservable) + { + return source; + } + + return new AsObservableObservable(source); + } + + public static IObservable ToObservable(this IEnumerable source) + { + return ToObservable(source, Scheduler.DefaultSchedulers.Iteration); + } + + public static IObservable ToObservable(this IEnumerable source, IScheduler scheduler) + { + return new ToObservableObservable(source, scheduler); + } + + public static IObservable Cast(this IObservable source) + { + return new CastObservable(source); + } + + /// + /// witness is for type inference. + /// + public static IObservable Cast(this IObservable source, TResult witness) + { + return new CastObservable(source); + } + + public static IObservable OfType(this IObservable source) + { + return new OfTypeObservable(source); + } + + /// + /// witness is for type inference. + /// + public static IObservable OfType(this IObservable source, TResult witness) + { + return new OfTypeObservable(source); + } + + /// + /// Converting .Select(_ => Unit.Default) sequence. + /// + public static IObservable AsUnitObservable(this IObservable source) + { + return new AsUnitObservableObservable(source); + } + + /// + /// Same as LastOrDefault().AsUnitObservable(). + /// + public static IObservable AsSingleUnitObservable(this IObservable source) + { + return new AsSingleUnitObservableObservable(source); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs.meta new file mode 100644 index 00000000..b8533d06 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Conversions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e32bd7bbf28014b4ab2873cc8de3dea9 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs new file mode 100644 index 00000000..b4973cb9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + /// + /// Create anonymous observable. Observer has exception durability. This is recommended for make operator and event like generator. + /// + public static IObservable Create(Func, IDisposable> subscribe) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateObservable(subscribe); + } + + /// + /// Create anonymous observable. Observer has exception durability. This is recommended for make operator and event like generator(HotObservable). + /// + public static IObservable Create(Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateObservable(subscribe, isRequiredSubscribeOnCurrentThread); + } + + /// + /// Create anonymous observable. Observer has exception durability. This is recommended for make operator and event like generator. + /// + public static IObservable CreateWithState(TState state, Func, IDisposable> subscribe) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateObservable(state, subscribe); + } + + /// + /// Create anonymous observable. Observer has exception durability. This is recommended for make operator and event like generator(HotObservable). + /// + public static IObservable CreateWithState(TState state, Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateObservable(state, subscribe, isRequiredSubscribeOnCurrentThread); + } + + /// + /// Create anonymous observable. Safe means auto detach when error raised in onNext pipeline. This is recommended for make generator (ColdObservable). + /// + public static IObservable CreateSafe(Func, IDisposable> subscribe) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateSafeObservable(subscribe); + } + + /// + /// Create anonymous observable. Safe means auto detach when error raised in onNext pipeline. This is recommended for make generator (ColdObservable). + /// + public static IObservable CreateSafe(Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + { + if (subscribe == null) throw new ArgumentNullException("subscribe"); + + return new CreateSafeObservable(subscribe, isRequiredSubscribeOnCurrentThread); + } + + /// + /// Empty Observable. Returns only OnCompleted. + /// + public static IObservable Empty() + { + return Empty(Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + /// + /// Empty Observable. Returns only OnCompleted on specified scheduler. + /// + public static IObservable Empty(IScheduler scheduler) + { + if (scheduler == Scheduler.Immediate) + { + return ImmutableEmptyObservable.Instance; + } + else + { + return new EmptyObservable(scheduler); + } + } + + /// + /// Empty Observable. Returns only OnCompleted. witness is for type inference. + /// + public static IObservable Empty(T witness) + { + return Empty(Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + /// + /// Empty Observable. Returns only OnCompleted on specified scheduler. witness is for type inference. + /// + public static IObservable Empty(IScheduler scheduler, T witness) + { + return Empty(scheduler); + } + + /// + /// Non-Terminating Observable. It's no returns, never finish. + /// + public static IObservable Never() + { + return ImmutableNeverObservable.Instance; + } + + /// + /// Non-Terminating Observable. It's no returns, never finish. witness is for type inference. + /// + public static IObservable Never(T witness) + { + return ImmutableNeverObservable.Instance; + } + + /// + /// Return single sequence Immediately. + /// + public static IObservable Return(T value) + { + return Return(value, Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + /// + /// Return single sequence on specified scheduler. + /// + public static IObservable Return(T value, IScheduler scheduler) + { + if (scheduler == Scheduler.Immediate) + { + return new ImmediateReturnObservable(value); + } + else + { + return new ReturnObservable(value, scheduler); + } + } + + /// + /// Return single sequence Immediately, optimized for Unit(no allocate memory). + /// + public static IObservable Return(Unit value) + { + return ImmutableReturnUnitObservable.Instance; + } + + /// + /// Return single sequence Immediately, optimized for Boolean(no allocate memory). + /// + public static IObservable Return(bool value) + { + return (value == true) + ? (IObservable)ImmutableReturnTrueObservable.Instance + : (IObservable)ImmutableReturnFalseObservable.Instance; + } + + /// + /// Return single sequence Immediately, optimized for Int32. + /// + public static IObservable Return(int value) + { + return ImmutableReturnInt32Observable.GetInt32Observable(value); + } + + /// + /// Same as Observable.Return(Unit.Default); but no allocate memory. + /// + public static IObservable ReturnUnit() + { + return ImmutableReturnUnitObservable.Instance; + } + + /// + /// Empty Observable. Returns only onError. + /// + public static IObservable Throw(Exception error) + { + return Throw(error, Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + /// + /// Empty Observable. Returns only onError. witness if for Type inference. + /// + public static IObservable Throw(Exception error, T witness) + { + return Throw(error, Scheduler.DefaultSchedulers.ConstantTimeOperations); + } + + /// + /// Empty Observable. Returns only onError on specified scheduler. + /// + public static IObservable Throw(Exception error, IScheduler scheduler) + { + return new ThrowObservable(error, scheduler); + } + + /// + /// Empty Observable. Returns only onError on specified scheduler. witness if for Type inference. + /// + public static IObservable Throw(Exception error, IScheduler scheduler, T witness) + { + return Throw(error, scheduler); + } + + public static IObservable Range(int start, int count) + { + return Range(start, count, Scheduler.DefaultSchedulers.Iteration); + } + + public static IObservable Range(int start, int count, IScheduler scheduler) + { + return new RangeObservable(start, count, scheduler); + } + + public static IObservable Repeat(T value) + { + return Repeat(value, Scheduler.DefaultSchedulers.Iteration); + } + + public static IObservable Repeat(T value, IScheduler scheduler) + { + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + return new RepeatObservable(value, null, scheduler); + } + + public static IObservable Repeat(T value, int repeatCount) + { + return Repeat(value, repeatCount, Scheduler.DefaultSchedulers.Iteration); + } + + public static IObservable Repeat(T value, int repeatCount, IScheduler scheduler) + { + if (repeatCount < 0) throw new ArgumentOutOfRangeException("repeatCount"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + return new RepeatObservable(value, repeatCount, scheduler); + } + + public static IObservable Repeat(this IObservable source) + { + return RepeatInfinite(source).Concat(); + } + + static IEnumerable> RepeatInfinite(IObservable source) + { + while (true) + { + yield return source; + } + } + + /// + /// Same as Repeat() but if arriving contiguous "OnComplete" Repeat stops. + /// + public static IObservable RepeatSafe(this IObservable source) + { + return new RepeatSafeObservable(RepeatInfinite(source), source.IsRequiredSubscribeOnCurrentThread()); + } + + public static IObservable Defer(Func> observableFactory) + { + return new DeferObservable(observableFactory); + } + + public static IObservable Start(Func function) + { + return new StartObservable(function, null, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static IObservable Start(Func function, TimeSpan timeSpan) + { + return new StartObservable(function, timeSpan, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static IObservable Start(Func function, IScheduler scheduler) + { + return new StartObservable(function, null, scheduler); + } + + public static IObservable Start(Func function, TimeSpan timeSpan, IScheduler scheduler) + { + return new StartObservable(function, timeSpan, scheduler); + } + + public static IObservable Start(Action action) + { + return new StartObservable(action, null, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static IObservable Start(Action action, TimeSpan timeSpan) + { + return new StartObservable(action, timeSpan, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static IObservable Start(Action action, IScheduler scheduler) + { + return new StartObservable(action, null, scheduler); + } + + public static IObservable Start(Action action, TimeSpan timeSpan, IScheduler scheduler) + { + return new StartObservable(action, timeSpan, scheduler); + } + + public static Func> ToAsync(Func function) + { + return ToAsync(function, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static Func> ToAsync(Func function, IScheduler scheduler) + { + return () => + { + var subject = new AsyncSubject(); + + scheduler.Schedule(() => + { + var result = default(T); + try + { + result = function(); + } + catch (Exception exception) + { + subject.OnError(exception); + return; + } + subject.OnNext(result); + subject.OnCompleted(); + }); + + return subject.AsObservable(); + }; + } + + public static Func> ToAsync(Action action) + { + return ToAsync(action, Scheduler.DefaultSchedulers.AsyncConversions); + } + + public static Func> ToAsync(Action action, IScheduler scheduler) + { + return () => + { + var subject = new AsyncSubject(); + + scheduler.Schedule(() => + { + try + { + action(); + } + catch (Exception exception) + { + subject.OnError(exception); + return; + } + subject.OnNext(Unit.Default); + subject.OnCompleted(); + }); + + return subject.AsObservable(); + }; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs.meta new file mode 100644 index 00000000..cb9c1c8c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Creation.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e63036d2dba75f64382beed512fd086c +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs new file mode 100644 index 00000000..4e77cb1d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IObservable Finally(this IObservable source, Action finallyAction) + { + return new FinallyObservable(source, finallyAction); + } + + public static IObservable Catch(this IObservable source, Func> errorHandler) + where TException : Exception + { + return new CatchObservable(source, errorHandler); + } + + public static IObservable Catch(this IEnumerable> sources) + { + return new CatchObservable(sources); + } + + /// Catch exception and return Observable.Empty. + public static IObservable CatchIgnore(this IObservable source) + { + return source.Catch(Stubs.CatchIgnore); + } + + /// Catch exception and return Observable.Empty. + public static IObservable CatchIgnore(this IObservable source, Action errorAction) + where TException : Exception + { + var result = source.Catch((TException ex) => + { + errorAction(ex); + return Observable.Empty(); + }); + return result; + } + + public static IObservable Retry(this IObservable source) + { + return RepeatInfinite(source).Catch(); + } + + public static IObservable Retry(this IObservable source, int retryCount) + { + return System.Linq.Enumerable.Repeat(source, retryCount).Catch(); + } + + /// + /// Repeats the source observable sequence until it successfully terminates. + /// This is same as Retry(). + /// + public static IObservable OnErrorRetry( + this IObservable source) + { + var result = source.Retry(); + return result; + } + + /// + /// When catched exception, do onError action and repeat observable sequence. + /// + public static IObservable OnErrorRetry( + this IObservable source, Action onError) + where TException : Exception + { + return source.OnErrorRetry(onError, TimeSpan.Zero); + } + + /// + /// When catched exception, do onError action and repeat observable sequence after delay time. + /// + public static IObservable OnErrorRetry( + this IObservable source, Action onError, TimeSpan delay) + where TException : Exception + { + return source.OnErrorRetry(onError, int.MaxValue, delay); + } + + /// + /// When catched exception, do onError action and repeat observable sequence during within retryCount. + /// + public static IObservable OnErrorRetry( + this IObservable source, Action onError, int retryCount) + where TException : Exception + { + return source.OnErrorRetry(onError, retryCount, TimeSpan.Zero); + } + + /// + /// When catched exception, do onError action and repeat observable sequence after delay time during within retryCount. + /// + public static IObservable OnErrorRetry( + this IObservable source, Action onError, int retryCount, TimeSpan delay) + where TException : Exception + { + return source.OnErrorRetry(onError, retryCount, delay, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + /// + /// When catched exception, do onError action and repeat observable sequence after delay time(work on delayScheduler) during within retryCount. + /// + public static IObservable OnErrorRetry( + this IObservable source, Action onError, int retryCount, TimeSpan delay, IScheduler delayScheduler) + where TException : Exception + { + var result = Observable.Defer(() => + { + var dueTime = (delay.Ticks < 0) ? TimeSpan.Zero : delay; + var count = 0; + + IObservable self = null; + self = source.Catch((TException ex) => + { + onError(ex); + + return (++count < retryCount) + ? (dueTime == TimeSpan.Zero) + ? self.SubscribeOn(Scheduler.CurrentThread) + : self.DelaySubscription(dueTime, delayScheduler).SubscribeOn(Scheduler.CurrentThread) + : Observable.Throw(ex); + }); + return self; + }); + + return result; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs.meta new file mode 100644 index 00000000..c7c215c8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.ErrorHandling.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f40cab35efe24e6448ac8455bc7a4eb9 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs new file mode 100644 index 00000000..dc339188 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs @@ -0,0 +1,34 @@ +using System; +using UniRx.Operators; + +namespace UniRx +{ + public static partial class Observable + { + public static IObservable> FromEventPattern(Func, TDelegate> conversion, Action addHandler, Action removeHandler) + where TEventArgs : EventArgs + { + return new FromEventPatternObservable(conversion, addHandler, removeHandler); + } + + public static IObservable FromEvent(Func conversion, Action addHandler, Action removeHandler) + { + return new FromEventObservable(conversion, addHandler, removeHandler); + } + + public static IObservable FromEvent(Func, TDelegate> conversion, Action addHandler, Action removeHandler) + { + return new FromEventObservable(conversion, addHandler, removeHandler); + } + + public static IObservable FromEvent(Action addHandler, Action removeHandler) + { + return new FromEventObservable(addHandler, removeHandler); + } + + public static IObservable FromEvent(Action> addHandler, Action> removeHandler) + { + return new FromEventObservable_(addHandler, removeHandler); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs.meta new file mode 100644 index 00000000..d748fb9c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Events.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e591aafff0492c94590cf9702f6c408f +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs new file mode 100644 index 00000000..303387bb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs @@ -0,0 +1,127 @@ +using System; + +namespace UniRx +{ + public static partial class Observable + { + public static Func> FromAsyncPattern(Func begin, Func end) + { + return () => + { + var subject = new AsyncSubject(); + try + { + begin(iar => + { + TResult result; + try + { + result = end(iar); + } + catch (Exception exception) + { + subject.OnError(exception); + return; + } + subject.OnNext(result); + subject.OnCompleted(); + }, null); + } + catch (Exception exception) + { + return Observable.Throw(exception, Scheduler.DefaultSchedulers.AsyncConversions); + } + return subject.AsObservable(); + }; + } + + public static Func> FromAsyncPattern(Func begin, Func end) + { + return x => + { + var subject = new AsyncSubject(); + try + { + begin(x, iar => + { + TResult result; + try + { + result = end(iar); + } + catch (Exception exception) + { + subject.OnError(exception); + return; + } + subject.OnNext(result); + subject.OnCompleted(); + }, null); + } + catch (Exception exception) + { + return Observable.Throw(exception, Scheduler.DefaultSchedulers.AsyncConversions); + } + return subject.AsObservable(); + }; + } + + public static Func> FromAsyncPattern(Func begin, Func end) + { + return (x, y) => + { + var subject = new AsyncSubject(); + try + { + begin(x, y, iar => + { + TResult result; + try + { + result = end(iar); + } + catch (Exception exception) + { + subject.OnError(exception); + return; + } + subject.OnNext(result); + subject.OnCompleted(); + }, null); + } + catch (Exception exception) + { + return Observable.Throw(exception, Scheduler.DefaultSchedulers.AsyncConversions); + } + return subject.AsObservable(); + }; + } + + public static Func> FromAsyncPattern(Func begin, Action end) + { + return FromAsyncPattern(begin, iar => + { + end(iar); + return Unit.Default; + }); + } + + public static Func> FromAsyncPattern(Func begin, Action end) + { + return FromAsyncPattern(begin, iar => + { + end(iar); + return Unit.Default; + }); + } + + public static Func> FromAsyncPattern(Func begin, Action end) + { + return FromAsyncPattern(begin, iar => + { + end(iar); + return Unit.Default; + }); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs.meta new file mode 100644 index 00000000..37a8699e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.FromAsync.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 601f5bb7bb302a14cb46df717729b8c7 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs new file mode 100644 index 00000000..ad4c6d89 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx +{ + public static partial class Observable + { + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs.meta new file mode 100644 index 00000000..077551b7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Joins.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dd92425c6c6dec24e9e52677cbc36aa0 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs new file mode 100644 index 00000000..daab133a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs @@ -0,0 +1,327 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UniRx.InternalUtil; +using UniRx.Operators; + +namespace UniRx +{ + // Take, Skip, etc.. + public static partial class Observable + { + public static IObservable Take(this IObservable source, int count) + { + if (source == null) throw new ArgumentNullException("source"); + if (count < 0) throw new ArgumentOutOfRangeException("count"); + + if (count == 0) return Empty(); + + // optimize .Take(count).Take(count) + var take = source as TakeObservable; + if (take != null && take.scheduler == null) + { + return take.Combine(count); + } + + return new TakeObservable(source, count); + } + + public static IObservable Take(this IObservable source, TimeSpan duration) + { + return Take(source, duration, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Take(this IObservable source, TimeSpan duration, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // optimize .Take(duration).Take(duration) + var take = source as TakeObservable; + if (take != null && take.scheduler == scheduler) + { + return take.Combine(duration); + } + + return new TakeObservable(source, duration, scheduler); + } + + public static IObservable TakeWhile(this IObservable source, Func predicate) + { + return new TakeWhileObservable(source, predicate); + } + + public static IObservable TakeWhile(this IObservable source, Func predicate) + { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + + return new TakeWhileObservable(source, predicate); + } + + public static IObservable TakeUntil(this IObservable source, IObservable other) + { + if (source == null) throw new ArgumentNullException("source"); + if (other == null) throw new ArgumentNullException("other"); + + return new TakeUntilObservable(source, other); + } + + public static IObservable TakeLast(this IObservable source, int count) + { + if (source == null) throw new ArgumentNullException("source"); + if (count < 0) throw new ArgumentOutOfRangeException("count"); + + return new TakeLastObservable(source, count); + } + + public static IObservable TakeLast(this IObservable source, TimeSpan duration) + { + return TakeLast(source, duration, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable TakeLast(this IObservable source, TimeSpan duration, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + + return new TakeLastObservable(source, duration, scheduler); + } + + public static IObservable Skip(this IObservable source, int count) + { + if (source == null) throw new ArgumentNullException("source"); + if (count < 0) throw new ArgumentOutOfRangeException("count"); + + // optimize .Skip(count).Skip(count) + var skip = source as SkipObservable; + if (skip != null && skip.scheduler == null) + { + return skip.Combine(count); + } + + return new SkipObservable(source, count); + } + + public static IObservable Skip(this IObservable source, TimeSpan duration) + { + return Skip(source, duration, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Skip(this IObservable source, TimeSpan duration, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + // optimize .Skip(duration).Skip(duration) + var skip = source as SkipObservable; + if (skip != null && skip.scheduler == scheduler) + { + return skip.Combine(duration); + } + + return new SkipObservable(source, duration, scheduler); + } + + public static IObservable SkipWhile(this IObservable source, Func predicate) + { + return new SkipWhileObservable(source, predicate); + } + + public static IObservable SkipWhile(this IObservable source, Func predicate) + { + if (source == null) throw new ArgumentNullException("source"); + if (predicate == null) throw new ArgumentNullException("predicate"); + + return new SkipWhileObservable(source, predicate); + } + + public static IObservable SkipUntil(this IObservable source, IObservable other) + { + return new SkipUntilObservable(source, other); + } + + public static IObservable> Buffer(this IObservable source, int count) + { + if (source == null) throw new ArgumentNullException("source"); + if (count <= 0) throw new ArgumentOutOfRangeException("count <= 0"); + + return new BufferObservable(source, count, 0); + } + + public static IObservable> Buffer(this IObservable source, int count, int skip) + { + if (source == null) throw new ArgumentNullException("source"); + if (count <= 0) throw new ArgumentOutOfRangeException("count <= 0"); + if (skip <= 0) throw new ArgumentOutOfRangeException("skip <= 0"); + + return new BufferObservable(source, count, skip); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan) + { + return Buffer(source, timeSpan, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + + return new BufferObservable(source, timeSpan, timeSpan, scheduler); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan, int count) + { + return Buffer(source, timeSpan, count, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + if (count <= 0) throw new ArgumentOutOfRangeException("count <= 0"); + + return new BufferObservable(source, timeSpan, count, scheduler); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan, TimeSpan timeShift) + { + return new BufferObservable(source, timeSpan, timeShift, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable> Buffer(this IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) + { + if (source == null) throw new ArgumentNullException("source"); + + return new BufferObservable(source, timeSpan, timeShift, scheduler); + } + + public static IObservable> Buffer(this IObservable source, IObservable windowBoundaries) + { + return new BufferObservable(source, windowBoundaries); + } + + /// Projects old and new element of a sequence into a new form. + public static IObservable> Pairwise(this IObservable source) + { + return new PairwiseObservable(source); + } + + /// Projects old and new element of a sequence into a new form. + public static IObservable Pairwise(this IObservable source, Func selector) + { + return new PairwiseObservable(source, selector); + } + + // first, last, single + + public static IObservable Last(this IObservable source) + { + return new LastObservable(source, false); + } + public static IObservable Last(this IObservable source, Func predicate) + { + return new LastObservable(source, predicate, false); + } + + public static IObservable LastOrDefault(this IObservable source) + { + return new LastObservable(source, true); + } + + public static IObservable LastOrDefault(this IObservable source, Func predicate) + { + return new LastObservable(source, predicate, true); + } + + public static IObservable First(this IObservable source) + { + return new FirstObservable(source, false); + } + public static IObservable First(this IObservable source, Func predicate) + { + return new FirstObservable(source, predicate, false); + } + + public static IObservable FirstOrDefault(this IObservable source) + { + return new FirstObservable(source, true); + } + + public static IObservable FirstOrDefault(this IObservable source, Func predicate) + { + return new FirstObservable(source, predicate, true); + } + + public static IObservable Single(this IObservable source) + { + return new SingleObservable(source, false); + } + public static IObservable Single(this IObservable source, Func predicate) + { + return new SingleObservable(source, predicate, false); + } + + public static IObservable SingleOrDefault(this IObservable source) + { + return new SingleObservable(source, true); + } + + public static IObservable SingleOrDefault(this IObservable source, Func predicate) + { + return new SingleObservable(source, predicate, true); + } + + // Grouping + + public static IObservable> GroupBy(this IObservable source, Func keySelector) + { + return GroupBy(source, keySelector, Stubs.Identity); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, IEqualityComparer comparer) + { + return GroupBy(source, keySelector, Stubs.Identity, comparer); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, Func elementSelector) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return GroupBy(source, keySelector, elementSelector, comparer); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, Func elementSelector, IEqualityComparer comparer) + { + return new GroupByObservable(source, keySelector, elementSelector, null, comparer); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, int capacity) + { + return GroupBy(source, keySelector, Stubs.Identity, capacity); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, int capacity, IEqualityComparer comparer) + { + return GroupBy(source, keySelector, Stubs.Identity, capacity, comparer); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, Func elementSelector, int capacity) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return GroupBy(source, keySelector, elementSelector, capacity, comparer); + } + + public static IObservable> GroupBy(this IObservable source, Func keySelector, Func elementSelector, int capacity, IEqualityComparer comparer) + { + return new GroupByObservable(source, keySelector, elementSelector, capacity, comparer); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs.meta new file mode 100644 index 00000000..493ae430 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Paging.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4c9428bf00006d408fcfe4c514ee798 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs new file mode 100644 index 00000000..24e58ed2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx +{ + // Timer, Interval, etc... + public static partial class Observable + { + public static IObservable Interval(TimeSpan period) + { + return new TimerObservable(period, period, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Interval(TimeSpan period, IScheduler scheduler) + { + return new TimerObservable(period, period, scheduler); + } + + public static IObservable Timer(TimeSpan dueTime) + { + return new TimerObservable(dueTime, null, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timer(DateTimeOffset dueTime) + { + return new TimerObservable(dueTime, null, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timer(TimeSpan dueTime, TimeSpan period) + { + return new TimerObservable(dueTime, period, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timer(DateTimeOffset dueTime, TimeSpan period) + { + return new TimerObservable(dueTime, period, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timer(TimeSpan dueTime, IScheduler scheduler) + { + return new TimerObservable(dueTime, null, scheduler); + } + + public static IObservable Timer(DateTimeOffset dueTime, IScheduler scheduler) + { + return new TimerObservable(dueTime, null, scheduler); + } + + public static IObservable Timer(TimeSpan dueTime, TimeSpan period, IScheduler scheduler) + { + return new TimerObservable(dueTime, period, scheduler); + } + + public static IObservable Timer(DateTimeOffset dueTime, TimeSpan period, IScheduler scheduler) + { + return new TimerObservable(dueTime, period, scheduler); + } + + public static IObservable> Timestamp(this IObservable source) + { + return Timestamp(source, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable> Timestamp(this IObservable source, IScheduler scheduler) + { + return new TimestampObservable(source, scheduler); + } + + public static IObservable> TimeInterval(this IObservable source) + { + return TimeInterval(source, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable> TimeInterval(this IObservable source, IScheduler scheduler) + { + return new UniRx.Operators.TimeIntervalObservable(source, scheduler); + } + + public static IObservable Delay(this IObservable source, TimeSpan dueTime) + { + return source.Delay(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Delay(this IObservable source, TimeSpan dueTime, IScheduler scheduler) + { + return new DelayObservable(source, dueTime, scheduler); + } + + public static IObservable Sample(this IObservable source, TimeSpan interval) + { + return source.Sample(interval, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Sample(this IObservable source, TimeSpan interval, IScheduler scheduler) + { + return new SampleObservable(source, interval, scheduler); + } + + public static IObservable Throttle(this IObservable source, TimeSpan dueTime) + { + return source.Throttle(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Throttle(this IObservable source, TimeSpan dueTime, IScheduler scheduler) + { + return new ThrottleObservable(source, dueTime, scheduler); + } + + public static IObservable ThrottleFirst(this IObservable source, TimeSpan dueTime) + { + return source.ThrottleFirst(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable ThrottleFirst(this IObservable source, TimeSpan dueTime, IScheduler scheduler) + { + return new ThrottleFirstObservable(source, dueTime, scheduler); + } + + public static IObservable Timeout(this IObservable source, TimeSpan dueTime) + { + return source.Timeout(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timeout(this IObservable source, TimeSpan dueTime, IScheduler scheduler) + { + return new TimeoutObservable(source, dueTime, scheduler); + } + + public static IObservable Timeout(this IObservable source, DateTimeOffset dueTime) + { + return source.Timeout(dueTime, Scheduler.DefaultSchedulers.TimeBasedOperations); + } + + public static IObservable Timeout(this IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + { + return new TimeoutObservable(source, dueTime, scheduler); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs.meta new file mode 100644 index 00000000..906b97ac --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.Time.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7da89fcf95f5c364ca62bbb874005d32 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs new file mode 100644 index 00000000..a2dc67b9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using UniRx.InternalUtil; +using UniRx.Operators; + +namespace UniRx +{ + // Standard Query Operators + + // onNext implementation guide. enclose otherFunc but onNext is not catch. + // try{ otherFunc(); } catch { onError() } + // onNext(); + + public static partial class Observable + { + static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, -1); // from .NET 4.5 + + public static IObservable Select(this IObservable source, Func selector) + { + // sometimes cause "which no ahead of time (AOT) code was generated." on IL2CPP... + + //var select = source as ISelect; + //if (select != null) + //{ + // return select.CombineSelector(selector); + //} + + // optimized path + var whereObservable = source as UniRx.Operators.WhereObservable; + if (whereObservable != null) + { + return whereObservable.CombineSelector(selector); + } + + return new SelectObservable(source, selector); + } + + public static IObservable Select(this IObservable source, Func selector) + { + return new SelectObservable(source, selector); + } + + public static IObservable Where(this IObservable source, Func predicate) + { + // optimized path + var whereObservable = source as UniRx.Operators.WhereObservable; + if (whereObservable != null) + { + return whereObservable.CombinePredicate(predicate); + } + + var selectObservable = source as UniRx.Operators.ISelect; + if (selectObservable != null) + { + return selectObservable.CombinePredicate(predicate); + } + + return new WhereObservable(source, predicate); + } + + public static IObservable Where(this IObservable source, Func predicate) + { + return new WhereObservable(source, predicate); + } + + /// + /// Lightweight SelectMany for Single Async Operation. + /// + public static IObservable ContinueWith(this IObservable source, IObservable other) + { + return ContinueWith(source, _ => other); + } + + /// + /// Lightweight SelectMany for Single Async Operation. + /// + public static IObservable ContinueWith(this IObservable source, Func> selector) + { + return new ContinueWithObservable(source, selector); + } + + public static IObservable SelectMany(this IObservable source, IObservable other) + { + return SelectMany(source, _ => other); + } + + public static IObservable SelectMany(this IObservable source, Func> selector) + { + return new SelectManyObservable(source, selector); + } + + public static IObservable SelectMany(this IObservable source, Func> selector) + { + return new SelectManyObservable(source, selector); + } + + public static IObservable SelectMany(this IObservable source, Func> collectionSelector, Func resultSelector) + { + return new SelectManyObservable(source, collectionSelector, resultSelector); + } + + public static IObservable SelectMany(this IObservable source, Func> collectionSelector, Func resultSelector) + { + return new SelectManyObservable(source, collectionSelector, resultSelector); + } + + public static IObservable SelectMany(this IObservable source, Func> selector) + { + return new SelectManyObservable(source, selector); + } + + public static IObservable SelectMany(this IObservable source, Func> selector) + { + return new SelectManyObservable(source, selector); + } + + public static IObservable SelectMany(this IObservable source, Func> collectionSelector, Func resultSelector) + { + return new SelectManyObservable(source, collectionSelector, resultSelector); + } + + public static IObservable SelectMany(this IObservable source, Func> collectionSelector, Func resultSelector) + { + return new SelectManyObservable(source, collectionSelector, resultSelector); + } + + public static IObservable ToArray(this IObservable source) + { + return new ToArrayObservable(source); + } + + public static IObservable> ToList(this IObservable source) + { + return new ToListObservable(source); + } + + public static IObservable Do(this IObservable source, IObserver observer) + { + return new DoObserverObservable(source, observer); + } + + public static IObservable Do(this IObservable source, Action onNext) + { + return new DoObservable(source, onNext, Stubs.Throw, Stubs.Nop); + } + + public static IObservable Do(this IObservable source, Action onNext, Action onError) + { + return new DoObservable(source, onNext, onError, Stubs.Nop); + } + + public static IObservable Do(this IObservable source, Action onNext, Action onCompleted) + { + return new DoObservable(source, onNext, Stubs.Throw, onCompleted); + } + + public static IObservable Do(this IObservable source, Action onNext, Action onError, Action onCompleted) + { + return new DoObservable(source, onNext, onError, onCompleted); + } + + public static IObservable DoOnError(this IObservable source, Action onError) + { + return new DoOnErrorObservable(source, onError); + } + + public static IObservable DoOnCompleted(this IObservable source, Action onCompleted) + { + return new DoOnCompletedObservable(source, onCompleted); + } + + public static IObservable DoOnTerminate(this IObservable source, Action onTerminate) + { + return new DoOnTerminateObservable(source, onTerminate); + } + + public static IObservable DoOnSubscribe(this IObservable source, Action onSubscribe) + { + return new DoOnSubscribeObservable(source, onSubscribe); + } + + public static IObservable DoOnCancel(this IObservable source, Action onCancel) + { + return new DoOnCancelObservable(source, onCancel); + } + + public static IObservable> Materialize(this IObservable source) + { + return new MaterializeObservable(source); + } + + public static IObservable Dematerialize(this IObservable> source) + { + return new DematerializeObservable(source); + } + + public static IObservable DefaultIfEmpty(this IObservable source) + { + return new DefaultIfEmptyObservable(source, default(T)); + } + + public static IObservable DefaultIfEmpty(this IObservable source, T defaultValue) + { + return new DefaultIfEmptyObservable(source, defaultValue); + } + + public static IObservable Distinct(this IObservable source) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return new DistinctObservable(source, comparer); + } + + public static IObservable Distinct(this IObservable source, IEqualityComparer comparer) + { + return new DistinctObservable(source, comparer); + } + + public static IObservable Distinct(this IObservable source, Func keySelector) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return new DistinctObservable(source, keySelector, comparer); + } + + public static IObservable Distinct(this IObservable source, Func keySelector, IEqualityComparer comparer) + { + return new DistinctObservable(source, keySelector, comparer); + } + + public static IObservable DistinctUntilChanged(this IObservable source) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return new DistinctUntilChangedObservable(source, comparer); + } + + public static IObservable DistinctUntilChanged(this IObservable source, IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException("source"); + + return new DistinctUntilChangedObservable(source, comparer); + } + + public static IObservable DistinctUntilChanged(this IObservable source, Func keySelector) + { +#if !UniRxLibrary + var comparer = UnityEqualityComparer.GetDefault(); +#else + var comparer = EqualityComparer.Default; +#endif + + return new DistinctUntilChangedObservable(source, keySelector, comparer); + } + + public static IObservable DistinctUntilChanged(this IObservable source, Func keySelector, IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException("source"); + + return new DistinctUntilChangedObservable(source, keySelector, comparer); + } + + public static IObservable IgnoreElements(this IObservable source) + { + return new IgnoreElementsObservable(source); + } + + public static IObservable ForEachAsync(this IObservable source, Action onNext) + { + return new ForEachAsyncObservable(source, onNext); + } + + public static IObservable ForEachAsync(this IObservable source, Action onNext) + { + return new ForEachAsyncObservable(source, onNext); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs.meta new file mode 100644 index 00000000..24486d46 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a2dd1c80d4559fd4ca9ef62f20d031ab +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs new file mode 100644 index 00000000..e12daecb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs @@ -0,0 +1,524 @@ +using System; +using System.Threading; +using UniRx.InternalUtil; + +namespace UniRx +{ + public static class Observer + { + internal static IObserver CreateSubscribeObserver(Action onNext, Action onError, Action onCompleted) + { + // need compare for avoid iOS AOT + if (onNext == Stubs.Ignore) + { + return new Subscribe_(onError, onCompleted); + } + else + { + return new Subscribe(onNext, onError, onCompleted); + } + } + + internal static IObserver CreateSubscribeWithStateObserver(TState state, Action onNext, Action onError, Action onCompleted) + { + return new Subscribe(state, onNext, onError, onCompleted); + } + + internal static IObserver CreateSubscribeWithState2Observer(TState1 state1, TState2 state2, Action onNext, Action onError, Action onCompleted) + { + return new Subscribe(state1, state2, onNext, onError, onCompleted); + } + + internal static IObserver CreateSubscribeWithState3Observer(TState1 state1, TState2 state2, TState3 state3, Action onNext, Action onError, Action onCompleted) + { + return new Subscribe(state1, state2, state3, onNext, onError, onCompleted); + } + + public static IObserver Create(Action onNext) + { + return Create(onNext, UniRx.Stubs.Throw, UniRx.Stubs.Nop); + } + + public static IObserver Create(Action onNext, Action onError) + { + return Create(onNext, onError, UniRx.Stubs.Nop); + } + + public static IObserver Create(Action onNext, Action onCompleted) + { + return Create(onNext, UniRx.Stubs.Throw, onCompleted); + } + + public static IObserver Create(Action onNext, Action onError, Action onCompleted) + { + // need compare for avoid iOS AOT + if (onNext == Stubs.Ignore) + { + return new EmptyOnNextAnonymousObserver(onError, onCompleted); + } + else + { + return new AnonymousObserver(onNext, onError, onCompleted); + } + } + + public static IObserver CreateAutoDetachObserver(IObserver observer, IDisposable disposable) + { + return new AutoDetachObserver(observer, disposable); + } + + class AnonymousObserver : IObserver + { + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public AnonymousObserver(Action onNext, Action onError, Action onCompleted) + { + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + if (isStopped == 0) + { + onNext(value); + } + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error); + } + } + + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(); + } + } + } + + class EmptyOnNextAnonymousObserver : IObserver + { + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public EmptyOnNextAnonymousObserver(Action onError, Action onCompleted) + { + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error); + } + } + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(); + } + } + } + + // same as AnonymousObserver... + class Subscribe : IObserver + { + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public Subscribe(Action onNext, Action onError, Action onCompleted) + { + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + if (isStopped == 0) + { + onNext(value); + } + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error); + } + } + + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(); + } + } + } + + // same as EmptyOnNextAnonymousObserver... + class Subscribe_ : IObserver + { + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public Subscribe_(Action onError, Action onCompleted) + { + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error); + } + } + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(); + } + } + } + + // with state + class Subscribe : IObserver + { + readonly TState state; + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public Subscribe(TState state, Action onNext, Action onError, Action onCompleted) + { + this.state = state; + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + if (isStopped == 0) + { + onNext(value, state); + } + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error, state); + } + } + + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(state); + } + } + } + + class Subscribe : IObserver + { + readonly TState1 state1; + readonly TState2 state2; + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public Subscribe(TState1 state1, TState2 state2, Action onNext, Action onError, Action onCompleted) + { + this.state1 = state1; + this.state2 = state2; + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + if (isStopped == 0) + { + onNext(value, state1, state2); + } + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error, state1, state2); + } + } + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(state1, state2); + } + } + } + + class Subscribe : IObserver + { + readonly TState1 state1; + readonly TState2 state2; + readonly TState3 state3; + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + int isStopped = 0; + + public Subscribe(TState1 state1, TState2 state2, TState3 state3, Action onNext, Action onError, Action onCompleted) + { + this.state1 = state1; + this.state2 = state2; + this.state3 = state3; + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + public void OnNext(T value) + { + if (isStopped == 0) + { + onNext(value, state1, state2, state3); + } + } + + public void OnError(Exception error) + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onError(error, state1, state2, state3); + } + } + + + public void OnCompleted() + { + if (Interlocked.Increment(ref isStopped) == 1) + { + onCompleted(state1, state2, state3); + } + } + } + + class AutoDetachObserver : UniRx.Operators.OperatorObserverBase + { + public AutoDetachObserver(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + public static partial class ObserverExtensions + { + public static IObserver Synchronize(this IObserver observer) + { + return new UniRx.Operators.SynchronizedObserver(observer, new object()); + } + + public static IObserver Synchronize(this IObserver observer, object gate) + { + return new UniRx.Operators.SynchronizedObserver(observer, gate); + } + } + + public static partial class ObservableExtensions + { + public static IDisposable Subscribe(this IObservable source) + { + return source.Subscribe(UniRx.InternalUtil.ThrowObserver.Instance); + } + + public static IDisposable Subscribe(this IObservable source, Action onNext) + { + return source.Subscribe(Observer.CreateSubscribeObserver(onNext, Stubs.Throw, Stubs.Nop)); + } + + public static IDisposable Subscribe(this IObservable source, Action onNext, Action onError) + { + return source.Subscribe(Observer.CreateSubscribeObserver(onNext, onError, Stubs.Nop)); + } + + public static IDisposable Subscribe(this IObservable source, Action onNext, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeObserver(onNext, Stubs.Throw, onCompleted)); + } + + public static IDisposable Subscribe(this IObservable source, Action onNext, Action onError, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeObserver(onNext, onError, onCompleted)); + } + + public static IDisposable SubscribeWithState(this IObservable source, TState state, Action onNext) + { + return source.Subscribe(Observer.CreateSubscribeWithStateObserver(state, onNext, Stubs.Throw, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState(this IObservable source, TState state, Action onNext, Action onError) + { + return source.Subscribe(Observer.CreateSubscribeWithStateObserver(state, onNext, onError, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState(this IObservable source, TState state, Action onNext, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithStateObserver(state, onNext, Stubs.Throw, onCompleted)); + } + + public static IDisposable SubscribeWithState(this IObservable source, TState state, Action onNext, Action onError, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithStateObserver(state, onNext, onError, onCompleted)); + } + + public static IDisposable SubscribeWithState2(this IObservable source, TState1 state1, TState2 state2, Action onNext) + { + return source.Subscribe(Observer.CreateSubscribeWithState2Observer(state1, state2, onNext, Stubs.Throw, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState2(this IObservable source, TState1 state1, TState2 state2, Action onNext, Action onError) + { + return source.Subscribe(Observer.CreateSubscribeWithState2Observer(state1, state2, onNext, onError, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState2(this IObservable source, TState1 state1, TState2 state2, Action onNext, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithState2Observer(state1, state2, onNext, Stubs.Throw, onCompleted)); + } + + public static IDisposable SubscribeWithState2(this IObservable source, TState1 state1, TState2 state2, Action onNext, Action onError, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithState2Observer(state1, state2, onNext, onError, onCompleted)); + } + + public static IDisposable SubscribeWithState3(this IObservable source, TState1 state1, TState2 state2, TState3 state3, Action onNext) + { + return source.Subscribe(Observer.CreateSubscribeWithState3Observer(state1, state2, state3, onNext, Stubs.Throw, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState3(this IObservable source, TState1 state1, TState2 state2, TState3 state3, Action onNext, Action onError) + { + return source.Subscribe(Observer.CreateSubscribeWithState3Observer(state1, state2, state3, onNext, onError, Stubs.Ignore)); + } + + public static IDisposable SubscribeWithState3(this IObservable source, TState1 state1, TState2 state2, TState3 state3, Action onNext, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithState3Observer(state1, state2, state3, onNext, Stubs.Throw, onCompleted)); + } + + public static IDisposable SubscribeWithState3(this IObservable source, TState1 state1, TState2 state2, TState3 state3, Action onNext, Action onError, Action onCompleted) + { + return source.Subscribe(Observer.CreateSubscribeWithState3Observer(state1, state2, state3, onNext, onError, onCompleted)); + } + } + + internal static class Stubs + { + public static readonly Action Nop = () => { }; + public static readonly Action Throw = ex => { ex.Throw(); }; + + // marker for CatchIgnore and Catch avoid iOS AOT problem. + public static IObservable CatchIgnore(Exception ex) + { + return Observable.Empty(); + } + } + + internal static class Stubs + { + public static readonly Action Ignore = (T t) => { }; + public static readonly Func Identity = (T t) => t; + public static readonly Action Throw = (ex, _) => { ex.Throw(); }; + } + + internal static class Stubs + { + public static readonly Action Ignore = (x, y) => { }; + public static readonly Action Throw = (ex, _, __) => { ex.Throw(); }; + } + + + internal static class Stubs + { + public static readonly Action Ignore = (x, y, z) => { }; + public static readonly Action Throw = (ex, _, __, ___) => { ex.Throw(); }; + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs.meta new file mode 100644 index 00000000..96308b54 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Observer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 57d25c3f6fa1d334e89c384393252b8a +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators.meta new file mode 100644 index 00000000..007464fd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b37ab723fc6829344bcb6a5991a4e2a1 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs new file mode 100644 index 00000000..ae4c4040 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs @@ -0,0 +1,207 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class AggregateObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func accumulator; + + public AggregateObservable(IObservable source, Func accumulator) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.accumulator = accumulator; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Aggregate(this, observer, cancel)); + } + + class Aggregate : OperatorObserverBase + { + readonly AggregateObservable parent; + TSource accumulation; + bool seenValue; + + public Aggregate(AggregateObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.seenValue = false; + } + + public override void OnNext(TSource value) + { + if (!seenValue) + { + seenValue = true; + accumulation = value; + } + else + { + try + { + accumulation = parent.accumulator(accumulation, value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (!seenValue) + { + throw new InvalidOperationException("Sequence contains no elements."); + } + + observer.OnNext(accumulation); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class AggregateObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TAccumulate seed; + readonly Func accumulator; + + public AggregateObservable(IObservable source, TAccumulate seed, Func accumulator) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.seed = seed; + this.accumulator = accumulator; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Aggregate(this, observer, cancel)); + } + + class Aggregate : OperatorObserverBase + { + readonly AggregateObservable parent; + TAccumulate accumulation; + + public Aggregate(AggregateObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.accumulation = parent.seed; + } + + public override void OnNext(TSource value) + { + try + { + accumulation = parent.accumulator(accumulation, value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + observer.OnNext(accumulation); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class AggregateObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TAccumulate seed; + readonly Func accumulator; + readonly Func resultSelector; + + public AggregateObservable(IObservable source, TAccumulate seed, Func accumulator, Func resultSelector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.seed = seed; + this.accumulator = accumulator; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Aggregate(this, observer, cancel)); + } + + class Aggregate : OperatorObserverBase + { + readonly AggregateObservable parent; + TAccumulate accumulation; + + public Aggregate(AggregateObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.accumulation = parent.seed; + } + + public override void OnNext(TSource value) + { + try + { + accumulation = parent.accumulator(accumulation, value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + TResult result; + try + { + result = parent.resultSelector(accumulation); + } + catch (Exception ex) + { + OnError(ex); + return; + } + + observer.OnNext(result); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs.meta new file mode 100644 index 00000000..e3612b90 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Aggregate.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f777fc54ecf275349a3f007e760705b3 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs new file mode 100644 index 00000000..198ef91d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class AmbObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObservable second; + + public AmbObservable(IObservable source, IObservable second) + : base(source.IsRequiredSubscribeOnCurrentThread() || second.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.second = second; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new AmbOuterObserver(this, observer, cancel).Run(); + } + + class AmbOuterObserver : OperatorObserverBase + { + enum AmbState + { + Left, Right, Neither + } + + readonly AmbObservable parent; + readonly object gate = new object(); + SingleAssignmentDisposable leftSubscription; + SingleAssignmentDisposable rightSubscription; + AmbState choice = AmbState.Neither; + + public AmbOuterObserver(AmbObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + leftSubscription = new SingleAssignmentDisposable(); + rightSubscription = new SingleAssignmentDisposable(); + var d = StableCompositeDisposable.Create(leftSubscription, rightSubscription); + + var left = new Amb(); + left.targetDisposable = d; + left.targetObserver = new AmbDecisionObserver(this, AmbState.Left, rightSubscription, left); + + var right = new Amb(); + right.targetDisposable = d; + right.targetObserver = new AmbDecisionObserver(this, AmbState.Right, leftSubscription, right); + + leftSubscription.Disposable = parent.source.Subscribe(left); + rightSubscription.Disposable = parent.second.Subscribe(right); + + return d; + } + + public override void OnNext(T value) + { + // no use + } + + public override void OnError(Exception error) + { + // no use + } + + public override void OnCompleted() + { + // no use + } + + class Amb : IObserver + { + public IObserver targetObserver; + public IDisposable targetDisposable; + + public void OnNext(T value) + { + targetObserver.OnNext(value); + } + + public void OnError(Exception error) + { + try + { + targetObserver.OnError(error); + } + finally + { + targetObserver = UniRx.InternalUtil.EmptyObserver.Instance; + targetDisposable.Dispose(); + } + } + + public void OnCompleted() + { + try + { + targetObserver.OnCompleted(); + } + finally + { + targetObserver = UniRx.InternalUtil.EmptyObserver.Instance; + targetDisposable.Dispose(); + } + } + } + + class AmbDecisionObserver : IObserver + { + readonly AmbOuterObserver parent; + readonly AmbState me; + readonly IDisposable otherSubscription; + readonly Amb self; + + public AmbDecisionObserver(AmbOuterObserver parent, AmbState me, IDisposable otherSubscription, Amb self) + { + this.parent = parent; + this.me = me; + this.otherSubscription = otherSubscription; + this.self = self; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + if (parent.choice == AmbState.Neither) + { + parent.choice = me; + otherSubscription.Dispose(); + self.targetObserver = parent.observer; + } + + if (parent.choice == me) self.targetObserver.OnNext(value); + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (parent.choice == AmbState.Neither) + { + parent.choice = me; + otherSubscription.Dispose(); + self.targetObserver = parent.observer; + } + + if (parent.choice == me) + { + self.targetObserver.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (parent.choice == AmbState.Neither) + { + parent.choice = me; + otherSubscription.Dispose(); + self.targetObserver = parent.observer; + } + + if (parent.choice == me) + { + self.targetObserver.OnCompleted(); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs.meta new file mode 100644 index 00000000..6fda3c4e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Amb.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ad1a22922a735ee479baf0e179648532 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs new file mode 100644 index 00000000..2265a1cd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs @@ -0,0 +1,45 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class AsObservableObservable : OperatorObservableBase + { + readonly IObservable source; + + public AsObservableObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new AsObservable(observer, cancel)); + } + + class AsObservable : OperatorObserverBase + { + public AsObservable(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs.meta new file mode 100644 index 00000000..5d6c9b91 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9e4851fd48b2b42469d71b311254877b +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs new file mode 100644 index 00000000..396e18fe --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs @@ -0,0 +1,46 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class AsSingleUnitObservableObservable : OperatorObservableBase + { + readonly IObservable source; + + public AsSingleUnitObservableObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new AsSingleUnitObservable(observer, cancel)); + } + + class AsSingleUnitObservable : OperatorObserverBase + { + public AsSingleUnitObservable(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + observer.OnNext(Unit.Default); + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs.meta new file mode 100644 index 00000000..cc1e73d0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsSingleUnitObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3b5e05dba2d3aca4e9c3a6312bef8690 +timeCreated: 1462636004 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs new file mode 100644 index 00000000..82cba6eb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs @@ -0,0 +1,45 @@ +using System; + +namespace UniRx.Operators +{ + internal class AsUnitObservableObservable : OperatorObservableBase + { + readonly IObservable source; + + public AsUnitObservableObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new AsUnitObservable(observer, cancel)); + } + + class AsUnitObservable : OperatorObserverBase + { + public AsUnitObservable(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + base.observer.OnNext(Unit.Default); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs.meta new file mode 100644 index 00000000..27cd014e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/AsUnitObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 236f5f407bf92c949844fcaf450af450 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs new file mode 100644 index 00000000..f12b0eaf --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class BufferObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly int count; + readonly int skip; + + readonly TimeSpan timeSpan; + readonly TimeSpan timeShift; + readonly IScheduler scheduler; + + public BufferObservable(IObservable source, int count, int skip) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.count = count; + this.skip = skip; + } + + public BufferObservable(IObservable source, TimeSpan timeSpan, TimeSpan timeShift, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.timeSpan = timeSpan; + this.timeShift = timeShift; + this.scheduler = scheduler; + } + + public BufferObservable(IObservable source, TimeSpan timeSpan, int count, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.timeSpan = timeSpan; + this.count = count; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + // count,skip + if (scheduler == null) + { + if (skip == 0) + { + return new Buffer(this, observer, cancel).Run(); + } + else + { + return new Buffer_(this, observer, cancel).Run(); + } + } + else + { + // time + count + if (count > 0) + { + return new BufferTC(this, observer, cancel).Run(); + } + else + { + if (timeSpan == timeShift) + { + return new BufferT(this, observer, cancel).Run(); + } + else + { + return new BufferTS(this, observer, cancel).Run(); + } + } + } + } + + // count only + class Buffer : OperatorObserverBase> + { + readonly BufferObservable parent; + List list; + + public Buffer(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + list = new List(parent.count); + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + list.Add(value); + if (list.Count == parent.count) + { + observer.OnNext(list); + list = new List(parent.count); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + if (list.Count > 0) + { + observer.OnNext(list); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + // count and skip + class Buffer_ : OperatorObserverBase> + { + readonly BufferObservable parent; + Queue> q; + int index; + + public Buffer_(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + q = new Queue>(); + index = -1; + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + index++; + + if (index % parent.skip == 0) + { + q.Enqueue(new List(parent.count)); + } + + var len = q.Count; + for (int i = 0; i < len; i++) + { + var list = q.Dequeue(); + list.Add(value); + if (list.Count == parent.count) + { + observer.OnNext(list); + } + else + { + q.Enqueue(list); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + foreach (var list in q) + { + observer.OnNext(list); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + // timespan = timeshift + class BufferT : OperatorObserverBase> + { + static readonly T[] EmptyArray = new T[0]; + + readonly BufferObservable parent; + readonly object gate = new object(); + + List list; + + public BufferT(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + list = new List(); + + var timerSubscription = Observable.Interval(parent.timeSpan, parent.scheduler) + .Subscribe(new Buffer(this)); + + var sourceSubscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(timerSubscription, sourceSubscription); + } + + public override void OnNext(T value) + { + lock (gate) + { + list.Add(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + List currentList; + lock (gate) + { + currentList = list; + } + observer.OnNext(currentList); + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class Buffer : IObserver + { + BufferT parent; + + public Buffer(BufferT parent) + { + this.parent = parent; + } + + public void OnNext(long value) + { + var isZero = false; + List currentList; + lock (parent.gate) + { + currentList = parent.list; + if (currentList.Count != 0) + { + parent.list = new List(); + } + else + { + isZero = true; + } + } + + parent.observer.OnNext((isZero) ? (IList)EmptyArray : currentList); + } + + public void OnError(Exception error) + { + } + + public void OnCompleted() + { + } + } + } + + // timespan + timeshift + class BufferTS : OperatorObserverBase> + { + readonly BufferObservable parent; + readonly object gate = new object(); + + Queue> q; + TimeSpan totalTime; + TimeSpan nextShift; + TimeSpan nextSpan; + SerialDisposable timerD; + + public BufferTS(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + totalTime = TimeSpan.Zero; + nextShift = parent.timeShift; + nextSpan = parent.timeSpan; + + q = new Queue>(); + + timerD = new SerialDisposable(); + q.Enqueue(new List()); + CreateTimer(); + + var subscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(subscription, timerD); + } + + void CreateTimer() + { + var m = new SingleAssignmentDisposable(); + timerD.Disposable = m; + + var isSpan = false; + var isShift = false; + if (nextSpan == nextShift) + { + isSpan = true; + isShift = true; + } + else if (nextSpan < nextShift) + isSpan = true; + else + isShift = true; + + var newTotalTime = isSpan ? nextSpan : nextShift; + var ts = newTotalTime - totalTime; + totalTime = newTotalTime; + + if (isSpan) + nextSpan += parent.timeShift; + if (isShift) + nextShift += parent.timeShift; + + m.Disposable = parent.scheduler.Schedule(ts, () => + { + lock (gate) + { + if (isShift) + { + var s = new List(); + q.Enqueue(s); + } + if (isSpan) + { + var s = q.Dequeue(); + observer.OnNext(s); + } + } + + CreateTimer(); + }); + } + + public override void OnNext(T value) + { + lock (gate) + { + foreach (var s in q) + { + s.Add(value); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + lock (gate) + { + foreach (var list in q) + { + observer.OnNext(list); + } + + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + // timespan + count + class BufferTC : OperatorObserverBase> + { + static readonly T[] EmptyArray = new T[0]; // cache + + readonly BufferObservable parent; + readonly object gate = new object(); + + List list; + long timerId; + SerialDisposable timerD; + + public BufferTC(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + list = new List(); + timerId = 0L; + timerD = new SerialDisposable(); + + CreateTimer(); + var subscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(subscription, timerD); + } + + void CreateTimer() + { + var currentTimerId = timerId; + var timerS = new SingleAssignmentDisposable(); + timerD.Disposable = timerS; // restart timer(dispose before) + + + var periodicScheduler = parent.scheduler as ISchedulerPeriodic; + if (periodicScheduler != null) + { + timerS.Disposable = periodicScheduler.SchedulePeriodic(parent.timeSpan, () => OnNextTick(currentTimerId)); + } + else + { + timerS.Disposable = parent.scheduler.Schedule(parent.timeSpan, self => OnNextRecursive(currentTimerId, self)); + } + } + + void OnNextTick(long currentTimerId) + { + var isZero = false; + List currentList; + lock (gate) + { + if (currentTimerId != timerId) return; + + currentList = list; + if (currentList.Count != 0) + { + list = new List(); + } + else + { + isZero = true; + } + } + + observer.OnNext((isZero) ? (IList)EmptyArray : currentList); + } + + void OnNextRecursive(long currentTimerId, Action self) + { + var isZero = false; + List currentList; + lock (gate) + { + if (currentTimerId != timerId) return; + + currentList = list; + if (currentList.Count != 0) + { + list = new List(); + } + else + { + isZero = true; + } + } + + observer.OnNext((isZero) ? (IList)EmptyArray : currentList); + self(parent.timeSpan); + } + + public override void OnNext(T value) + { + List currentList = null; + lock (gate) + { + list.Add(value); + if (list.Count == parent.count) + { + currentList = list; + list = new List(); + timerId++; + CreateTimer(); + } + } + if (currentList != null) + { + observer.OnNext(currentList); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + List currentList; + lock (gate) + { + timerId++; + currentList = list; + } + observer.OnNext(currentList); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + internal class BufferObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly IObservable windowBoundaries; + + public BufferObservable(IObservable source, IObservable windowBoundaries) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.windowBoundaries = windowBoundaries; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new Buffer(this, observer, cancel).Run(); + } + + class Buffer : OperatorObserverBase> + { + static readonly TSource[] EmptyArray = new TSource[0]; // cache + + readonly BufferObservable parent; + object gate = new object(); + List list; + + public Buffer(BufferObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + list = new List(); + + var sourceSubscription = parent.source.Subscribe(this); + var windowSubscription = parent.windowBoundaries.Subscribe(new Buffer_(this)); + + return StableCompositeDisposable.Create(sourceSubscription, windowSubscription); + } + + public override void OnNext(TSource value) + { + lock (gate) + { + list.Add(value); + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + var currentList = list; + list = new List(); // safe + observer.OnNext(currentList); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class Buffer_ : IObserver + { + readonly Buffer parent; + + public Buffer_(Buffer parent) + { + this.parent = parent; + } + + public void OnNext(TWindowBoundary value) + { + var isZero = false; + List currentList; + lock (parent.gate) + { + currentList = parent.list; + if (currentList.Count != 0) + { + parent.list = new List(); + } + else + { + isZero = true; + } + } + if (isZero) + { + parent.observer.OnNext(EmptyArray); + } + else + { + parent.observer.OnNext(currentList); + } + } + + public void OnError(Exception error) + { + parent.OnError(error); + } + + public void OnCompleted() + { + parent.OnCompleted(); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs.meta new file mode 100644 index 00000000..83e4a888 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Buffer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4137aec9640d3ea41a740d677026aa8c +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs new file mode 100644 index 00000000..f0008b11 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs @@ -0,0 +1,57 @@ +using System; + +namespace UniRx.Operators +{ + internal class CastObservable : OperatorObservableBase + { + readonly IObservable source; + + public CastObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Cast(observer, cancel)); + } + + class Cast : OperatorObserverBase + { + public Cast(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(TSource value) + { + var castValue = default(TResult); + try + { + castValue = (TResult)(object)value; + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + observer.OnNext(castValue); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs.meta new file mode 100644 index 00000000..44cd9f7e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Cast.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e70ae559c9b927742acbff91d50b3b22 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs new file mode 100644 index 00000000..93014d9a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class CatchObservable : OperatorObservableBase + where TException : Exception + { + readonly IObservable source; + readonly Func> errorHandler; + + public CatchObservable(IObservable source, Func> errorHandler) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.errorHandler = errorHandler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Catch(this, observer, cancel).Run(); + } + + class Catch : OperatorObserverBase + { + readonly CatchObservable parent; + SingleAssignmentDisposable sourceSubscription; + SingleAssignmentDisposable exceptionSubscription; + + public Catch(CatchObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + this.sourceSubscription = new SingleAssignmentDisposable(); + this.exceptionSubscription = new SingleAssignmentDisposable(); + + this.sourceSubscription.Disposable = parent.source.Subscribe(this); + return StableCompositeDisposable.Create(sourceSubscription, exceptionSubscription); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + var e = error as TException; + if (e != null) + { + IObservable next; + try + { + if (parent.errorHandler == Stubs.CatchIgnore) + { + next = Observable.Empty(); // for avoid iOS AOT + } + else + { + next = parent.errorHandler(e); + } + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + exceptionSubscription.Disposable = next.Subscribe(observer); + } + else + { + try { observer.OnError(error); } finally { Dispose(); }; + return; + } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + + + internal class CatchObservable : OperatorObservableBase + { + readonly IEnumerable> sources; + + public CatchObservable(IEnumerable> sources) + : base(true) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Catch(this, observer, cancel).Run(); + } + + class Catch : OperatorObserverBase + { + readonly CatchObservable parent; + readonly object gate = new object(); + bool isDisposed; + IEnumerator> e; + SerialDisposable subscription; + Exception lastException; + Action nextSelf; + + public Catch(CatchObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + isDisposed = false; + e = parent.sources.GetEnumerator(); + subscription = new SerialDisposable(); + + var schedule = Scheduler.DefaultSchedulers.TailRecursion.Schedule(RecursiveRun); + + return StableCompositeDisposable.Create(schedule, subscription, Disposable.Create(() => + { + lock (gate) + { + this.isDisposed = true; + this.e.Dispose(); + } + })); + } + + void RecursiveRun(Action self) + { + lock (gate) + { + nextSelf = self; + if (isDisposed) return; + + var current = default(IObservable); + var hasNext = false; + var ex = default(Exception); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + if (current == null) throw new InvalidOperationException("sequence is null."); + } + else + { + e.Dispose(); + } + } + catch (Exception exception) + { + ex = exception; + e.Dispose(); + } + + if (ex != null) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (!hasNext) + { + if (lastException != null) + { + try { observer.OnError(lastException); } + finally { Dispose(); } + } + else + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + return; + } + + var source = current; + var d = new SingleAssignmentDisposable(); + subscription.Disposable = d; + d.Disposable = source.Subscribe(this); + } + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + lastException = error; + nextSelf(); + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs.meta new file mode 100644 index 00000000..881769f8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Catch.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 404a684db151ca34f8258c6fb373db8d +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs new file mode 100644 index 00000000..b24b6c1f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs @@ -0,0 +1,1010 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + public delegate TR CombineLatestFunc(T1 arg1, T2 arg2, T3 arg3); + public delegate TR CombineLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + public delegate TR CombineLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate TR CombineLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate TR CombineLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + + // binary + internal class CombineLatestObservable : OperatorObservableBase + { + readonly IObservable left; + readonly IObservable right; + readonly Func selector; + + public CombineLatestObservable(IObservable left, IObservable right, Func selector) + : base(left.IsRequiredSubscribeOnCurrentThread() || right.IsRequiredSubscribeOnCurrentThread()) + { + this.left = left; + this.right = right; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(this, observer, cancel).Run(); + } + + class CombineLatest : OperatorObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + + TLeft leftValue = default(TLeft); + bool leftStarted = false; + bool leftCompleted = false; + + TRight rightValue = default(TRight); + bool rightStarted = false; + bool rightCompleted = false; + + public CombineLatest(CombineLatestObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var l = parent.left.Subscribe(new LeftObserver(this)); + var r = parent.right.Subscribe(new RightObserver(this)); + + return StableCompositeDisposable.Create(l, r); + } + + // publish in lock + public void Publish() + { + if ((leftCompleted && !leftStarted) || (rightCompleted && !rightStarted)) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else if (!(leftStarted && rightStarted)) + { + return; + } + + TResult v; + try + { + v = parent.selector(leftValue, rightValue); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + OnNext(v); + } + + public override void OnNext(TResult value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class LeftObserver : IObserver + { + readonly CombineLatest parent; + + public LeftObserver(CombineLatest parent) + { + this.parent = parent; + } + + public void OnNext(TLeft value) + { + lock (parent.gate) + { + parent.leftStarted = true; + parent.leftValue = value; + parent.Publish(); + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.leftCompleted = true; + if (parent.rightCompleted) parent.OnCompleted(); + } + } + } + + class RightObserver : IObserver + { + readonly CombineLatest parent; + + public RightObserver(CombineLatest parent) + { + this.parent = parent; + } + + + public void OnNext(TRight value) + { + lock (parent.gate) + { + parent.rightStarted = true; + parent.rightValue = value; + parent.Publish(); + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.rightCompleted = true; + if (parent.leftCompleted) parent.OnCompleted(); + } + } + } + } + } + + // array + internal class CombineLatestObservable : OperatorObservableBase> + { + readonly IObservable[] sources; + + public CombineLatestObservable(IObservable[] sources) + : base(true) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new CombineLatest(this, observer, cancel).Run(); + } + + class CombineLatest : OperatorObserverBase, IList> + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + + int length; + T[] values; + bool[] isStarted; + bool[] isCompleted; + bool isAllValueStarted; + + public CombineLatest(CombineLatestObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + length = parent.sources.Length; + values = new T[length]; + isStarted = new bool[length]; + isCompleted = new bool[length]; + isAllValueStarted = false; + + var disposables = new IDisposable[length]; + for (int i = 0; i < length; i++) + { + var source = parent.sources[i]; + disposables[i] = source.Subscribe(new CombineLatestObserver(this, i)); + } + + return StableCompositeDisposable.CreateUnsafe(disposables); + } + + // publish is in the lock + void Publish(int index) + { + isStarted[index] = true; + + if (isAllValueStarted) + { + OnNext(new List(values)); + return; + } + + var allValueStarted = true; + for (int i = 0; i < length; i++) + { + if (!isStarted[i]) + { + allValueStarted = false; + break; + } + } + + isAllValueStarted = allValueStarted; + + if (isAllValueStarted) + { + OnNext(new List(values)); + return; + } + else + { + var allCompletedWithoutSelf = true; + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (!isCompleted[i]) + { + allCompletedWithoutSelf = false; + break; + } + } + + if (allCompletedWithoutSelf) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + return; + } + } + } + + public override void OnNext(IList value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class CombineLatestObserver : IObserver + { + readonly CombineLatest parent; + readonly int index; + + public CombineLatestObserver(CombineLatest parent, int index) + { + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + parent.values[index] = value; + parent.Publish(index); + } + } + + public void OnError(Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.isCompleted[index] = true; + + var allTrue = true; + for (int i = 0; i < parent.length; i++) + { + if (!parent.isCompleted[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + parent.OnCompleted(); + } + } + } + } + } + } + + // generated from UniRx.Console.CombineLatestGenerator.tt + #region NTH + + internal class CombineLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + CombineLatestFunc resultSelector; + + public CombineLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + CombineLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(3, this, observer, cancel).Run(); + } + + class CombineLatest : NthCombineLatestObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + CombineLatestObserver c1; + CombineLatestObserver c2; + CombineLatestObserver c3; + + public CombineLatest(int length, CombineLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new CombineLatestObserver(gate, this, 0); + c2 = new CombineLatestObserver(gate, this, 1); + c3 = new CombineLatestObserver(gate, this, 2); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + + return StableCompositeDisposable.Create(s1, s2, s3); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class CombineLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + CombineLatestFunc resultSelector; + + public CombineLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + CombineLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(4, this, observer, cancel).Run(); + } + + class CombineLatest : NthCombineLatestObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + CombineLatestObserver c1; + CombineLatestObserver c2; + CombineLatestObserver c3; + CombineLatestObserver c4; + + public CombineLatest(int length, CombineLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new CombineLatestObserver(gate, this, 0); + c2 = new CombineLatestObserver(gate, this, 1); + c3 = new CombineLatestObserver(gate, this, 2); + c4 = new CombineLatestObserver(gate, this, 3); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + + return StableCompositeDisposable.Create(s1, s2, s3, s4); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class CombineLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + CombineLatestFunc resultSelector; + + public CombineLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + CombineLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(5, this, observer, cancel).Run(); + } + + class CombineLatest : NthCombineLatestObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + CombineLatestObserver c1; + CombineLatestObserver c2; + CombineLatestObserver c3; + CombineLatestObserver c4; + CombineLatestObserver c5; + + public CombineLatest(int length, CombineLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new CombineLatestObserver(gate, this, 0); + c2 = new CombineLatestObserver(gate, this, 1); + c3 = new CombineLatestObserver(gate, this, 2); + c4 = new CombineLatestObserver(gate, this, 3); + c5 = new CombineLatestObserver(gate, this, 4); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class CombineLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + CombineLatestFunc resultSelector; + + public CombineLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + CombineLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(6, this, observer, cancel).Run(); + } + + class CombineLatest : NthCombineLatestObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + CombineLatestObserver c1; + CombineLatestObserver c2; + CombineLatestObserver c3; + CombineLatestObserver c4; + CombineLatestObserver c5; + CombineLatestObserver c6; + + public CombineLatest(int length, CombineLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new CombineLatestObserver(gate, this, 0); + c2 = new CombineLatestObserver(gate, this, 1); + c3 = new CombineLatestObserver(gate, this, 2); + c4 = new CombineLatestObserver(gate, this, 3); + c5 = new CombineLatestObserver(gate, this, 4); + c6 = new CombineLatestObserver(gate, this, 5); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + var s6 = parent.source6.Subscribe(c6); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class CombineLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + IObservable source7; + CombineLatestFunc resultSelector; + + public CombineLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + IObservable source7, + CombineLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + source7.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.source7 = source7; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new CombineLatest(7, this, observer, cancel).Run(); + } + + class CombineLatest : NthCombineLatestObserverBase + { + readonly CombineLatestObservable parent; + readonly object gate = new object(); + CombineLatestObserver c1; + CombineLatestObserver c2; + CombineLatestObserver c3; + CombineLatestObserver c4; + CombineLatestObserver c5; + CombineLatestObserver c6; + CombineLatestObserver c7; + + public CombineLatest(int length, CombineLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new CombineLatestObserver(gate, this, 0); + c2 = new CombineLatestObserver(gate, this, 1); + c3 = new CombineLatestObserver(gate, this, 2); + c4 = new CombineLatestObserver(gate, this, 3); + c5 = new CombineLatestObserver(gate, this, 4); + c6 = new CombineLatestObserver(gate, this, 5); + c7 = new CombineLatestObserver(gate, this, 6); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + var s6 = parent.source6.Subscribe(c6); + var s7 = parent.source7.Subscribe(c7); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6, s7); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value, c7.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + #endregion + + // Nth infrastructure + + internal interface ICombineLatestObservable + { + void Publish(int index); + void Fail(Exception error); + void Done(int index); + } + + internal abstract class NthCombineLatestObserverBase : OperatorObserverBase, ICombineLatestObservable + { + readonly int length; + bool isAllValueStarted; + readonly bool[] isStarted; + readonly bool[] isCompleted; + + public NthCombineLatestObserverBase(int length, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.length = length; + this.isAllValueStarted = false; + this.isStarted = new bool[length]; + this.isCompleted = new bool[length]; + } + + public abstract T GetResult(); + + // operators in lock + public void Publish(int index) + { + isStarted[index] = true; + + if (isAllValueStarted) + { + var result = default(T); + try + { + result = GetResult(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + OnNext(result); + return; + } + + var allValueStarted = true; + for (int i = 0; i < length; i++) + { + if (!isStarted[i]) + { + allValueStarted = false; + break; + } + } + + isAllValueStarted = allValueStarted; + + if (isAllValueStarted) + { + var result = default(T); + try + { + result = GetResult(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + OnNext(result); + return; + } + else + { + var allCompletedWithoutSelf = true; + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (!isCompleted[i]) + { + allCompletedWithoutSelf = false; + break; + } + } + + if (allCompletedWithoutSelf) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + return; + } + } + } + + public void Done(int index) + { + isCompleted[index] = true; + + var allTrue = true; + for (int i = 0; i < length; i++) + { + if (!isCompleted[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + + public void Fail(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + } + + // Nth + internal class CombineLatestObserver : IObserver + { + readonly object gate; + readonly ICombineLatestObservable parent; + readonly int index; + T value; + + public T Value { get { return value; } } + + public CombineLatestObserver(object gate, ICombineLatestObservable parent, int index) + { + this.gate = gate; + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (gate) + { + this.value = value; + parent.Publish(index); + } + } + + public void OnError(Exception error) + { + lock (gate) + { + parent.Fail(error); + } + } + + public void OnCompleted() + { + lock (gate) + { + parent.Done(index); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs.meta new file mode 100644 index 00000000..ad958dec --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/CombineLatest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 64910ffa78510ee48b3a395ee5b2cfe1 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs new file mode 100644 index 00000000..b1d80d76 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + // needs to more improvement + + internal class ConcatObservable : OperatorObservableBase + { + readonly IEnumerable> sources; + + public ConcatObservable(IEnumerable> sources) + : base(true) + { + this.sources = sources; + } + + public IObservable Combine(IEnumerable> combineSources) + { + return new ConcatObservable(CombineSources(this.sources, combineSources)); + } + + static IEnumerable> CombineSources(IEnumerable> first, IEnumerable> second) + { + foreach (var item in first) + { + yield return item; + } + foreach (var item in second) + { + yield return item; + } + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Concat(this, observer, cancel).Run(); + } + + class Concat : OperatorObserverBase + { + readonly ConcatObservable parent; + readonly object gate = new object(); + + bool isDisposed; + IEnumerator> e; + SerialDisposable subscription; + Action nextSelf; + + public Concat(ConcatObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + isDisposed = false; + e = parent.sources.GetEnumerator(); + subscription = new SerialDisposable(); + + var schedule = Scheduler.DefaultSchedulers.TailRecursion.Schedule(RecursiveRun); + + return StableCompositeDisposable.Create(schedule, subscription, Disposable.Create(() => + { + lock (gate) + { + this.isDisposed = true; + this.e.Dispose(); + } + })); + } + + void RecursiveRun(Action self) + { + lock (gate) + { + this.nextSelf = self; + if (isDisposed) return; + + var current = default(IObservable); + var hasNext = false; + var ex = default(Exception); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + if (current == null) throw new InvalidOperationException("sequence is null."); + } + else + { + e.Dispose(); + } + } + catch (Exception exception) + { + ex = exception; + e.Dispose(); + } + + if (ex != null) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (!hasNext) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + + var source = current; + var d = new SingleAssignmentDisposable(); + subscription.Disposable = d; + d.Disposable = source.Subscribe(this); + } + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + this.nextSelf(); + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs.meta new file mode 100644 index 00000000..3fbc84eb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Concat.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 740c2691a7e434f439abfdcac75ea809 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs new file mode 100644 index 00000000..6ce640f3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs @@ -0,0 +1,77 @@ +using System; + +namespace UniRx.Operators +{ + internal class ContinueWithObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func> selector; + + public ContinueWithObservable(IObservable source, Func> selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ContinueWith(this, observer, cancel).Run(); + } + + class ContinueWith : OperatorObserverBase + { + readonly ContinueWithObservable parent; + readonly SerialDisposable serialDisposable = new SerialDisposable(); + + bool seenValue; + TSource lastValue; + + public ContinueWith(ContinueWithObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var sourceDisposable = new SingleAssignmentDisposable(); + serialDisposable.Disposable = sourceDisposable; + + sourceDisposable.Disposable = parent.source.Subscribe(this); + return serialDisposable; + } + + public override void OnNext(TSource value) + { + this.seenValue = true; + this.lastValue = value; + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + if (seenValue) + { + try + { + var v = parent.selector(lastValue); + // dispose source subscription + serialDisposable.Disposable = v.Subscribe(observer); + } + catch (Exception error) + { + OnError(error); + } + } + else + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs.meta new file mode 100644 index 00000000..adc62b43 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ContinueWith.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bea59b3eb246d244a99183eeb7f3bad4 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs new file mode 100644 index 00000000..fc4fa87a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs @@ -0,0 +1,156 @@ +using System; + +namespace UniRx.Operators +{ + internal class CreateObservable : OperatorObservableBase + { + readonly Func, IDisposable> subscribe; + + public CreateObservable(Func, IDisposable> subscribe) + : base(true) // fail safe + { + this.subscribe = subscribe; + } + + public CreateObservable(Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.subscribe = subscribe; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Create(observer, cancel); + return subscribe(observer) ?? Disposable.Empty; + } + + class Create : OperatorObserverBase + { + public Create(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class CreateObservable : OperatorObservableBase + { + readonly TState state; + readonly Func, IDisposable> subscribe; + + public CreateObservable(TState state, Func, IDisposable> subscribe) + : base(true) // fail safe + { + this.state = state; + this.subscribe = subscribe; + } + + public CreateObservable(TState state, Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.state = state; + this.subscribe = subscribe; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Create(observer, cancel); + return subscribe(state, observer) ?? Disposable.Empty; + } + + class Create : OperatorObserverBase + { + public Create(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class CreateSafeObservable : OperatorObservableBase + { + readonly Func, IDisposable> subscribe; + + public CreateSafeObservable(Func, IDisposable> subscribe) + : base(true) // fail safe + { + this.subscribe = subscribe; + } + + public CreateSafeObservable(Func, IDisposable> subscribe, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.subscribe = subscribe; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new CreateSafe(observer, cancel); + return subscribe(observer) ?? Disposable.Empty; + } + + class CreateSafe : OperatorObserverBase + { + public CreateSafe(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); // safe + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs.meta new file mode 100644 index 00000000..6d4b0114 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Create.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cae9e62bf5eb3dc4e9d93cf6ff606052 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs new file mode 100644 index 00000000..ff7b8c9c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs @@ -0,0 +1,58 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class DefaultIfEmptyObservable : OperatorObservableBase + { + readonly IObservable source; + readonly T defaultValue; + + public DefaultIfEmptyObservable(IObservable source, T defaultValue) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.defaultValue = defaultValue; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new DefaultIfEmpty(this, observer, cancel)); + } + + class DefaultIfEmpty : OperatorObserverBase + { + readonly DefaultIfEmptyObservable parent; + bool hasValue; + + public DefaultIfEmpty(DefaultIfEmptyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.hasValue = false; + } + + public override void OnNext(T value) + { + hasValue = true; + observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (!hasValue) + { + observer.OnNext(parent.defaultValue); + } + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs.meta new file mode 100644 index 00000000..7dca208f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DefaultIfEmpty.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 551075cda284fbc489824d153743b1e6 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs new file mode 100644 index 00000000..81f01a8e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs @@ -0,0 +1,64 @@ +using System; + +namespace UniRx.Operators +{ + internal class DeferObservable : OperatorObservableBase + { + readonly Func> observableFactory; + + public DeferObservable(Func> observableFactory) + : base(false) + { + this.observableFactory = observableFactory; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Defer(observer, cancel); + + IObservable source; + try + { + source = observableFactory(); + } + catch (Exception ex) + { + source = Observable.Throw(ex); + } + + return source.Subscribe(observer); + } + + class Defer : OperatorObserverBase + { + public Defer(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs.meta new file mode 100644 index 00000000..ec8a87a6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Defer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 15ca418b98836d943864b1e8b82f6658 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs new file mode 100644 index 00000000..82e55fe6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + internal class DelayObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TimeSpan dueTime; + readonly IScheduler scheduler; + + public DelayObservable(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.dueTime = dueTime; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Delay(this, observer, cancel).Run(); + } + + class Delay : OperatorObserverBase + { + readonly DelayObservable parent; + readonly object gate = new object(); + bool hasFailed; + bool running; + bool active; + Exception exception; + Queue> queue; + bool onCompleted; + DateTimeOffset completeAt; + IDisposable sourceSubscription; + TimeSpan delay; + bool ready; + SerialDisposable cancelable; + + public Delay(DelayObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + cancelable = new SerialDisposable(); + + active = false; + running = false; + queue = new Queue>(); + onCompleted = false; + completeAt = default(DateTimeOffset); + hasFailed = false; + exception = default(Exception); + ready = true; + delay = Scheduler.Normalize(parent.dueTime); + + var _sourceSubscription = new SingleAssignmentDisposable(); + sourceSubscription = _sourceSubscription; // assign to field + _sourceSubscription.Disposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(sourceSubscription, cancelable); + } + + public override void OnNext(T value) + { + var next = parent.scheduler.Now.Add(delay); + var shouldRun = false; + + lock (gate) + { + queue.Enqueue(new Timestamped(value, next)); + + shouldRun = ready && !active; + active = true; + } + + if (shouldRun) + { + cancelable.Disposable = parent.scheduler.Schedule(delay, DrainQueue); + } + } + + public override void OnError(Exception error) + { + sourceSubscription.Dispose(); + + var shouldRun = false; + + lock (gate) + { + queue.Clear(); + + exception = error; + hasFailed = true; + + shouldRun = !running; + } + + if (shouldRun) + { + try { base.observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + sourceSubscription.Dispose(); + + var next = parent.scheduler.Now.Add(delay); + var shouldRun = false; + + lock (gate) + { + completeAt = next; + onCompleted = true; + + shouldRun = ready && !active; + active = true; + } + + if (shouldRun) + { + cancelable.Disposable = parent.scheduler.Schedule(delay, DrainQueue); + } + } + + void DrainQueue(Action recurse) + { + lock (gate) + { + if (hasFailed) return; + running = true; + } + + var shouldYield = false; + + while (true) + { + var hasFailed = false; + var error = default(Exception); + + var hasValue = false; + var value = default(T); + var hasCompleted = false; + + var shouldRecurse = false; + var recurseDueTime = default(TimeSpan); + + lock (gate) + { + if (hasFailed) + { + error = exception; + hasFailed = true; + running = false; + } + else + { + if (queue.Count > 0) + { + var nextDue = queue.Peek().Timestamp; + + if (nextDue.CompareTo(parent.scheduler.Now) <= 0 && !shouldYield) + { + value = queue.Dequeue().Value; + hasValue = true; + } + else + { + shouldRecurse = true; + recurseDueTime = Scheduler.Normalize(nextDue.Subtract(parent.scheduler.Now)); + running = false; + } + } + else if (onCompleted) + { + if (completeAt.CompareTo(parent.scheduler.Now) <= 0 && !shouldYield) + { + hasCompleted = true; + } + else + { + shouldRecurse = true; + recurseDueTime = Scheduler.Normalize(completeAt.Subtract(parent.scheduler.Now)); + running = false; + } + } + else + { + running = false; + active = false; + } + } + } + + if (hasValue) + { + base.observer.OnNext(value); + shouldYield = true; + } + else + { + if (hasCompleted) + { + try { base.observer.OnCompleted(); } finally { Dispose(); } + } + else if (hasFailed) + { + try { base.observer.OnError(error); } finally { Dispose(); } + } + else if (shouldRecurse) + { + recurse(recurseDueTime); + } + + return; + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs.meta new file mode 100644 index 00000000..32689642 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Delay.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2af9c507ce062994a904e4b5565b49c0 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs new file mode 100644 index 00000000..22ae6ca5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class DelaySubscriptionObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IScheduler scheduler; + readonly TimeSpan? dueTimeT; + readonly DateTimeOffset? dueTimeD; + + public DelaySubscriptionObservable(IObservable source,TimeSpan dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + this.dueTimeT = dueTime; + } + + public DelaySubscriptionObservable(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + this.dueTimeD = dueTime; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (dueTimeT != null) + { + var d = new MultipleAssignmentDisposable(); + var dt = Scheduler.Normalize(dueTimeT.Value); + + d.Disposable = scheduler.Schedule(dt, () => + { + d.Disposable = source.Subscribe(observer); + }); + + return d; + } + else + { + var d = new MultipleAssignmentDisposable(); + + d.Disposable = scheduler.Schedule(dueTimeD.Value, () => + { + d.Disposable = source.Subscribe(observer); + }); + + return d; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs.meta new file mode 100644 index 00000000..cfc56b95 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DelaySubscription.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4f532fc776d5298439cb8f03d52e1211 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs new file mode 100644 index 00000000..b4a1b62f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs @@ -0,0 +1,66 @@ +using System; + +namespace UniRx.Operators +{ + internal class DematerializeObservable : OperatorObservableBase + { + readonly IObservable> source; + + public DematerializeObservable(IObservable> source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Dematerialize(this, observer, cancel).Run(); + } + + class Dematerialize : OperatorObserverBase, T> + { + readonly DematerializeObservable parent; + + public Dematerialize(DematerializeObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(Notification value) + { + switch (value.Kind) + { + case NotificationKind.OnNext: + observer.OnNext(value.Value); + break; + case NotificationKind.OnError: + try { observer.OnError(value.Exception); } + finally { Dispose(); } + break; + case NotificationKind.OnCompleted: + try { observer.OnCompleted(); } + finally { Dispose(); } + break; + default: + break; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs.meta new file mode 100644 index 00000000..fb98104c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Dematerialize.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 80682be7e41afb44581208534f226d38 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs new file mode 100644 index 00000000..2f3ee14a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class DistinctObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IEqualityComparer comparer; + + public DistinctObservable(IObservable source, IEqualityComparer comparer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.comparer = comparer; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Distinct(this, observer, cancel)); + } + + class Distinct : OperatorObserverBase + { + readonly HashSet hashSet; + + public Distinct(DistinctObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + hashSet = (parent.comparer == null) + ? new HashSet() + : new HashSet(parent.comparer); + } + + public override void OnNext(T value) + { + var key = default(T); + var isAdded = false; + try + { + key = value; + isAdded = hashSet.Add(key); + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (isAdded) + { + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + internal class DistinctObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IEqualityComparer comparer; + readonly Func keySelector; + + public DistinctObservable(IObservable source, Func keySelector, IEqualityComparer comparer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.comparer = comparer; + this.keySelector = keySelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Distinct(this, observer, cancel)); + } + + class Distinct : OperatorObserverBase + { + readonly DistinctObservable parent; + readonly HashSet hashSet; + + public Distinct(DistinctObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + hashSet = (parent.comparer == null) + ? new HashSet() + : new HashSet(parent.comparer); + } + + public override void OnNext(T value) + { + var key = default(TKey); + var isAdded = false; + try + { + key = parent.keySelector(value); + isAdded = hashSet.Add(key); + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (isAdded) + { + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs.meta new file mode 100644 index 00000000..d0c962bb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Distinct.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 376a7ed430bff5c4b860af4d23ab6b79 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs new file mode 100644 index 00000000..1c54c216 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class DistinctUntilChangedObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IEqualityComparer comparer; + + public DistinctUntilChangedObservable(IObservable source, IEqualityComparer comparer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.comparer = comparer; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new DistinctUntilChanged(this, observer, cancel)); + } + + class DistinctUntilChanged : OperatorObserverBase + { + readonly DistinctUntilChangedObservable parent; + bool isFirst = true; + T prevKey = default(T); + + public DistinctUntilChanged(DistinctUntilChangedObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + T currentKey; + try + { + currentKey = value; + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + var sameKey = false; + if (isFirst) + { + isFirst = false; + } + else + { + try + { + sameKey = parent.comparer.Equals(currentKey, prevKey); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + } + + if (!sameKey) + { + prevKey = currentKey; + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + internal class DistinctUntilChangedObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IEqualityComparer comparer; + readonly Func keySelector; + + public DistinctUntilChangedObservable(IObservable source, Func keySelector, IEqualityComparer comparer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.comparer = comparer; + this.keySelector = keySelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new DistinctUntilChanged(this, observer, cancel)); + } + + class DistinctUntilChanged : OperatorObserverBase + { + readonly DistinctUntilChangedObservable parent; + bool isFirst = true; + TKey prevKey = default(TKey); + + public DistinctUntilChanged(DistinctUntilChangedObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + TKey currentKey; + try + { + currentKey = parent.keySelector(value); + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + var sameKey = false; + if (isFirst) + { + isFirst = false; + } + else + { + try + { + sameKey = parent.comparer.Equals(currentKey, prevKey); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + } + + if (!sameKey) + { + prevKey = currentKey; + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs.meta new file mode 100644 index 00000000..98e81789 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/DistinctUntilChanged.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a09c4b58f60c22342871c30eaf589f6c +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs new file mode 100644 index 00000000..d1b08a1b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs @@ -0,0 +1,477 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + // Do, DoOnError, DoOnCompleted, DoOnTerminate, DoOnSubscribe, DoOnCancel + + internal class DoObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onNext; + readonly Action onError; + readonly Action onCompleted; + + public DoObservable(IObservable source, Action onNext, Action onError, Action onCompleted) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onNext = onNext; + this.onError = onError; + this.onCompleted = onCompleted; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Do(this, observer, cancel).Run(); + } + + class Do : OperatorObserverBase + { + readonly DoObservable parent; + + public Do(DoObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + try + { + parent.onNext(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try + { + parent.onError(error); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + try + { + parent.onCompleted(); + } + catch (Exception ex) + { + base.observer.OnError(ex); + Dispose(); + return; + } + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + + internal class DoObserverObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObserver observer; + + public DoObserverObservable(IObservable source, IObserver observer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.observer = observer; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Do(this, observer, cancel).Run(); + } + + class Do : OperatorObserverBase + { + readonly DoObserverObservable parent; + + public Do(DoObserverObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + try + { + parent.observer.OnNext(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try + { + parent.observer.OnError(error); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try + { + parent.observer.OnCompleted(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class DoOnErrorObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onError; + + public DoOnErrorObservable(IObservable source, Action onError) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onError = onError; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DoOnError(this, observer, cancel).Run(); + } + + class DoOnError : OperatorObserverBase + { + readonly DoOnErrorObservable parent; + + public DoOnError(DoOnErrorObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try + { + parent.onError(error); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class DoOnCompletedObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onCompleted; + + public DoOnCompletedObservable(IObservable source, Action onCompleted) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onCompleted = onCompleted; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DoOnCompleted(this, observer, cancel).Run(); + } + + class DoOnCompleted : OperatorObserverBase + { + readonly DoOnCompletedObservable parent; + + public DoOnCompleted(DoOnCompletedObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try + { + parent.onCompleted(); + } + catch (Exception ex) + { + base.observer.OnError(ex); + Dispose(); + return; + } + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + + internal class DoOnTerminateObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onTerminate; + + public DoOnTerminateObservable(IObservable source, Action onTerminate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onTerminate = onTerminate; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DoOnTerminate(this, observer, cancel).Run(); + } + + class DoOnTerminate : OperatorObserverBase + { + readonly DoOnTerminateObservable parent; + + public DoOnTerminate(DoOnTerminateObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try + { + parent.onTerminate(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + try + { + parent.onTerminate(); + } + catch (Exception ex) + { + base.observer.OnError(ex); + Dispose(); + return; + } + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + + internal class DoOnSubscribeObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onSubscribe; + + public DoOnSubscribeObservable(IObservable source, Action onSubscribe) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onSubscribe = onSubscribe; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DoOnSubscribe(this, observer, cancel).Run(); + } + + class DoOnSubscribe : OperatorObserverBase + { + readonly DoOnSubscribeObservable parent; + + public DoOnSubscribe(DoOnSubscribeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + try + { + parent.onSubscribe(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return Disposable.Empty; + } + + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + internal class DoOnCancelObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onCancel; + + public DoOnCancelObservable(IObservable source, Action onCancel) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onCancel = onCancel; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DoOnCancel(this, observer, cancel).Run(); + } + + class DoOnCancel : OperatorObserverBase + { + readonly DoOnCancelObservable parent; + bool isCompletedCall = false; + + public DoOnCancel(DoOnCancelObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return StableCompositeDisposable.Create(parent.source.Subscribe(this), Disposable.Create(() => + { + if (!isCompletedCall) + { + parent.onCancel(); + } + })); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + isCompletedCall = true; + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + isCompletedCall = true; + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs.meta new file mode 100644 index 00000000..6933ba38 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Do.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8f99ae8870195e34b8618451a95818e0 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs new file mode 100644 index 00000000..0cd77fd2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs @@ -0,0 +1,83 @@ +using System; + +namespace UniRx.Operators +{ + internal class EmptyObservable : OperatorObservableBase + { + readonly IScheduler scheduler; + + public EmptyObservable(IScheduler scheduler) + : base(false) + { + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Empty(observer, cancel); + + if (scheduler == Scheduler.Immediate) + { + observer.OnCompleted(); + return Disposable.Empty; + } + else + { + return scheduler.Schedule(observer.OnCompleted); + } + } + + class Empty : OperatorObserverBase + { + public Empty(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class ImmutableEmptyObservable : IObservable, IOptimizedObservable + { + internal static ImmutableEmptyObservable Instance = new ImmutableEmptyObservable(); + + ImmutableEmptyObservable() + { + + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnCompleted(); + return Disposable.Empty; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs.meta new file mode 100644 index 00000000..a95898ed --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Empty.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9e9a7050a289d3a4aa17cba89e085135 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs new file mode 100644 index 00000000..ced54f0c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs @@ -0,0 +1,68 @@ +using System; + +namespace UniRx.Operators +{ + internal class FinallyObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action finallyAction; + + public FinallyObservable(IObservable source, Action finallyAction) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.finallyAction = finallyAction; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Finally(this, observer, cancel).Run(); + } + + class Finally : OperatorObserverBase + { + readonly FinallyObservable parent; + + public Finally(FinallyObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + IDisposable subscription; + try + { + subscription = parent.source.Subscribe(this); + } + catch + { + // This behaviour is not same as .NET Official Rx + parent.finallyAction(); + throw; + } + + return StableCompositeDisposable.Create(subscription, Disposable.Create(() => + { + parent.finallyAction(); + })); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs.meta new file mode 100644 index 00000000..835f5288 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Finally.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9ce919d8f2acf2b47a932e850e399d3a +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs new file mode 100644 index 00000000..8233d9e1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs @@ -0,0 +1,166 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class FirstObservable : OperatorObservableBase + { + readonly IObservable source; + readonly bool useDefault; + readonly Func predicate; + + public FirstObservable(IObservable source, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.useDefault = useDefault; + } + + public FirstObservable(IObservable source, Func predicate, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + this.useDefault = useDefault; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate == null) + { + return source.Subscribe(new First(this, observer, cancel)); + } + else + { + return source.Subscribe(new First_(this, observer, cancel)); + } + } + + class First : OperatorObserverBase + { + readonly FirstObservable parent; + bool notPublished; + + public First(FirstObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.notPublished = true; + } + + public override void OnNext(T value) + { + if (notPublished) + { + notPublished = false; + observer.OnNext(value); + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (notPublished) + { + observer.OnNext(default(T)); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (notPublished) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + + // with predicate + class First_ : OperatorObserverBase + { + readonly FirstObservable parent; + bool notPublished; + + public First_(FirstObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.notPublished = true; + } + + public override void OnNext(T value) + { + if (notPublished) + { + bool isPassed; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (isPassed) + { + notPublished = false; + observer.OnNext(value); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (notPublished) + { + observer.OnNext(default(T)); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (notPublished) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs.meta new file mode 100644 index 00000000..589e364f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/First.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8e3093220aeb1d54faa3fca9fe0af6c0 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs new file mode 100644 index 00000000..fb9fab5b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs @@ -0,0 +1,116 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class ForEachAsyncObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Action onNext; + readonly Action onNextWithIndex; + + public ForEachAsyncObservable(IObservable source, Action onNext) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onNext = onNext; + } + + public ForEachAsyncObservable(IObservable source, Action onNext) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.onNextWithIndex = onNext; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (onNext != null) + { + return source.Subscribe(new ForEachAsync(this, observer, cancel)); + } + else + { + return source.Subscribe(new ForEachAsync_(this, observer, cancel)); + } + } + + class ForEachAsync : OperatorObserverBase + { + readonly ForEachAsyncObservable parent; + + public ForEachAsync(ForEachAsyncObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + try + { + parent.onNext(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + observer.OnNext(Unit.Default); + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + + // with index + class ForEachAsync_ : OperatorObserverBase + { + readonly ForEachAsyncObservable parent; + int index = 0; + + public ForEachAsync_(ForEachAsyncObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + try + { + parent.onNextWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + observer.OnNext(Unit.Default); + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs.meta new file mode 100644 index 00000000..688685fa --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ForEachAsync.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5b66ecd2e5290bc4eb8c78a1ccc2d009 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs new file mode 100644 index 00000000..7a085432 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + // FromEvent, FromEventPattern + + internal class FromEventPatternObservable : OperatorObservableBase> + where TEventArgs : EventArgs + { + readonly Func, TDelegate> conversion; + readonly Action addHandler; + readonly Action removeHandler; + + public FromEventPatternObservable(Func, TDelegate> conversion, Action addHandler, Action removeHandler) + : base(false) + { + this.conversion = conversion; + this.addHandler = addHandler; + this.removeHandler = removeHandler; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + var fe = new FromEventPattern(this, observer); + return fe.Register() ? fe : Disposable.Empty; + } + + class FromEventPattern : IDisposable + { + readonly FromEventPatternObservable parent; + readonly IObserver> observer; + TDelegate handler; + + public FromEventPattern(FromEventPatternObservable parent, IObserver> observer) + { + this.parent = parent; + this.observer = observer; + } + + public bool Register() + { + handler = parent.conversion(OnNext); + try + { + parent.addHandler(handler); + } + catch (Exception ex) + { + observer.OnError(ex); + return false; + } + return true; + } + + void OnNext(object sender, TEventArgs eventArgs) + { + observer.OnNext(new EventPattern(sender, eventArgs)); + } + + public void Dispose() + { + if (handler != null) + { + parent.removeHandler(handler); + handler = default(TDelegate); + } + } + } + } + + internal class FromEventObservable : OperatorObservableBase + { + readonly Func conversion; + readonly Action addHandler; + readonly Action removeHandler; + + public FromEventObservable(Func conversion, Action addHandler, Action removeHandler) + : base(false) + { + this.conversion = conversion; + this.addHandler = addHandler; + this.removeHandler = removeHandler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var fe = new FromEvent(this, observer); + return fe.Register() ? fe : Disposable.Empty; + } + + class FromEvent : IDisposable + { + readonly FromEventObservable parent; + readonly IObserver observer; + TDelegate handler; + + public FromEvent(FromEventObservable parent, IObserver observer) + { + this.parent = parent; + this.observer = observer; + } + + public bool Register() + { + handler = parent.conversion(OnNext); + + try + { + parent.addHandler(handler); + } + catch (Exception ex) + { + observer.OnError(ex); + return false; + } + return true; + } + + void OnNext() + { + observer.OnNext(Unit.Default); + } + + public void Dispose() + { + if (handler != null) + { + parent.removeHandler(handler); + handler = default(TDelegate); + } + } + } + } + + internal class FromEventObservable : OperatorObservableBase + { + readonly Func, TDelegate> conversion; + readonly Action addHandler; + readonly Action removeHandler; + + public FromEventObservable(Func, TDelegate> conversion, Action addHandler, Action removeHandler) + : base(false) + { + this.conversion = conversion; + this.addHandler = addHandler; + this.removeHandler = removeHandler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var fe = new FromEvent(this, observer); + return fe.Register() ? fe : Disposable.Empty; + } + + class FromEvent : IDisposable + { + readonly FromEventObservable parent; + readonly IObserver observer; + TDelegate handler; + + public FromEvent(FromEventObservable parent, IObserver observer) + { + this.parent = parent; + this.observer = observer; + } + + public bool Register() + { + handler = parent.conversion(OnNext); + + try + { + parent.addHandler(handler); + } + catch (Exception ex) + { + observer.OnError(ex); + return false; + } + return true; + } + + void OnNext(TEventArgs args) + { + observer.OnNext(args); + } + + public void Dispose() + { + if (handler != null) + { + parent.removeHandler(handler); + handler = default(TDelegate); + } + } + } + } + + internal class FromEventObservable : OperatorObservableBase + { + readonly Action addHandler; + readonly Action removeHandler; + + public FromEventObservable(Action addHandler, Action removeHandler) + : base(false) + { + this.addHandler = addHandler; + this.removeHandler = removeHandler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var fe = new FromEvent(this, observer); + return fe.Register() ? fe : Disposable.Empty; + } + + class FromEvent : IDisposable + { + readonly FromEventObservable parent; + readonly IObserver observer; + Action handler; + + public FromEvent(FromEventObservable parent, IObserver observer) + { + this.parent = parent; + this.observer = observer; + this.handler = OnNext; + } + + public bool Register() + { + try + { + parent.addHandler(handler); + } + catch (Exception ex) + { + observer.OnError(ex); + return false; + } + return true; + } + + void OnNext() + { + observer.OnNext(Unit.Default); + } + + public void Dispose() + { + if (handler != null) + { + parent.removeHandler(handler); + handler = null; + } + } + } + } + + internal class FromEventObservable_ : OperatorObservableBase + { + readonly Action> addHandler; + readonly Action> removeHandler; + + public FromEventObservable_(Action> addHandler, Action> removeHandler) + : base(false) + { + this.addHandler = addHandler; + this.removeHandler = removeHandler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var fe = new FromEvent(this, observer); + return fe.Register() ? fe : Disposable.Empty; + } + + class FromEvent : IDisposable + { + readonly FromEventObservable_ parent; + readonly IObserver observer; + Action handler; + + public FromEvent(FromEventObservable_ parent, IObserver observer) + { + this.parent = parent; + this.observer = observer; + this.handler = OnNext; + } + + public bool Register() + { + try + { + parent.addHandler(handler); + } + catch (Exception ex) + { + observer.OnError(ex); + return false; + } + return true; + } + + void OnNext(T value) + { + observer.OnNext(value); + } + + public void Dispose() + { + if (handler != null) + { + parent.removeHandler(handler); + handler = null; + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs.meta new file mode 100644 index 00000000..a9f8e622 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/FromEvent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05fcc5083e94e704ca8f059e4e535ffa +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs new file mode 100644 index 00000000..ba21bdca --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class GroupedObservable : IGroupedObservable + { + readonly TKey key; + readonly IObservable subject; + readonly RefCountDisposable refCount; + + public TKey Key + { + get { return key; } + } + + public GroupedObservable(TKey key, ISubject subject, RefCountDisposable refCount) + { + this.key = key; + this.subject = subject; + this.refCount = refCount; + } + + public IDisposable Subscribe(IObserver observer) + { + var release = refCount.GetDisposable(); + var subscription = subject.Subscribe(observer); + return StableCompositeDisposable.Create(release, subscription); + } + } + + internal class GroupByObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly Func keySelector; + readonly Func elementSelector; + readonly int? capacity; + readonly IEqualityComparer comparer; + + public GroupByObservable(IObservable source, Func keySelector, Func elementSelector, int? capacity, IEqualityComparer comparer) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.keySelector = keySelector; + this.elementSelector = elementSelector; + this.capacity = capacity; + this.comparer = comparer; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new GroupBy(this, observer, cancel).Run(); + } + + class GroupBy : OperatorObserverBase> + { + readonly GroupByObservable parent; + readonly Dictionary> map; + ISubject nullKeySubject; + + CompositeDisposable groupDisposable; + RefCountDisposable refCountDisposable; + + public GroupBy(GroupByObservable parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + if (parent.capacity.HasValue) + { + map = new Dictionary>(parent.capacity.Value, parent.comparer); + } + else + { + map = new Dictionary>(parent.comparer); + } + } + + public IDisposable Run() + { + groupDisposable = new CompositeDisposable(); + refCountDisposable = new RefCountDisposable(groupDisposable); + + groupDisposable.Add(parent.source.Subscribe(this)); + + return refCountDisposable; + } + + public override void OnNext(TSource value) + { + var key = default(TKey); + try + { + key = parent.keySelector(value); + } + catch (Exception exception) + { + Error(exception); + return; + } + + var fireNewMapEntry = false; + var writer = default(ISubject); + try + { + if (key == null) + { + if (nullKeySubject == null) + { + nullKeySubject = new Subject(); + fireNewMapEntry = true; + } + + writer = nullKeySubject; + } + else + { + if (!map.TryGetValue(key, out writer)) + { + writer = new Subject(); + map.Add(key, writer); + fireNewMapEntry = true; + } + } + } + catch (Exception exception) + { + Error(exception); + return; + } + + if (fireNewMapEntry) + { + var group = new GroupedObservable(key, writer, refCountDisposable); + observer.OnNext(group); + } + + var element = default(TElement); + try + { + element = parent.elementSelector(value); + } + catch (Exception exception) + { + Error(exception); + return; + } + + writer.OnNext(element); + } + + public override void OnError(Exception error) + { + Error(error); + } + + public override void OnCompleted() + { + try + { + if (nullKeySubject != null) nullKeySubject.OnCompleted(); + + foreach (var s in map.Values) + { + s.OnCompleted(); + } + + observer.OnCompleted(); + } + finally + { + Dispose(); + } + } + + void Error(Exception exception) + { + try + { + if (nullKeySubject != null) nullKeySubject.OnError(exception); + + foreach (var s in map.Values) + { + s.OnError(exception); + } + + observer.OnError(exception); + } + finally + { + Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs.meta new file mode 100644 index 00000000..96c5b0bc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/GroupBy.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7345fc4a6df05ca47ab89ec819bccde6 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs new file mode 100644 index 00000000..bd3c0b7d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs @@ -0,0 +1,44 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class IgnoreElementsObservable : OperatorObservableBase + { + readonly IObservable source; + + public IgnoreElementsObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new IgnoreElements(observer, cancel)); + } + + class IgnoreElements : OperatorObserverBase + { + public IgnoreElements(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs.meta new file mode 100644 index 00000000..01d716a5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/IgnoreElements.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d6c8ca210619da74b92cbdb3e8c58127 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs new file mode 100644 index 00000000..5c04e9d0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs @@ -0,0 +1,165 @@ +using System; + +namespace UniRx.Operators +{ + internal class LastObservable : OperatorObservableBase + { + readonly IObservable source; + readonly bool useDefault; + readonly Func predicate; + + public LastObservable(IObservable source, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.useDefault = useDefault; + } + + public LastObservable(IObservable source, Func predicate, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + this.useDefault = useDefault; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate == null) + { + return source.Subscribe(new Last(this, observer, cancel)); + } + else + { + return source.Subscribe(new Last_(this, observer, cancel)); + } + } + + class Last : OperatorObserverBase + { + readonly LastObservable parent; + bool notPublished; + T lastValue; + + public Last(LastObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.notPublished = true; + } + + public override void OnNext(T value) + { + notPublished = false; + lastValue = value; + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (notPublished) + { + observer.OnNext(default(T)); + } + else + { + observer.OnNext(lastValue); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (notPublished) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + observer.OnNext(lastValue); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + + class Last_ : OperatorObserverBase + { + readonly LastObservable parent; + bool notPublished; + T lastValue; + + public Last_(LastObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.notPublished = true; + } + + public override void OnNext(T value) + { + bool isPassed; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (isPassed) + { + notPublished = false; + lastValue = value; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (notPublished) + { + observer.OnNext(default(T)); + } + else + { + observer.OnNext(lastValue); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (notPublished) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + observer.OnNext(lastValue); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs.meta new file mode 100644 index 00000000..a8a5ba57 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Last.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 696780c8759162d4b996683ec13d7e0b +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs new file mode 100644 index 00000000..8c5268e9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs @@ -0,0 +1,53 @@ +using System; + +namespace UniRx.Operators +{ + internal class MaterializeObservable : OperatorObservableBase> + { + readonly IObservable source; + + public MaterializeObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new Materialize(this, observer, cancel).Run(); + } + + class Materialize : OperatorObserverBase> + { + readonly MaterializeObservable parent; + + public Materialize(MaterializeObservable parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + observer.OnNext(Notification.CreateOnNext(value)); + } + + public override void OnError(Exception error) + { + observer.OnNext(Notification.CreateOnError(error)); + try { observer.OnCompleted(); } finally { Dispose(); } + } + + public override void OnCompleted() + { + observer.OnNext(Notification.CreateOnCompleted()); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs.meta new file mode 100644 index 00000000..32254304 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Materialize.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 09d3ba9e6d5fe4643bbf0df943652908 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs new file mode 100644 index 00000000..b30c8a23 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class MergeObservable : OperatorObservableBase + { + private readonly IObservable> sources; + private readonly int maxConcurrent; + + public MergeObservable(IObservable> sources, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.sources = sources; + } + + public MergeObservable(IObservable> sources, int maxConcurrent, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.sources = sources; + this.maxConcurrent = maxConcurrent; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (maxConcurrent > 0) + { + return new MergeConcurrentObserver(this, observer, cancel).Run(); + } + else + { + return new MergeOuterObserver(this, observer, cancel).Run(); + } + } + + class MergeOuterObserver : OperatorObserverBase, T> + { + readonly MergeObservable parent; + + CompositeDisposable collectionDisposable; + SingleAssignmentDisposable sourceDisposable; + object gate = new object(); + bool isStopped = false; + + public MergeOuterObserver(MergeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.sources.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(IObservable value) + { + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new Merge(this, disposable); + disposable.Disposable = value.Subscribe(collectionObserver); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + isStopped = true; + if (collectionDisposable.Count == 1) + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + else + { + sourceDisposable.Dispose(); + } + } + + class Merge : OperatorObserverBase + { + readonly MergeOuterObserver parent; + readonly IDisposable cancel; + + public Merge(MergeOuterObserver parent, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.cancel = cancel; + } + + public override void OnNext(T value) + { + lock (parent.gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + if (parent.isStopped && parent.collectionDisposable.Count == 1) + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + + class MergeConcurrentObserver : OperatorObserverBase, T> + { + readonly MergeObservable parent; + + CompositeDisposable collectionDisposable; + SingleAssignmentDisposable sourceDisposable; + object gate = new object(); + bool isStopped = false; + + // concurrency + Queue> q; + int activeCount; + + public MergeConcurrentObserver(MergeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + q = new Queue>(); + activeCount = 0; + + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.sources.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(IObservable value) + { + lock (gate) + { + if (activeCount < parent.maxConcurrent) + { + activeCount++; + Subscribe(value); + } + else + { + q.Enqueue(value); + } + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + lock (gate) + { + isStopped = true; + if (activeCount == 0) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + else + { + sourceDisposable.Dispose(); + } + } + } + + void Subscribe(IObservable innerSource) + { + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new Merge(this, disposable); + disposable.Disposable = innerSource.Subscribe(collectionObserver); + } + + class Merge : OperatorObserverBase + { + readonly MergeConcurrentObserver parent; + readonly IDisposable cancel; + + public Merge(MergeConcurrentObserver parent, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.cancel = cancel; + } + + public override void OnNext(T value) + { + lock (parent.gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + lock (parent.gate) + { + if (parent.q.Count > 0) + { + var source = parent.q.Dequeue(); + parent.Subscribe(source); + } + else + { + parent.activeCount--; + if (parent.isStopped && parent.activeCount == 0) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs.meta new file mode 100644 index 00000000..a35b37a0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Merge.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 94158fab525468d4e896a62f633257e6 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs new file mode 100644 index 00000000..858408f6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs @@ -0,0 +1,32 @@ +using System; + +namespace UniRx.Operators +{ + internal class NeverObservable : OperatorObservableBase + { + public NeverObservable() + : base(false) + { + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return Disposable.Empty; + } + } + + internal class ImmutableNeverObservable : IObservable, IOptimizedObservable + { + internal static ImmutableNeverObservable Instance = new ImmutableNeverObservable(); + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + return Disposable.Empty; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs.meta new file mode 100644 index 00000000..83a5c2f7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Never.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b5db8d5c73883214abaf3715002da256 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs new file mode 100644 index 00000000..d8e3bd5b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class ObserveOnObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IScheduler scheduler; + + public ObserveOnObservable(IObservable source, IScheduler scheduler) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var queueing = scheduler as ISchedulerQueueing; + if (queueing == null) + { + return new ObserveOn(this, observer, cancel).Run(); + } + else + { + return new ObserveOn_(this, queueing, observer, cancel).Run(); + } + } + + class ObserveOn : OperatorObserverBase + { + class SchedulableAction : IDisposable + { + public Notification data; + public LinkedListNode node; + public IDisposable schedule; + + public void Dispose() + { + if (schedule != null) + schedule.Dispose(); + schedule = null; + + if (node.List != null) + { + node.List.Remove(node); + } + } + + public bool IsScheduled { get { return schedule != null; } } + } + + readonly ObserveOnObservable parent; + readonly LinkedList actions = new LinkedList(); + bool isDisposed; + + public ObserveOn(ObserveOnObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + isDisposed = false; + + var sourceDisposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(sourceDisposable, Disposable.Create(() => + { + lock (actions) + { + isDisposed = true; + + while (actions.Count > 0) + { + // Dispose will both cancel the action (if not already running) + // and remove it from 'actions' + actions.First.Value.Dispose(); + } + } + })); + } + + public override void OnNext(T value) + { + QueueAction(new Notification.OnNextNotification(value)); + } + + public override void OnError(Exception error) + { + QueueAction(new Notification.OnErrorNotification(error)); + } + + public override void OnCompleted() + { + QueueAction(new Notification.OnCompletedNotification()); + } + + private void QueueAction(Notification data) + { + var action = new SchedulableAction { data = data }; + lock (actions) + { + if (isDisposed) return; + + action.node = actions.AddLast(action); + ProcessNext(); + } + } + + private void ProcessNext() + { + lock (actions) + { + if (actions.Count == 0 || isDisposed) + return; + + var action = actions.First.Value; + + if (action.IsScheduled) + return; + + action.schedule = parent.scheduler.Schedule(() => + { + try + { + switch (action.data.Kind) + { + case NotificationKind.OnNext: + observer.OnNext(action.data.Value); + break; + case NotificationKind.OnError: + observer.OnError(action.data.Exception); + break; + case NotificationKind.OnCompleted: + observer.OnCompleted(); + break; + } + } + finally + { + lock (actions) + { + action.Dispose(); + } + + if (action.data.Kind == NotificationKind.OnNext) + ProcessNext(); + else + Dispose(); + } + }); + } + } + } + + class ObserveOn_ : OperatorObserverBase + { + readonly ObserveOnObservable parent; + readonly ISchedulerQueueing scheduler; + readonly BooleanDisposable isDisposed; + readonly Action onNext; + + public ObserveOn_(ObserveOnObservable parent, ISchedulerQueueing scheduler, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.scheduler = scheduler; + this.isDisposed = new BooleanDisposable(); + this.onNext = new Action(OnNext_); // cache delegate + } + + public IDisposable Run() + { + var sourceDisposable = parent.source.Subscribe(this); + return StableCompositeDisposable.Create(sourceDisposable, isDisposed); + } + + void OnNext_(T value) + { + base.observer.OnNext(value); + } + + void OnError_(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + + void OnCompleted_(Unit _) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + + public override void OnNext(T value) + { + scheduler.ScheduleQueueing(isDisposed, value, onNext); + } + + public override void OnError(Exception error) + { + scheduler.ScheduleQueueing(isDisposed, error, OnError_); + } + + public override void OnCompleted() + { + scheduler.ScheduleQueueing(isDisposed, Unit.Default, OnCompleted_); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs.meta new file mode 100644 index 00000000..50118591 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ObserveOn.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39df784f492c7404286d05b09a840705 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs new file mode 100644 index 00000000..79207c5b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs @@ -0,0 +1,47 @@ +using System; + +namespace UniRx.Operators +{ + internal class OfTypeObservable : OperatorObservableBase + { + readonly IObservable source; + + public OfTypeObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new OfType(observer, cancel)); + } + + class OfType : OperatorObserverBase + { + public OfType(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(TSource value) + { + if (value is TResult) + { + var castValue = (TResult)(object)value; + observer.OnNext(castValue); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs.meta new file mode 100644 index 00000000..70041982 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OfType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 981fd4bf7704404459a0deed254a03e5 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs new file mode 100644 index 00000000..35337aeb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs @@ -0,0 +1,42 @@ +using System; + +namespace UniRx.Operators +{ + // implements note : all field must be readonly. + public abstract class OperatorObservableBase : IObservable, IOptimizedObservable + { + readonly bool isRequiredSubscribeOnCurrentThread; + + public OperatorObservableBase(bool isRequiredSubscribeOnCurrentThread) + { + this.isRequiredSubscribeOnCurrentThread = isRequiredSubscribeOnCurrentThread; + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return isRequiredSubscribeOnCurrentThread; + } + + public IDisposable Subscribe(IObserver observer) + { + var subscription = new SingleAssignmentDisposable(); + + // note: + // does not make the safe observer, it breaks exception durability. + // var safeObserver = Observer.CreateAutoDetachObserver(observer, subscription); + + if (isRequiredSubscribeOnCurrentThread && Scheduler.IsCurrentThreadSchedulerScheduleRequired) + { + Scheduler.CurrentThread.Schedule(() => subscription.Disposable = SubscribeCore(observer, subscription)); + } + else + { + subscription.Disposable = SubscribeCore(observer, subscription); + } + + return subscription; + } + + protected abstract IDisposable SubscribeCore(IObserver observer, IDisposable cancel); + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs.meta new file mode 100644 index 00000000..5772193d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObservableBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1b94a1a0ae5d509488c6242454216bdb +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs new file mode 100644 index 00000000..a13affeb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading; + +namespace UniRx.Operators +{ + public abstract class OperatorObserverBase : IDisposable, IObserver + { + protected internal volatile IObserver observer; + IDisposable cancel; + + public OperatorObserverBase(IObserver observer, IDisposable cancel) + { + this.observer = observer; + this.cancel = cancel; + } + + public abstract void OnNext(TSource value); + + public abstract void OnError(Exception error); + + public abstract void OnCompleted(); + + public void Dispose() + { + observer = UniRx.InternalUtil.EmptyObserver.Instance; + var target = System.Threading.Interlocked.Exchange(ref cancel, null); + if (target != null) + { + target.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs.meta new file mode 100644 index 00000000..9f2b45d4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/OperatorObserverBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 258901a4513be8f4a8bfcca91e70bb12 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs new file mode 100644 index 00000000..481ee1a5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs @@ -0,0 +1,120 @@ +using System; + +namespace UniRx.Operators +{ + internal class PairwiseObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func selector; + + public PairwiseObservable(IObservable source, Func selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Pairwise(this, observer, cancel)); + } + + class Pairwise : OperatorObserverBase + { + readonly PairwiseObservable parent; + T prev = default(T); + bool isFirst = true; + + public Pairwise(PairwiseObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + if (isFirst) + { + isFirst = false; + prev = value; + return; + } + + TR v; + try + { + v = parent.selector(prev, value); + prev = value; + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + observer.OnNext(v); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + internal class PairwiseObservable : OperatorObservableBase> + { + readonly IObservable source; + + public PairwiseObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new Pairwise(observer, cancel)); + } + + class Pairwise : OperatorObserverBase> + { + T prev = default(T); + bool isFirst = true; + + public Pairwise(IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + if (isFirst) + { + isFirst = false; + prev = value; + return; + } + + var pair = new Pair(prev, value); + prev = value; + observer.OnNext(pair); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs.meta new file mode 100644 index 00000000..16c3afa9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/PairWise.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f66e4871304e6e74d8548d597457e53c +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs new file mode 100644 index 00000000..472926d5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs @@ -0,0 +1,89 @@ +using System; + +namespace UniRx.Operators +{ + internal class RangeObservable : OperatorObservableBase + { + readonly int start; + readonly int count; + readonly IScheduler scheduler; + + public RangeObservable(int start, int count, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + if (count < 0) throw new ArgumentOutOfRangeException("count < 0"); + + this.start = start; + this.count = count; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Range(observer, cancel); + + if (scheduler == Scheduler.Immediate) + { + for (int i = 0; i < count; i++) + { + int v = start + i; + observer.OnNext(v); + } + observer.OnCompleted(); + + return Disposable.Empty; + } + else + { + var i = 0; + return scheduler.Schedule((Action self) => + { + if (i < count) + { + int v = start + i; + observer.OnNext(v); + i++; + self(); + } + else + { + observer.OnCompleted(); + } + }); + } + } + + class Range : OperatorObserverBase + { + public Range(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(int value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs.meta new file mode 100644 index 00000000..30663625 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Range.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2249fbe589c8d3042ac201c1ab4be76f +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs new file mode 100644 index 00000000..668d279f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs @@ -0,0 +1,77 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class RefCountObservable : OperatorObservableBase + { + readonly IConnectableObservable source; + readonly object gate = new object(); + int refCount = 0; + IDisposable connection; + + public RefCountObservable(IConnectableObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new RefCount(this, observer, cancel).Run(); + } + + class RefCount : OperatorObserverBase + { + readonly RefCountObservable parent; + + public RefCount(RefCountObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var subcription = parent.source.Subscribe(this); + + lock (parent.gate) + { + if (++parent.refCount == 1) + { + parent.connection = parent.source.Connect(); + } + } + + return Disposable.Create(() => + { + subcription.Dispose(); + + lock (parent.gate) + { + if (--parent.refCount == 0) + { + parent.connection.Dispose(); + } + } + }); + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs.meta new file mode 100644 index 00000000..0fb0574e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RefCount.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 17a77b422aa699d4d8cfbf6de804d238 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs new file mode 100644 index 00000000..41a53f97 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs @@ -0,0 +1,99 @@ +using System; + +namespace UniRx.Operators +{ + internal class RepeatObservable : OperatorObservableBase + { + readonly T value; + readonly int? repeatCount; + readonly IScheduler scheduler; + + public RepeatObservable(T value, int? repeatCount, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.value = value; + this.repeatCount = repeatCount; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Repeat(observer, cancel); + + if (repeatCount == null) + { + return scheduler.Schedule((Action self) => + { + observer.OnNext(value); + self(); + }); + } + else + { + if (scheduler == Scheduler.Immediate) + { + var count = this.repeatCount.Value; + for (int i = 0; i < count; i++) + { + observer.OnNext(value); + } + observer.OnCompleted(); + return Disposable.Empty; + } + else + { + var currentCount = this.repeatCount.Value; + return scheduler.Schedule((Action self) => + { + if (currentCount > 0) + { + observer.OnNext(value); + currentCount--; + } + + if (currentCount == 0) + { + observer.OnCompleted(); + return; + } + + self(); + }); + } + } + } + + class Repeat : OperatorObserverBase + { + public Repeat(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs.meta new file mode 100644 index 00000000..02c5ceb8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Repeat.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 63930706f2ea6e847866fc6d914b0d2e +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs new file mode 100644 index 00000000..b4412bbc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class RepeatSafeObservable : OperatorObservableBase + { + readonly IEnumerable> sources; + + public RepeatSafeObservable(IEnumerable> sources, bool isRequiredSubscribeOnCurrentThread) + : base(isRequiredSubscribeOnCurrentThread) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new RepeatSafe(this, observer, cancel).Run(); + } + + class RepeatSafe : OperatorObserverBase + { + readonly RepeatSafeObservable parent; + readonly object gate = new object(); + + IEnumerator> e; + SerialDisposable subscription; + Action nextSelf; + bool isDisposed; + bool isRunNext; + + public RepeatSafe(RepeatSafeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + isDisposed = false; + isRunNext = false; + e = parent.sources.GetEnumerator(); + subscription = new SerialDisposable(); + + var schedule = Scheduler.DefaultSchedulers.TailRecursion.Schedule(RecursiveRun); + + return StableCompositeDisposable.Create(schedule, subscription, Disposable.Create(() => + { + lock (gate) + { + isDisposed = true; + e.Dispose(); + } + })); + } + + void RecursiveRun(Action self) + { + lock (gate) + { + this.nextSelf = self; + if (isDisposed) return; + + var current = default(IObservable); + var hasNext = false; + var ex = default(Exception); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + if (current == null) throw new InvalidOperationException("sequence is null."); + } + else + { + e.Dispose(); + } + } + catch (Exception exception) + { + ex = exception; + e.Dispose(); + } + + if (ex != null) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (!hasNext) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + + var source = e.Current; + var d = new SingleAssignmentDisposable(); + subscription.Disposable = d; + d.Disposable = source.Subscribe(this); + } + } + + public override void OnNext(T value) + { + isRunNext = true; + base.observer.OnNext(value); + } + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (isRunNext && !isDisposed) + { + isRunNext = false; + this.nextSelf(); + } + else + { + e.Dispose(); + if (!isDisposed) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs.meta new file mode 100644 index 00000000..3db57bdd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/RepeatSafe.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6458fa5124443dc4bb95ad3d0b743934 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs new file mode 100644 index 00000000..abb6b8e3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs @@ -0,0 +1,205 @@ +using System; + +namespace UniRx.Operators +{ + internal class ReturnObservable : OperatorObservableBase + { + readonly T value; + readonly IScheduler scheduler; + + public ReturnObservable(T value, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.value = value; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Return(observer, cancel); + + if (scheduler == Scheduler.Immediate) + { + observer.OnNext(value); + observer.OnCompleted(); + return Disposable.Empty; + } + else + { + return scheduler.Schedule(() => + { + observer.OnNext(value); + observer.OnCompleted(); + }); + } + } + + class Return : OperatorObserverBase + { + public Return(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class ImmediateReturnObservable : IObservable, IOptimizedObservable + { + readonly T value; + + public ImmediateReturnObservable(T value) + { + this.value = value; + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(value); + observer.OnCompleted(); + return Disposable.Empty; + } + } + + internal class ImmutableReturnUnitObservable : IObservable, IOptimizedObservable + { + internal static ImmutableReturnUnitObservable Instance = new ImmutableReturnUnitObservable(); + + ImmutableReturnUnitObservable() + { + + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(Unit.Default); + observer.OnCompleted(); + return Disposable.Empty; + } + } + + internal class ImmutableReturnTrueObservable : IObservable, IOptimizedObservable + { + internal static ImmutableReturnTrueObservable Instance = new ImmutableReturnTrueObservable(); + + ImmutableReturnTrueObservable() + { + + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(true); + observer.OnCompleted(); + return Disposable.Empty; + } + } + + internal class ImmutableReturnFalseObservable : IObservable, IOptimizedObservable + { + internal static ImmutableReturnFalseObservable Instance = new ImmutableReturnFalseObservable(); + + ImmutableReturnFalseObservable() + { + + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(false); + observer.OnCompleted(); + return Disposable.Empty; + } + } + + internal class ImmutableReturnInt32Observable : IObservable, IOptimizedObservable + { + static ImmutableReturnInt32Observable[] Caches = new ImmutableReturnInt32Observable[] + { + new ImmutableReturnInt32Observable(-1), + new ImmutableReturnInt32Observable(0), + new ImmutableReturnInt32Observable(1), + new ImmutableReturnInt32Observable(2), + new ImmutableReturnInt32Observable(3), + new ImmutableReturnInt32Observable(4), + new ImmutableReturnInt32Observable(5), + new ImmutableReturnInt32Observable(6), + new ImmutableReturnInt32Observable(7), + new ImmutableReturnInt32Observable(8), + new ImmutableReturnInt32Observable(9), + }; + + public static IObservable GetInt32Observable(int x) + { + if (-1 <= x && x <= 9) + { + return Caches[x + 1]; + } + + return new ImmediateReturnObservable(x); + } + + readonly int x; + + ImmutableReturnInt32Observable(int x) + { + this.x = x; + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + public IDisposable Subscribe(IObserver observer) + { + observer.OnNext(x); + observer.OnCompleted(); + return Disposable.Empty; + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs.meta new file mode 100644 index 00000000..9649b225 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Return.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 25648117feeec6043bd39468bfab62b7 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs new file mode 100644 index 00000000..18232a68 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + internal class SampleObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TimeSpan interval; + readonly IScheduler scheduler; + + public SampleObservable(IObservable source, TimeSpan interval, IScheduler scheduler) + : base(source.IsRequiredSubscribeOnCurrentThread() || scheduler == Scheduler.CurrentThread) + { + this.source = source; + this.interval = interval; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Sample(this, observer, cancel).Run(); + } + + class Sample : OperatorObserverBase + { + readonly SampleObservable parent; + readonly object gate = new object(); + T latestValue = default(T); + bool isUpdated = false; + bool isCompleted = false; + SingleAssignmentDisposable sourceSubscription; + + public Sample(SampleObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + + IDisposable scheduling; + var periodicScheduler = parent.scheduler as ISchedulerPeriodic; + if (periodicScheduler != null) + { + scheduling = periodicScheduler.SchedulePeriodic(parent.interval, OnNextTick); + } + else + { + scheduling = parent.scheduler.Schedule(parent.interval, OnNextRecursive); + } + + return StableCompositeDisposable.Create(sourceSubscription, scheduling); + } + + void OnNextTick() + { + lock (gate) + { + if (isUpdated) + { + var value = latestValue; + isUpdated = false; + observer.OnNext(value); + } + if (isCompleted) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + void OnNextRecursive(Action self) + { + lock (gate) + { + if (isUpdated) + { + var value = latestValue; + isUpdated = false; + observer.OnNext(value); + } + if (isCompleted) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + self(parent.interval); + } + + public override void OnNext(T value) + { + lock (gate) + { + latestValue = value; + isUpdated = true; + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { base.observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + isCompleted = true; + sourceSubscription.Dispose(); + } + } + } + } + + internal class SampleObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObservable intervalSource; + + public SampleObservable(IObservable source, IObservable intervalSource) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.intervalSource = intervalSource; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Sample(this, observer, cancel).Run(); + } + + class Sample : OperatorObserverBase + { + readonly SampleObservable parent; + readonly object gate = new object(); + T latestValue = default(T); + bool isUpdated = false; + bool isCompleted = false; + SingleAssignmentDisposable sourceSubscription; + + public Sample( + SampleObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + var scheduling = this.parent.intervalSource.Subscribe(new SampleTick(this)); + + return StableCompositeDisposable.Create(sourceSubscription, scheduling); + } + + public override void OnNext(T value) + { + lock (gate) + { + latestValue = value; + isUpdated = true; + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { base.observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + isCompleted = true; + sourceSubscription.Dispose(); + } + } + + class SampleTick : IObserver + { + readonly Sample parent; + + public SampleTick(Sample parent) + { + this.parent = parent; + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (parent.isUpdated) + { + parent.isUpdated = false; + parent.observer.OnNext(parent.latestValue); + } + if (parent.isCompleted) + { + try { parent.observer.OnCompleted(); } finally { parent.Dispose(); } + } + } + } + + public void OnError(Exception error) + { + } + + public void OnNext(T2 _) + { + lock (parent.gate) + { + if (parent.isUpdated) + { + var value = parent.latestValue; + parent.isUpdated = false; + parent.observer.OnNext(value); + } + if (parent.isCompleted) + { + try { parent.observer.OnCompleted(); } finally { parent.Dispose(); } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs.meta new file mode 100644 index 00000000..4b9ab0a0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Sample.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 414e918f6a4dfc549b2a8c916a6325e1 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs new file mode 100644 index 00000000..0139ab29 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs @@ -0,0 +1,139 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class ScanObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func accumulator; + + public ScanObservable(IObservable source, Func accumulator) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.accumulator = accumulator; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Scan(this, observer, cancel)); + } + + class Scan : OperatorObserverBase + { + readonly ScanObservable parent; + TSource accumulation; + bool isFirst; + + public Scan(ScanObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.isFirst = true; + } + + public override void OnNext(TSource value) + { + if (isFirst) + { + isFirst = false; + accumulation = value; + } + else + { + try + { + accumulation = parent.accumulator(accumulation, value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + } + + observer.OnNext(accumulation); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class ScanObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TAccumulate seed; + readonly Func accumulator; + + public ScanObservable(IObservable source, TAccumulate seed, Func accumulator) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.seed = seed; + this.accumulator = accumulator; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Scan(this, observer, cancel)); + } + + class Scan : OperatorObserverBase + { + readonly ScanObservable parent; + TAccumulate accumulation; + bool isFirst; + + public Scan(ScanObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.isFirst = true; + } + + public override void OnNext(TSource value) + { + if (isFirst) + { + isFirst = false; + accumulation = parent.seed; + } + + try + { + accumulation = parent.accumulator(accumulation, value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + observer.OnNext(accumulation); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs.meta new file mode 100644 index 00000000..b8acfa35 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Scan.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 461fecd0ef4d48c4d95aae68c2ca2c1c +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs new file mode 100644 index 00000000..73464ce6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs @@ -0,0 +1,146 @@ +using System; + +namespace UniRx.Operators +{ + internal interface ISelect + { + // IObservable CombineSelector(Func selector); + IObservable CombinePredicate(Func predicate); + } + + internal class SelectObservable : OperatorObservableBase, ISelect + { + readonly IObservable source; + readonly Func selector; + readonly Func selectorWithIndex; + + public SelectObservable(IObservable source, Func selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selector = selector; + } + + public SelectObservable(IObservable source, Func selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selectorWithIndex = selector; + } + + // sometimes cause "which no ahead of time (AOT) code was generated." on IL2CPP... + + //public IObservable CombineSelector(Func combineSelector) + //{ + // if (this.selector != null) + // { + // return new Select(source, x => combineSelector(this.selector(x))); + // } + // else + // { + // return new Select(this, combineSelector); + // } + //} + + public IObservable CombinePredicate(Func predicate) + { + if (this.selector != null) + { + return new SelectWhereObservable(this.source, this.selector, predicate); + } + else + { + return new WhereObservable(this, predicate); // can't combine + } + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (selector != null) + { + return source.Subscribe(new Select(this, observer, cancel)); + } + else + { + return source.Subscribe(new Select_(this, observer, cancel)); + } + } + + class Select : OperatorObserverBase + { + readonly SelectObservable parent; + + public Select(SelectObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + var v = default(TR); + try + { + v = parent.selector(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + observer.OnNext(v); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + // with Index + class Select_ : OperatorObserverBase + { + readonly SelectObservable parent; + int index; + + public Select_(SelectObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + this.index = 0; + } + + public override void OnNext(T value) + { + var v = default(TR); + try + { + v = parent.selectorWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + observer.OnNext(v); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs.meta new file mode 100644 index 00000000..7d98e79a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Select.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 997e36ad7b02b804ea1f03d05e60bed5 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs new file mode 100644 index 00000000..c0576212 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs @@ -0,0 +1,910 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class SelectManyObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func> selector; + readonly Func> selectorWithIndex; + readonly Func> selectorEnumerable; + readonly Func> selectorEnumerableWithIndex; + + public SelectManyObservable(IObservable source, Func> selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selector = selector; + } + + public SelectManyObservable(IObservable source, Func> selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selectorWithIndex = selector; + } + + public SelectManyObservable(IObservable source, Func> selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selectorEnumerable = selector; + } + + public SelectManyObservable(IObservable source, Func> selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selectorEnumerableWithIndex = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (this.selector != null) + { + return new SelectManyOuterObserver(this, observer, cancel).Run(); + } + else if (this.selectorWithIndex != null) + { + return new SelectManyObserverWithIndex(this, observer, cancel).Run(); + } + else if (this.selectorEnumerable != null) + { + return new SelectManyEnumerableObserver(this, observer, cancel).Run(); + } + else if (this.selectorEnumerableWithIndex != null) + { + return new SelectManyEnumerableObserverWithIndex(this, observer, cancel).Run(); + } + else + { + throw new InvalidOperationException(); + } + } + + class SelectManyOuterObserver : OperatorObserverBase + { + readonly SelectManyObservable parent; + + CompositeDisposable collectionDisposable; + SingleAssignmentDisposable sourceDisposable; + object gate = new object(); + bool isStopped = false; + + public SelectManyOuterObserver(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.source.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(TSource value) + { + IObservable nextObservable; + try + { + nextObservable = parent.selector(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new SelectMany(this, disposable); + disposable.Disposable = nextObservable.Subscribe(collectionObserver); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + isStopped = true; + if (collectionDisposable.Count == 1) + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + else + { + sourceDisposable.Dispose(); + } + } + + class SelectMany : OperatorObserverBase + { + readonly SelectManyOuterObserver parent; + readonly IDisposable cancel; + + public SelectMany(SelectManyOuterObserver parent, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.cancel = cancel; + } + + public override void OnNext(TResult value) + { + lock (parent.gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + if (parent.isStopped && parent.collectionDisposable.Count == 1) + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + + class SelectManyObserverWithIndex : OperatorObserverBase + { + readonly SelectManyObservable parent; + + CompositeDisposable collectionDisposable; + int index = 0; + object gate = new object(); + bool isStopped = false; + SingleAssignmentDisposable sourceDisposable; + + public SelectManyObserverWithIndex(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.source.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(TSource value) + { + IObservable nextObservable; + try + { + nextObservable = parent.selectorWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new SelectMany(this, disposable); + disposable.Disposable = nextObservable.Subscribe(collectionObserver); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + isStopped = true; + if (collectionDisposable.Count == 1) + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + else + { + sourceDisposable.Dispose(); + } + } + + class SelectMany : OperatorObserverBase + { + readonly SelectManyObserverWithIndex parent; + readonly IDisposable cancel; + + public SelectMany(SelectManyObserverWithIndex parent, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.cancel = cancel; + } + + public override void OnNext(TResult value) + { + lock (parent.gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + if (parent.isStopped && parent.collectionDisposable.Count == 1) + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + + class SelectManyEnumerableObserver : OperatorObserverBase + { + readonly SelectManyObservable parent; + + public SelectManyEnumerableObserver(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(TSource value) + { + IEnumerable nextEnumerable; + try + { + nextEnumerable = parent.selectorEnumerable(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + var e = nextEnumerable.GetEnumerator(); + try + { + var hasNext = true; + while (hasNext) + { + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + } + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (hasNext) + { + observer.OnNext(current); + } + } + } + finally + { + if (e != null) + { + e.Dispose(); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class SelectManyEnumerableObserverWithIndex : OperatorObserverBase + { + readonly SelectManyObservable parent; + int index = 0; + + public SelectManyEnumerableObserverWithIndex(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(TSource value) + { + IEnumerable nextEnumerable; + try + { + nextEnumerable = parent.selectorEnumerableWithIndex(value, index++); + } + catch (Exception ex) + { + OnError(ex); + return; + } + + var e = nextEnumerable.GetEnumerator(); + try + { + var hasNext = true; + while (hasNext) + { + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + } + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (hasNext) + { + observer.OnNext(current); + } + } + } + finally + { + if (e != null) + { + e.Dispose(); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + // with resultSelector + internal class SelectManyObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func> collectionSelector; + readonly Func> collectionSelectorWithIndex; + readonly Func> collectionSelectorEnumerable; + readonly Func> collectionSelectorEnumerableWithIndex; + readonly Func resultSelector; + readonly Func resultSelectorWithIndex; + + public SelectManyObservable(IObservable source, Func> collectionSelector, Func resultSelector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.collectionSelector = collectionSelector; + this.resultSelector = resultSelector; + } + + public SelectManyObservable(IObservable source, Func> collectionSelector, Func resultSelector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.collectionSelectorWithIndex = collectionSelector; + this.resultSelectorWithIndex = resultSelector; + } + + public SelectManyObservable(IObservable source, Func> collectionSelector, Func resultSelector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.collectionSelectorEnumerable = collectionSelector; + this.resultSelector = resultSelector; + } + + public SelectManyObservable(IObservable source, Func> collectionSelector, Func resultSelector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.collectionSelectorEnumerableWithIndex = collectionSelector; + this.resultSelectorWithIndex = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (collectionSelector != null) + { + return new SelectManyOuterObserver(this, observer, cancel).Run(); + } + else if (collectionSelectorWithIndex != null) + { + return new SelectManyObserverWithIndex(this, observer, cancel).Run(); + } + else if (collectionSelectorEnumerable != null) + { + return new SelectManyEnumerableObserver(this, observer, cancel).Run(); + } + else if (collectionSelectorEnumerableWithIndex != null) + { + return new SelectManyEnumerableObserverWithIndex(this, observer, cancel).Run(); + } + else + { + throw new InvalidOperationException(); + } + } + + class SelectManyOuterObserver : OperatorObserverBase + { + readonly SelectManyObservable parent; + + CompositeDisposable collectionDisposable; + object gate = new object(); + bool isStopped = false; + SingleAssignmentDisposable sourceDisposable; + + public SelectManyOuterObserver(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.source.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(TSource value) + { + IObservable nextObservable; + try + { + nextObservable = parent.collectionSelector(value); + } + catch (Exception ex) + { + OnError(ex); + return; + } + + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new SelectMany(this, value, disposable); + disposable.Disposable = nextObservable.Subscribe(collectionObserver); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + isStopped = true; + if (collectionDisposable.Count == 1) + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + else + { + sourceDisposable.Dispose(); + } + } + + class SelectMany : OperatorObserverBase + { + readonly SelectManyOuterObserver parent; + readonly TSource sourceValue; + readonly IDisposable cancel; + + public SelectMany(SelectManyOuterObserver parent, TSource value, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.sourceValue = value; + this.cancel = cancel; + } + + public override void OnNext(TCollection value) + { + TResult resultValue; + try + { + resultValue = parent.parent.resultSelector(sourceValue, value); + } + catch (Exception ex) + { + OnError(ex); + return; + } + + lock (parent.gate) + { + base.observer.OnNext(resultValue); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + if (parent.isStopped && parent.collectionDisposable.Count == 1) + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + + class SelectManyObserverWithIndex : OperatorObserverBase + { + readonly SelectManyObservable parent; + + CompositeDisposable collectionDisposable; + object gate = new object(); + bool isStopped = false; + SingleAssignmentDisposable sourceDisposable; + int index = 0; + + public SelectManyObserverWithIndex(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + collectionDisposable = new CompositeDisposable(); + sourceDisposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(sourceDisposable); + + sourceDisposable.Disposable = parent.source.Subscribe(this); + return collectionDisposable; + } + + public override void OnNext(TSource value) + { + var i = index++; + IObservable nextObservable; + try + { + nextObservable = parent.collectionSelectorWithIndex(value, i); + } + catch (Exception ex) + { + OnError(ex); + return; + } + + var disposable = new SingleAssignmentDisposable(); + collectionDisposable.Add(disposable); + var collectionObserver = new SelectManyObserver(this, value, i, disposable); + disposable.Disposable = nextObservable.Subscribe(collectionObserver); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + isStopped = true; + if (collectionDisposable.Count == 1) + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + else + { + sourceDisposable.Dispose(); + } + } + + class SelectManyObserver : OperatorObserverBase + { + readonly SelectManyObserverWithIndex parent; + readonly TSource sourceValue; + readonly int sourceIndex; + readonly IDisposable cancel; + int index; + + public SelectManyObserver(SelectManyObserverWithIndex parent, TSource value, int index, IDisposable cancel) + : base(parent.observer, cancel) + { + this.parent = parent; + this.sourceValue = value; + this.sourceIndex = index; + this.cancel = cancel; + } + + public override void OnNext(TCollection value) + { + TResult resultValue; + try + { + resultValue = parent.parent.resultSelectorWithIndex(sourceValue, sourceIndex, value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + lock (parent.gate) + { + base.observer.OnNext(resultValue); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + parent.collectionDisposable.Remove(cancel); + if (parent.isStopped && parent.collectionDisposable.Count == 1) + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } + } + + class SelectManyEnumerableObserver : OperatorObserverBase + { + readonly SelectManyObservable parent; + + public SelectManyEnumerableObserver(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(TSource value) + { + IEnumerable nextEnumerable; + try + { + nextEnumerable = parent.collectionSelectorEnumerable(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + var e = nextEnumerable.GetEnumerator(); + try + { + var hasNext = true; + while (hasNext) + { + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = parent.resultSelector(value, e.Current); + } + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (hasNext) + { + observer.OnNext(current); + } + } + } + finally + { + if (e != null) + { + e.Dispose(); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class SelectManyEnumerableObserverWithIndex : OperatorObserverBase + { + readonly SelectManyObservable parent; + int index = 0; + + public SelectManyEnumerableObserverWithIndex(SelectManyObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(TSource value) + { + var i = index++; + IEnumerable nextEnumerable; + try + { + nextEnumerable = parent.collectionSelectorEnumerableWithIndex(value, i); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); }; + return; + } + + var e = nextEnumerable.GetEnumerator(); + try + { + var sequenceI = 0; + var hasNext = true; + while (hasNext) + { + hasNext = false; + var current = default(TResult); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = parent.resultSelectorWithIndex(value, i, e.Current, sequenceI++); + } + } + catch (Exception exception) + { + try { observer.OnError(exception); } finally { Dispose(); } + return; + } + + if (hasNext) + { + observer.OnNext(current); + } + } + } + finally + { + if (e != null) + { + e.Dispose(); + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs.meta new file mode 100644 index 00000000..fd3178e3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectMany.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6496e8557f6066e4380c32935b6f37c3 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs new file mode 100644 index 00000000..833688a0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs @@ -0,0 +1,77 @@ +using System; + +namespace UniRx.Operators +{ + // Optimize for .Select().Where() + + internal class SelectWhereObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func selector; + readonly Func predicate; + + public SelectWhereObservable(IObservable source, Func selector, Func predicate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.selector = selector; + this.predicate = predicate; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new SelectWhere(this, observer, cancel)); + } + + class SelectWhere : OperatorObserverBase + { + readonly SelectWhereObservable parent; + + public SelectWhere(SelectWhereObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + var v = default(TR); + try + { + v = parent.selector(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + var isPassed = false; + try + { + isPassed = parent.predicate(v); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + observer.OnNext(v); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs.meta new file mode 100644 index 00000000..e4bd10bf --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SelectWhere.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6a7561d10967d6b4d9c2a67ffc3b9d85 +timeCreated: 1468748731 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs new file mode 100644 index 00000000..41a57816 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs @@ -0,0 +1,182 @@ +using System; + +namespace UniRx.Operators +{ + internal class SingleObservable : OperatorObservableBase + { + readonly IObservable source; + readonly bool useDefault; + readonly Func predicate; + + public SingleObservable(IObservable source, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.useDefault = useDefault; + } + + public SingleObservable(IObservable source, Func predicate, bool useDefault) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + this.useDefault = useDefault; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate == null) + { + return source.Subscribe(new Single(this, observer, cancel)); + } + else + { + return source.Subscribe(new Single_(this, observer, cancel)); + } + } + + class Single : OperatorObserverBase + { + readonly SingleObservable parent; + bool seenValue; + T lastValue; + + public Single(SingleObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.seenValue = false; + } + + public override void OnNext(T value) + { + if (seenValue) + { + try { observer.OnError(new InvalidOperationException("sequence is not single")); } + finally { Dispose(); } + } + else + { + seenValue = true; + lastValue = value; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (!seenValue) + { + observer.OnNext(default(T)); + } + else + { + observer.OnNext(lastValue); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (!seenValue) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + observer.OnNext(lastValue); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + + class Single_ : OperatorObserverBase + { + readonly SingleObservable parent; + bool seenValue; + T lastValue; + + public Single_(SingleObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.seenValue = false; + } + + public override void OnNext(T value) + { + bool isPassed; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (isPassed) + { + if (seenValue) + { + try { observer.OnError(new InvalidOperationException("sequence is not single")); } + finally { Dispose(); } + return; + } + else + { + seenValue = true; + lastValue = value; + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (parent.useDefault) + { + if (!seenValue) + { + observer.OnNext(default(T)); + } + else + { + observer.OnNext(lastValue); + } + try { observer.OnCompleted(); } + finally { Dispose(); } + } + else + { + if (!seenValue) + { + try { observer.OnError(new InvalidOperationException("sequence is empty")); } + finally { Dispose(); } + } + else + { + observer.OnNext(lastValue); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs.meta new file mode 100644 index 00000000..4c854459 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Single.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9a50aee929f403f4ea076fc11f71fc53 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs new file mode 100644 index 00000000..a8cc51d1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs @@ -0,0 +1,138 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class SkipObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int count; + readonly TimeSpan duration; + internal readonly IScheduler scheduler; // public for optimization check + + public SkipObservable(IObservable source, int count) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.count = count; + } + + public SkipObservable(IObservable source, TimeSpan duration, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.duration = duration; + this.scheduler = scheduler; + } + + // optimize combiner + + public IObservable Combine(int count) + { + // use sum + // xs = 6 + // xs.Skip(2) = 4 + // xs.Skip(2).Skip(3) = 1 + + return new SkipObservable(source, this.count + count); + } + + public IObservable Combine(TimeSpan duration) + { + // use max + // xs = 6s + // xs.Skip(2s) = 2s + // xs.Skip(2s).Skip(3s) = 3s + + return (duration <= this.duration) + ? this + : new SkipObservable(source, duration, scheduler); + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (scheduler == null) + { + return source.Subscribe(new Skip(this, observer, cancel)); + } + else + { + return new Skip_(this, observer, cancel).Run(); + } + } + + class Skip : OperatorObserverBase + { + int remaining; + + public Skip(SkipObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.remaining = parent.count; + } + + public override void OnNext(T value) + { + if (remaining <= 0) + { + base.observer.OnNext(value); + } + else + { + remaining--; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class Skip_ : OperatorObserverBase + { + readonly SkipObservable parent; + volatile bool open; + + public Skip_(SkipObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var d1 = parent.scheduler.Schedule(parent.duration, Tick); + var d2 = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(d1, d2); + } + + void Tick() + { + open = true; + } + + public override void OnNext(T value) + { + if (open) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs.meta new file mode 100644 index 00000000..53d4b4ed --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Skip.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1ffcb45c02e14e94bb37c6513b04bb7c +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs new file mode 100644 index 00000000..19c89a7b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs @@ -0,0 +1,119 @@ +using System; + +namespace UniRx.Operators +{ + internal class SkipUntilObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObservable other; + + public SkipUntilObservable(IObservable source, IObservable other) + : base(source.IsRequiredSubscribeOnCurrentThread() || other.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.other = other; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new SkipUntilOuterObserver(this, observer, cancel).Run(); + } + + class SkipUntilOuterObserver : OperatorObserverBase + { + readonly SkipUntilObservable parent; + + public SkipUntilOuterObserver(SkipUntilObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var sourceSubscription = new SingleAssignmentDisposable(); + var sourceObserver = new SkipUntil(this, sourceSubscription); + + var otherSubscription = new SingleAssignmentDisposable(); + var otherObserver = new SkipUntilOther(this, sourceObserver, otherSubscription); + + sourceSubscription.Disposable = parent.source.Subscribe(sourceObserver); + otherSubscription.Disposable = parent.other.Subscribe(otherObserver); + + return StableCompositeDisposable.Create(otherSubscription, sourceSubscription); + } + + public override void OnNext(T value) + { + } + + public override void OnError(Exception error) + { + } + + public override void OnCompleted() + { + } + + class SkipUntil : IObserver + { + public volatile IObserver observer; + readonly SkipUntilOuterObserver parent; + readonly IDisposable subscription; + + public SkipUntil(SkipUntilOuterObserver parent, IDisposable subscription) + { + this.parent = parent; + observer = UniRx.InternalUtil.EmptyObserver.Instance; + this.subscription = subscription; + } + + public void OnNext(T value) + { + observer.OnNext(value); + } + + public void OnError(Exception error) + { + try { observer.OnError(error); } + finally { parent.Dispose(); } + } + + public void OnCompleted() + { + try { observer.OnCompleted(); } + finally { subscription.Dispose(); } + } + } + + class SkipUntilOther : IObserver + { + readonly SkipUntilOuterObserver parent; + readonly SkipUntil sourceObserver; + readonly IDisposable subscription; + + public SkipUntilOther(SkipUntilOuterObserver parent, SkipUntil sourceObserver, IDisposable subscription) + { + this.parent = parent; + this.sourceObserver = sourceObserver; + this.subscription = subscription; + } + + public void OnNext(TOther value) + { + sourceObserver.observer = parent.observer; + subscription.Dispose(); + } + + public void OnError(Exception error) + { + try { parent.observer.OnError(error); } finally { parent.Dispose(); } + } + + public void OnCompleted() + { + subscription.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs.meta new file mode 100644 index 00000000..b9b65556 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipUntil.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 52314487e375f3d44a49bc5ceb90adab +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs new file mode 100644 index 00000000..834caffd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs @@ -0,0 +1,130 @@ +using System; + +namespace UniRx.Operators +{ + internal class SkipWhileObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func predicate; + readonly Func predicateWithIndex; + + public SkipWhileObservable(IObservable source, Func predicate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + } + + public SkipWhileObservable(IObservable source, Func predicateWithIndex) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicateWithIndex = predicateWithIndex; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate != null) + { + return new SkipWhile(this, observer, cancel).Run(); + } + else + { + return new SkipWhile_(this, observer, cancel).Run(); + } + } + + class SkipWhile : OperatorObserverBase + { + readonly SkipWhileObservable parent; + bool endSkip = false; + + public SkipWhile(SkipWhileObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + if (!endSkip) + { + try + { + endSkip = !parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (!endSkip) return; + } + + observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class SkipWhile_ : OperatorObserverBase + { + readonly SkipWhileObservable parent; + bool endSkip = false; + int index = 0; + + public SkipWhile_(SkipWhileObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + if (!endSkip) + { + try + { + endSkip = !parent.predicateWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (!endSkip) return; + } + + observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs.meta new file mode 100644 index 00000000..55b23bd9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SkipWhile.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4bc7a1e818d05654694d51e883739cca +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs new file mode 100644 index 00000000..6343a32c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs @@ -0,0 +1,101 @@ +using System; + +namespace UniRx.Operators +{ + internal class StartObservable : OperatorObservableBase + { + readonly Action action; + readonly Func function; + readonly IScheduler scheduler; + readonly TimeSpan? startAfter; + + public StartObservable(Func function, TimeSpan? startAfter, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.function = function; + this.startAfter = startAfter; + this.scheduler = scheduler; + } + + public StartObservable(Action action, TimeSpan? startAfter, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.action = action; + this.startAfter = startAfter; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (startAfter != null) + { + return scheduler.Schedule(startAfter.Value, new StartObserver(this, observer, cancel).Run); + } + else + { + return scheduler.Schedule(new StartObserver(this, observer, cancel).Run); + } + } + + class StartObserver : OperatorObserverBase + { + readonly StartObservable parent; + + public StartObserver(StartObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public void Run() + { + var result = default(T); + try + { + if (parent.function != null) + { + result = parent.function(); + } + else + { + parent.action(); + } + } + catch (Exception exception) + { + try { observer.OnError(exception); } + finally { Dispose(); } + return; + } + + OnNext(result); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs.meta new file mode 100644 index 00000000..6c72de1c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Start.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2b99cac67f8c387439619e01a480c465 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs new file mode 100644 index 00000000..4fbb221e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs @@ -0,0 +1,82 @@ +using System; + +namespace UniRx.Operators +{ + internal class StartWithObservable : OperatorObservableBase + { + readonly IObservable source; + readonly T value; + readonly Func valueFactory; + + public StartWithObservable(IObservable source, T value) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.value = value; + } + + public StartWithObservable(IObservable source, Func valueFactory) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.valueFactory = valueFactory; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new StartWith(this, observer, cancel).Run(); + } + + class StartWith : OperatorObserverBase + { + readonly StartWithObservable parent; + + public StartWith(StartWithObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + T t; + if (parent.valueFactory == null) + { + t = parent.value; + } + else + { + try + { + t = parent.valueFactory(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return Disposable.Empty; + } + } + + OnNext(t); + return parent.source.Subscribe(base.observer); // good bye StartWithObserver + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs.meta new file mode 100644 index 00000000..fed8fc0c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/StartWith.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 05df6719453543e458dc3e0d29ac7fa8 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs new file mode 100644 index 00000000..e63fde96 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class SubscribeOnObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IScheduler scheduler; + + public SubscribeOnObservable(IObservable source, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var m = new SingleAssignmentDisposable(); + var d = new SerialDisposable(); + d.Disposable = m; + + m.Disposable = scheduler.Schedule(() => + { + d.Disposable = new ScheduledDisposable(scheduler, source.Subscribe(observer)); + }); + + return d; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs.meta new file mode 100644 index 00000000..8ade24af --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SubscribeOn.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bff34f363b1797c4396815b5b3a4be1c +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs new file mode 100644 index 00000000..29482bd2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + internal class SwitchObservable : OperatorObservableBase + { + readonly IObservable> sources; + + public SwitchObservable(IObservable> sources) + : base(true) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new SwitchObserver(this, observer, cancel).Run(); + } + + class SwitchObserver : OperatorObserverBase, T> + { + readonly SwitchObservable parent; + + readonly object gate = new object(); + readonly SerialDisposable innerSubscription = new SerialDisposable(); + bool isStopped = false; + ulong latest = 0UL; + bool hasLatest = false; + + public SwitchObserver(SwitchObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var subscription = parent.sources.Subscribe(this); + return StableCompositeDisposable.Create(subscription, innerSubscription); + } + + public override void OnNext(IObservable value) + { + var id = default(ulong); + lock (gate) + { + id = unchecked(++latest); + hasLatest = true; + } + + var d = new SingleAssignmentDisposable(); + innerSubscription.Disposable = d; + d.Disposable = value.Subscribe(new Switch(this, id)); + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + isStopped = true; + if (!hasLatest) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + class Switch : IObserver + { + readonly SwitchObserver parent; + readonly ulong id; + + public Switch(SwitchObserver observer, ulong id) + { + this.parent = observer; + this.id = id; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + if (parent.latest == id) + { + parent.observer.OnNext(value); + } + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (parent.latest == id) + { + parent.observer.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (parent.latest == id) + { + parent.hasLatest = false; + if (parent.isStopped) + { + parent.observer.OnCompleted(); + } + } + } + } + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs.meta new file mode 100644 index 00000000..bb1328f4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Switch.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5e16cdc638ec3bf41bbd380b75991734 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs new file mode 100644 index 00000000..6d368a2e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs @@ -0,0 +1,57 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class SynchronizeObservable : OperatorObservableBase + { + readonly IObservable source; + readonly object gate; + + public SynchronizeObservable(IObservable source, object gate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.gate = gate; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new Synchronize(this, observer, cancel)); + } + + class Synchronize : OperatorObserverBase + { + readonly SynchronizeObservable parent; + + public Synchronize(SynchronizeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + lock (parent.gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (parent.gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + lock (parent.gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs.meta new file mode 100644 index 00000000..19486242 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Synchronize.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 31ddcb8477b384b4c9867568f6dc8359 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs new file mode 100644 index 00000000..7edd1344 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs @@ -0,0 +1,40 @@ +using System; + +namespace UniRx.Operators +{ + internal class SynchronizedObserver : IObserver + { + readonly IObserver observer; + readonly object gate; + + public SynchronizedObserver(IObserver observer, object gate) + { + this.observer = observer; + this.gate = gate; + } + + public void OnNext(T value) + { + lock (gate) + { + observer.OnNext(value); + } + } + + public void OnError(Exception error) + { + lock (gate) + { + observer.OnError(error); + } + } + + public void OnCompleted() + { + lock (gate) + { + observer.OnCompleted(); + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs.meta new file mode 100644 index 00000000..0fd48bab --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/SynchronizedObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4fd465af6ee05a64f9115b45b58360b7 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs new file mode 100644 index 00000000..d22dfed0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs @@ -0,0 +1,150 @@ +using System; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class TakeObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int count; + readonly TimeSpan duration; + internal readonly IScheduler scheduler; // public for optimization check + + public TakeObservable(IObservable source, int count) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.count = count; + } + + public TakeObservable(IObservable source, TimeSpan duration, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.duration = duration; + this.scheduler = scheduler; + } + + // optimize combiner + + public IObservable Combine(int count) + { + // xs = 6 + // xs.Take(5) = 5 | xs.Take(3) = 3 + // xs.Take(5).Take(3) = 3 | xs.Take(3).Take(5) = 3 + + // use minimum one + return (this.count <= count) + ? this + : new TakeObservable(source, count); + } + + public IObservable Combine(TimeSpan duration) + { + // xs = 6s + // xs.Take(5s) = 5s | xs.Take(3s) = 3s + // xs.Take(5s).Take(3s) = 3s | xs.Take(3s).Take(5s) = 3s + + // use minimum one + return (this.duration <= duration) + ? this + : new TakeObservable(source, duration, scheduler); + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (scheduler == null) + { + return source.Subscribe(new Take(this, observer, cancel)); + } + else + { + return new Take_(this, observer, cancel).Run(); + } + } + + class Take : OperatorObserverBase + { + int rest; + + public Take(TakeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.rest = parent.count; + } + + public override void OnNext(T value) + { + if (rest > 0) + { + rest -= 1; + base.observer.OnNext(value); + if (rest == 0) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class Take_ : OperatorObserverBase + { + readonly TakeObservable parent; + readonly object gate = new object(); + + public Take_(TakeObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var d1 = parent.scheduler.Schedule(parent.duration, Tick); + var d2 = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(d1, d2); + } + + void Tick() + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + + public override void OnNext(T value) + { + lock (gate) + { + base.observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + } + + public override void OnCompleted() + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs.meta new file mode 100644 index 00000000..26f72869 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Take.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5275fc8bb6611984781d8ccd56b9b572 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs new file mode 100644 index 00000000..8887cd6d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using UniRx.Operators; + +namespace UniRx.Operators +{ + internal class TakeLastObservable : OperatorObservableBase + { + readonly IObservable source; + + // count + readonly int count; + + // duration + readonly TimeSpan duration; + readonly IScheduler scheduler; + + public TakeLastObservable(IObservable source, int count) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.count = count; + } + + public TakeLastObservable(IObservable source, TimeSpan duration, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.duration = duration; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (scheduler == null) + { + return new TakeLast(this, observer, cancel).Run(); + } + else + { + return new TakeLast_(this, observer, cancel).Run(); + } + } + + // count + class TakeLast : OperatorObserverBase + { + readonly TakeLastObservable parent; + readonly Queue q; + + public TakeLast(TakeLastObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.q = new Queue(); + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + q.Enqueue(value); + if (q.Count > parent.count) + { + q.Dequeue(); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + foreach (var item in q) + { + observer.OnNext(item); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + // time + class TakeLast_ : OperatorObserverBase + { + DateTimeOffset startTime; + readonly TakeLastObservable parent; + readonly Queue> q; + + public TakeLast_(TakeLastObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.q = new Queue>(); + } + + public IDisposable Run() + { + startTime = parent.scheduler.Now; + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + var now = parent.scheduler.Now; + var elapsed = now - startTime; + q.Enqueue(new TimeInterval(value, elapsed)); + Trim(elapsed); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); }; + } + + public override void OnCompleted() + { + var now = parent.scheduler.Now; + var elapsed = now - startTime; + Trim(elapsed); + + foreach (var item in q) + { + observer.OnNext(item.Value); + } + try { observer.OnCompleted(); } finally { Dispose(); }; + } + + void Trim(TimeSpan now) + { + while (q.Count > 0 && now - q.Peek().Interval >= parent.duration) + { + q.Dequeue(); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs.meta new file mode 100644 index 00000000..a3b7ba32 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeLast.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8ea2ac59577a3214f9fb66ccc62f2ffd +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs new file mode 100644 index 00000000..a8704fa7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs @@ -0,0 +1,128 @@ +using System; + +namespace UniRx.Operators +{ + internal class TakeUntilObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObservable other; + + public TakeUntilObservable(IObservable source, IObservable other) + : base(source.IsRequiredSubscribeOnCurrentThread() || other.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.other = other; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new TakeUntil(this, observer, cancel).Run(); + } + + class TakeUntil : OperatorObserverBase + { + readonly TakeUntilObservable parent; + object gate = new object(); + + public TakeUntil(TakeUntilObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var otherSubscription = new SingleAssignmentDisposable(); + var otherObserver = new TakeUntilOther(this, otherSubscription); + otherSubscription.Disposable = parent.other.Subscribe(otherObserver); + + var sourceSubscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(otherSubscription, sourceSubscription); + } + + public override void OnNext(T value) + { + lock (gate) + { + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class TakeUntilOther : IObserver + { + readonly TakeUntil sourceObserver; + readonly IDisposable subscription; + + public TakeUntilOther(TakeUntil sourceObserver, IDisposable subscription) + { + this.sourceObserver = sourceObserver; + this.subscription = subscription; + } + + public void OnNext(TOther value) + { + lock (sourceObserver.gate) + { + try + { + sourceObserver.observer.OnCompleted(); + } + finally + { + sourceObserver.Dispose(); + subscription.Dispose(); + } + } + } + + public void OnError(Exception error) + { + lock (sourceObserver.gate) + { + try + { + sourceObserver.observer.OnError(error); + } + finally + { + sourceObserver.Dispose(); + subscription.Dispose(); + } + } + } + + public void OnCompleted() + { + lock (sourceObserver.gate) + { + try + { + sourceObserver.observer.OnCompleted(); + } + finally + { + sourceObserver.Dispose(); + subscription.Dispose(); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs.meta new file mode 100644 index 00000000..ae29e38c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeUntil.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 163e3eab299b735418c94e634fecd811 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs new file mode 100644 index 00000000..56e69d49 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs @@ -0,0 +1,134 @@ +using System; + +namespace UniRx.Operators +{ + internal class TakeWhileObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func predicate; + readonly Func predicateWithIndex; + + public TakeWhileObservable(IObservable source, Func predicate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + } + + public TakeWhileObservable(IObservable source, Func predicateWithIndex) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicateWithIndex = predicateWithIndex; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate != null) + { + return new TakeWhile(this, observer, cancel).Run(); + } + else + { + return new TakeWhile_(this, observer, cancel).Run(); + } + } + + class TakeWhile : OperatorObserverBase + { + readonly TakeWhileObservable parent; + + public TakeWhile(TakeWhileObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + bool isPassed; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + observer.OnNext(value); + } + else + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class TakeWhile_ : OperatorObserverBase + { + readonly TakeWhileObservable parent; + int index = 0; + + public TakeWhile_(TakeWhileObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + return parent.source.Subscribe(this); + } + + public override void OnNext(T value) + { + bool isPassed; + try + { + isPassed = parent.predicateWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + observer.OnNext(value); + } + else + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs.meta new file mode 100644 index 00000000..9fb6f896 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TakeWhile.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d6f2da76023d9734ebb4ed1883fda2bc +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs new file mode 100644 index 00000000..e69afe42 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + internal class ThrottleObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TimeSpan dueTime; + readonly IScheduler scheduler; + + public ThrottleObservable(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.dueTime = dueTime; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Throttle(this, observer, cancel).Run(); + } + + class Throttle : OperatorObserverBase + { + readonly ThrottleObservable parent; + readonly object gate = new object(); + T latestValue = default(T); + bool hasValue = false; + SerialDisposable cancelable; + ulong id = 0; + + public Throttle(ThrottleObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + cancelable = new SerialDisposable(); + var subscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(cancelable, subscription); + } + + void OnNext(ulong currentid) + { + lock (gate) + { + if (hasValue && id == currentid) + { + observer.OnNext(latestValue); + } + hasValue = false; + } + } + + public override void OnNext(T value) + { + ulong currentid; + lock (gate) + { + hasValue = true; + latestValue = value; + id = unchecked(id + 1); + currentid = id; + } + + var d = new SingleAssignmentDisposable(); + cancelable.Disposable = d; + d.Disposable = parent.scheduler.Schedule(parent.dueTime, () => OnNext(currentid)); + } + + public override void OnError(Exception error) + { + cancelable.Dispose(); + + lock (gate) + { + hasValue = false; + id = unchecked(id + 1); + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + cancelable.Dispose(); + + lock (gate) + { + if (hasValue) + { + observer.OnNext(latestValue); + } + hasValue = false; + id = unchecked(id + 1); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs.meta new file mode 100644 index 00000000..a3b0eec8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throttle.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dc296a61927394b4b908b385087f23d0 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs new file mode 100644 index 00000000..0bb5876c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs @@ -0,0 +1,87 @@ +using System; + +namespace UniRx.Operators +{ + internal class ThrottleFirstObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TimeSpan dueTime; + readonly IScheduler scheduler; + + public ThrottleFirstObservable(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.dueTime = dueTime; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ThrottleFirst(this, observer, cancel).Run(); + } + + class ThrottleFirst : OperatorObserverBase + { + readonly ThrottleFirstObservable parent; + readonly object gate = new object(); + bool open = true; + SerialDisposable cancelable; + + public ThrottleFirst(ThrottleFirstObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + cancelable = new SerialDisposable(); + var subscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(cancelable, subscription); + } + + void OnNext() + { + lock (gate) + { + open = true; + } + } + + public override void OnNext(T value) + { + lock (gate) + { + if (!open) return; + observer.OnNext(value); + open = false; + } + + var d = new SingleAssignmentDisposable(); + cancelable.Disposable = d; + d.Disposable = parent.scheduler.Schedule(parent.dueTime, OnNext); + } + + public override void OnError(Exception error) + { + cancelable.Dispose(); + + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + cancelable.Dispose(); + + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs.meta new file mode 100644 index 00000000..2d01f882 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ThrottleFirst.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 32b6a6efbab897b41a055d830a4d9755 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs new file mode 100644 index 00000000..781a1da9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs @@ -0,0 +1,69 @@ +using System; + +namespace UniRx.Operators +{ + internal class ThrowObservable : OperatorObservableBase + { + readonly Exception error; + readonly IScheduler scheduler; + + public ThrowObservable(Exception error, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.error = error; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + observer = new Throw(observer, cancel); + + if (scheduler == Scheduler.Immediate) + { + observer.OnError(error); + return Disposable.Empty; + } + else + { + return scheduler.Schedule(() => + { + observer.OnError(error); + observer.OnCompleted(); + }); + } + } + + class Throw : OperatorObserverBase + { + public Throw(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs.meta new file mode 100644 index 00000000..fcba5343 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Throw.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1e5623719e9b1f1418aa67a63abed4cc +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs new file mode 100644 index 00000000..9d233770 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs @@ -0,0 +1,56 @@ +using System; + +namespace UniRx.Operators +{ + internal class TimeIntervalObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly IScheduler scheduler; + + public TimeIntervalObservable(IObservable source, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new TimeInterval(this, observer, cancel)); + } + + class TimeInterval : OperatorObserverBase> + { + readonly TimeIntervalObservable parent; + DateTimeOffset lastTime; + + public TimeInterval(TimeIntervalObservable parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + this.lastTime = parent.scheduler.Now; + } + + public override void OnNext(T value) + { + var now = parent.scheduler.Now; + var span = now.Subtract(lastTime); + lastTime = now; + + base.observer.OnNext(new UniRx.TimeInterval(value, span)); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs.meta new file mode 100644 index 00000000..4453dd4f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/TimeInterval.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 065e40ebd4bd4a848b58a7a90dac881d +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs new file mode 100644 index 00000000..3a0e9f38 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs @@ -0,0 +1,198 @@ +using System; + +namespace UniRx.Operators +{ + internal class TimeoutObservable : OperatorObservableBase + { + readonly IObservable source; + readonly TimeSpan? dueTime; + readonly DateTimeOffset? dueTimeDT; + readonly IScheduler scheduler; + + public TimeoutObservable(IObservable source, TimeSpan dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.dueTime = dueTime; + this.scheduler = scheduler; + } + + public TimeoutObservable(IObservable source, DateTimeOffset dueTime, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.dueTimeDT = dueTime; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (dueTime != null) + { + return new Timeout(this, observer, cancel).Run(); + } + else + { + return new Timeout_(this, observer, cancel).Run(); + } + } + + class Timeout : OperatorObserverBase + { + readonly TimeoutObservable parent; + readonly object gate = new object(); + ulong objectId = 0ul; + bool isTimeout = false; + SingleAssignmentDisposable sourceSubscription; + SerialDisposable timerSubscription; + + public Timeout(TimeoutObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + timerSubscription = new SerialDisposable(); + timerSubscription.Disposable = RunTimer(objectId); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(timerSubscription, sourceSubscription); + } + + IDisposable RunTimer(ulong timerId) + { + return parent.scheduler.Schedule(parent.dueTime.Value, () => + { + lock (gate) + { + if (objectId == timerId) + { + isTimeout = true; + } + } + if (isTimeout) + { + try { observer.OnError(new TimeoutException()); } finally { Dispose(); } + } + }); + } + + public override void OnNext(T value) + { + ulong useObjectId; + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + useObjectId = objectId; + } + if (timeout) return; + + timerSubscription.Disposable = Disposable.Empty; // cancel old timer + observer.OnNext(value); + timerSubscription.Disposable = RunTimer(useObjectId); + } + + public override void OnError(Exception error) + { + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + } + if (timeout) return; + + timerSubscription.Dispose(); + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + } + if (timeout) return; + + timerSubscription.Dispose(); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class Timeout_ : OperatorObserverBase + { + readonly TimeoutObservable parent; + readonly object gate = new object(); + bool isFinished = false; + SingleAssignmentDisposable sourceSubscription; + IDisposable timerSubscription; + + public Timeout_(TimeoutObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + + timerSubscription = parent.scheduler.Schedule(parent.dueTimeDT.Value, OnNext); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(timerSubscription, sourceSubscription); + } + + // in timer + void OnNext() + { + lock (gate) + { + if (isFinished) return; + isFinished = true; + } + + sourceSubscription.Dispose(); + try { observer.OnError(new TimeoutException()); } finally { Dispose(); } + } + + public override void OnNext(T value) + { + lock (gate) + { + if (!isFinished) observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + if (isFinished) return; + isFinished = true; + timerSubscription.Dispose(); + } + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + + lock (gate) + { + if (!isFinished) + { + isFinished = true; + timerSubscription.Dispose(); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs.meta new file mode 100644 index 00000000..a13e965a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timeout.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a22cd4a86f62fc64384dddb043530703 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs new file mode 100644 index 00000000..ceac8b52 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs @@ -0,0 +1,124 @@ +using System; + +namespace UniRx.Operators +{ + internal class TimerObservable : OperatorObservableBase + { + readonly DateTimeOffset? dueTimeA; + readonly TimeSpan? dueTimeB; + readonly TimeSpan? period; + readonly IScheduler scheduler; + + public TimerObservable(DateTimeOffset dueTime, TimeSpan? period, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.dueTimeA = dueTime; + this.period = period; + this.scheduler = scheduler; + } + + public TimerObservable(TimeSpan dueTime, TimeSpan? period, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.dueTimeB = dueTime; + this.period = period; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var timerObserver = new Timer(observer, cancel); + + var dueTime = (dueTimeA != null) + ? dueTimeA.Value - scheduler.Now + : dueTimeB.Value; + + // one-shot + if (period == null) + { + return scheduler.Schedule(Scheduler.Normalize(dueTime), () => + { + timerObserver.OnNext(); + timerObserver.OnCompleted(); + }); + } + else + { + var periodicScheduler = scheduler as ISchedulerPeriodic; + if (periodicScheduler != null) + { + if (dueTime == period.Value) + { + // same(Observable.Interval), run periodic + return periodicScheduler.SchedulePeriodic(Scheduler.Normalize(dueTime), timerObserver.OnNext); + } + else + { + // Schedule Once + Scheudle Periodic + var disposable = new SerialDisposable(); + + disposable.Disposable = scheduler.Schedule(Scheduler.Normalize(dueTime), () => + { + timerObserver.OnNext(); // run first + + var timeP = Scheduler.Normalize(period.Value); + disposable.Disposable = periodicScheduler.SchedulePeriodic(timeP, timerObserver.OnNext); // run periodic + }); + + return disposable; + } + } + else + { + var timeP = Scheduler.Normalize(period.Value); + + return scheduler.Schedule(Scheduler.Normalize(dueTime), self => + { + timerObserver.OnNext(); + self(timeP); + }); + } + } + } + + class Timer : OperatorObserverBase + { + long index = 0; + + public Timer(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public void OnNext() + { + try + { + base.observer.OnNext(index++); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnNext(long value) + { + // no use. + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs.meta new file mode 100644 index 00000000..c4d9e901 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6be220be1da39e14ea87b366c149953e +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs new file mode 100644 index 00000000..43ccdfc2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs @@ -0,0 +1,50 @@ +using System; + +namespace UniRx.Operators +{ + internal class TimestampObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly IScheduler scheduler; + + public TimestampObservable(IObservable source, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread || source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new Timestamp(this, observer, cancel)); + } + + class Timestamp : OperatorObserverBase> + { + readonly TimestampObservable parent; + + public Timestamp(TimestampObservable parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + base.observer.OnNext(new Timestamped(value, parent.scheduler.Now)); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs.meta new file mode 100644 index 00000000..ec2ef511 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Timestamp.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d9ec806fec477b243a812e7f609a4453 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs new file mode 100644 index 00000000..9226ee89 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class ToArrayObservable : OperatorObservableBase + { + readonly IObservable source; + + public ToArrayObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new ToArray(observer, cancel)); + } + + class ToArray : OperatorObserverBase + { + readonly List list = new List(); + + public ToArray(IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(TSource value) + { + try + { + list.Add(value); // sometimes cause error on multithread + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + TSource[] result; + try + { + result = list.ToArray(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + base.observer.OnNext(result); + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs.meta new file mode 100644 index 00000000..6b04a78d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToArray.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 38d1f7c869353b542af469b0e3fae89a +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs new file mode 100644 index 00000000..62c924db --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class ToListObservable : OperatorObservableBase> + { + readonly IObservable source; + + public ToListObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new ToList(observer, cancel)); + } + + class ToList : OperatorObserverBase> + { + readonly List list = new List(); + + public ToList(IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + } + + public override void OnNext(TSource value) + { + try + { + list.Add(value); // sometimes cause error on multithread + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + base.observer.OnNext(list); + try { observer.OnCompleted(); } finally { Dispose(); }; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs.meta new file mode 100644 index 00000000..e8cd422d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cee1b9300a644c9458346c1f80f64197 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs new file mode 100644 index 00000000..81b6b88a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class ToObservableObservable : OperatorObservableBase + { + readonly IEnumerable source; + readonly IScheduler scheduler; + + public ToObservableObservable(IEnumerable source, IScheduler scheduler) + : base(scheduler == Scheduler.CurrentThread) + { + this.source = source; + this.scheduler = scheduler; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ToObservable(this, observer, cancel).Run(); + } + + class ToObservable : OperatorObserverBase + { + readonly ToObservableObservable parent; + + public ToObservable(ToObservableObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var e = default(IEnumerator); + try + { + e = parent.source.GetEnumerator(); + } + catch (Exception exception) + { + OnError(exception); + return Disposable.Empty; + } + + if (parent.scheduler == Scheduler.Immediate) + { + while (true) + { + bool hasNext; + var current = default(T); + try + { + hasNext = e.MoveNext(); + if (hasNext) current = e.Current; + } + catch (Exception ex) + { + e.Dispose(); + try { observer.OnError(ex); } + finally { Dispose(); } + break; + } + + if (hasNext) + { + observer.OnNext(current); + } + else + { + e.Dispose(); + try { observer.OnCompleted(); } + finally { Dispose(); } + break; + } + } + + return Disposable.Empty; + } + + var flag = new SingleAssignmentDisposable(); + flag.Disposable = parent.scheduler.Schedule(self => + { + if (flag.IsDisposed) + { + e.Dispose(); + return; + } + + bool hasNext; + var current = default(T); + try + { + hasNext = e.MoveNext(); + if (hasNext) current = e.Current; + } + catch (Exception ex) + { + e.Dispose(); + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + if (hasNext) + { + observer.OnNext(current); + self(); + } + else + { + e.Dispose(); + try { observer.OnCompleted(); } + finally { Dispose(); } + } + }); + + return flag; + } + + public override void OnNext(T value) + { + // do nothing + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs.meta new file mode 100644 index 00000000..fb7ed5ca --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ToObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7cd3ae084c8ca754f9aceca2e18c3af9 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs new file mode 100644 index 00000000..8710c49a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs @@ -0,0 +1,63 @@ +using System; +using UniRx.InternalUtil; + +namespace UniRx.Operators +{ + internal class Wait : IObserver + { + static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, -1); // from .NET 4.5 + + readonly IObservable source; + readonly TimeSpan timeout; + + System.Threading.ManualResetEvent semaphore; + + bool seenValue = false; + T value = default(T); + Exception ex = default(Exception); + + public Wait(IObservable source, TimeSpan timeout) + { + this.source = source; + this.timeout = timeout; + } + + public T Run() + { + semaphore = new System.Threading.ManualResetEvent(false); + using (source.Subscribe(this)) + { + var waitComplete = (timeout == InfiniteTimeSpan) + ? semaphore.WaitOne() + : semaphore.WaitOne(timeout); + + if (!waitComplete) + { + throw new TimeoutException("OnCompleted not fired."); + } + } + + if (ex != null) ex.Throw(); + if (!seenValue) throw new InvalidOperationException("No Elements."); + + return value; + } + + public void OnNext(T value) + { + seenValue = true; + this.value = value; + } + + public void OnError(Exception error) + { + this.ex = error; + semaphore.Set(); + } + + public void OnCompleted() + { + semaphore.Set(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs.meta new file mode 100644 index 00000000..68300427 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Wait.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ea55c5647aa075b4f894dd37abf5e469 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs new file mode 100644 index 00000000..e7d33766 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs @@ -0,0 +1,485 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class WhenAllObservable : OperatorObservableBase + { + readonly IObservable[] sources; + readonly IEnumerable> sourcesEnumerable; + + public WhenAllObservable(IObservable[] sources) + : base(false) + { + this.sources = sources; + } + + public WhenAllObservable(IEnumerable> sources) + : base(false) + { + this.sourcesEnumerable = sources; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (sources != null) + { + return new WhenAll(this.sources, observer, cancel).Run(); + } + else + { + var xs = sourcesEnumerable as IList>; + if (xs == null) + { + xs = new List>(sourcesEnumerable); // materialize observables + } + return new WhenAll_(xs, observer, cancel).Run(); + } + } + + class WhenAll : OperatorObserverBase + { + readonly IObservable[] sources; + readonly object gate = new object(); + int completedCount; + int length; + T[] values; + + public WhenAll(IObservable[] sources, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.sources = sources; + } + + public IDisposable Run() + { + length = sources.Length; + + // fail safe... + if (length == 0) + { + OnNext(new T[0]); + try { observer.OnCompleted(); } finally { Dispose(); } + return Disposable.Empty; + } + + completedCount = 0; + values = new T[length]; + + var subscriptions = new IDisposable[length]; + for (int index = 0; index < length; index++) + { + var source = sources[index]; + var observer = new WhenAllCollectionObserver(this, index); + subscriptions[index] = source.Subscribe(observer); + } + + return StableCompositeDisposable.CreateUnsafe(subscriptions); + } + + public override void OnNext(T[] value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class WhenAllCollectionObserver : IObserver + { + readonly WhenAll parent; + readonly int index; + bool isCompleted = false; + + public WhenAllCollectionObserver(WhenAll parent, int index) + { + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.values[index] = value; + } + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (!isCompleted) + { + isCompleted = true; + parent.completedCount++; + if (parent.completedCount == parent.length) + { + parent.OnNext(parent.values); + parent.OnCompleted(); + } + } + } + } + } + } + + class WhenAll_ : OperatorObserverBase + { + readonly IList> sources; + readonly object gate = new object(); + int completedCount; + int length; + T[] values; + + public WhenAll_(IList> sources, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.sources = sources; + } + + public IDisposable Run() + { + length = sources.Count; + + // fail safe... + if (length == 0) + { + OnNext(new T[0]); + try { observer.OnCompleted(); } finally { Dispose(); } + return Disposable.Empty; + } + + completedCount = 0; + values = new T[length]; + + var subscriptions = new IDisposable[length]; + for (int index = 0; index < length; index++) + { + var source = sources[index]; + var observer = new WhenAllCollectionObserver(this, index); + subscriptions[index] = source.Subscribe(observer); + } + + return StableCompositeDisposable.CreateUnsafe(subscriptions); + } + + public override void OnNext(T[] value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class WhenAllCollectionObserver : IObserver + { + readonly WhenAll_ parent; + readonly int index; + bool isCompleted = false; + + public WhenAllCollectionObserver(WhenAll_ parent, int index) + { + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.values[index] = value; + } + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (!isCompleted) + { + isCompleted = true; + parent.completedCount++; + if (parent.completedCount == parent.length) + { + parent.OnNext(parent.values); + parent.OnCompleted(); + } + } + } + } + } + } + } + + internal class WhenAllObservable : OperatorObservableBase + { + readonly IObservable[] sources; + readonly IEnumerable> sourcesEnumerable; + + public WhenAllObservable(IObservable[] sources) + : base(false) + { + this.sources = sources; + } + + public WhenAllObservable(IEnumerable> sources) + : base(false) + { + this.sourcesEnumerable = sources; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (sources != null) + { + return new WhenAll(this.sources, observer, cancel).Run(); + } + else + { + var xs = sourcesEnumerable as IList>; + if (xs == null) + { + xs = new List>(sourcesEnumerable); // materialize observables + } + return new WhenAll_(xs, observer, cancel).Run(); + } + } + + class WhenAll : OperatorObserverBase + { + readonly IObservable[] sources; + readonly object gate = new object(); + int completedCount; + int length; + + public WhenAll(IObservable[] sources, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.sources = sources; + } + + public IDisposable Run() + { + length = sources.Length; + + // fail safe... + if (length == 0) + { + OnNext(Unit.Default); + try { observer.OnCompleted(); } finally { Dispose(); } + return Disposable.Empty; + } + + completedCount = 0; + + var subscriptions = new IDisposable[length]; + for (int index = 0; index < sources.Length; index++) + { + var source = sources[index]; + var observer = new WhenAllCollectionObserver(this); + subscriptions[index] = source.Subscribe(observer); + } + + return StableCompositeDisposable.CreateUnsafe(subscriptions); + } + + public override void OnNext(Unit value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class WhenAllCollectionObserver : IObserver + { + readonly WhenAll parent; + bool isCompleted = false; + + public WhenAllCollectionObserver(WhenAll parent) + { + this.parent = parent; + } + + public void OnNext(Unit value) + { + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (!isCompleted) + { + isCompleted = true; + parent.completedCount++; + if (parent.completedCount == parent.length) + { + parent.OnNext(Unit.Default); + parent.OnCompleted(); + } + } + } + } + } + } + + class WhenAll_ : OperatorObserverBase + { + readonly IList> sources; + readonly object gate = new object(); + int completedCount; + int length; + + public WhenAll_(IList> sources, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.sources = sources; + } + + public IDisposable Run() + { + length = sources.Count; + + // fail safe... + if (length == 0) + { + OnNext(Unit.Default); + try { observer.OnCompleted(); } finally { Dispose(); } + return Disposable.Empty; + } + + completedCount = 0; + + var subscriptions = new IDisposable[length]; + for (int index = 0; index < length; index++) + { + var source = sources[index]; + var observer = new WhenAllCollectionObserver(this); + subscriptions[index] = source.Subscribe(observer); + } + + return StableCompositeDisposable.CreateUnsafe(subscriptions); + } + + public override void OnNext(Unit value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class WhenAllCollectionObserver : IObserver + { + readonly WhenAll_ parent; + bool isCompleted = false; + + public WhenAllCollectionObserver(WhenAll_ parent) + { + this.parent = parent; + } + + public void OnNext(Unit value) + { + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + if (!isCompleted) + { + parent.OnError(error); + } + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + if (!isCompleted) + { + isCompleted = true; + parent.completedCount++; + if (parent.completedCount == parent.length) + { + parent.OnNext(Unit.Default); + parent.OnCompleted(); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs.meta new file mode 100644 index 00000000..baddb5f3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhenAll.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0af8ada83db8f8a408ee6e9aa994fbbd +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs new file mode 100644 index 00000000..f9d9c057 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs @@ -0,0 +1,147 @@ +using System; + +namespace UniRx.Operators +{ + internal class WhereObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func predicate; + readonly Func predicateWithIndex; + + public WhereObservable(IObservable source, Func predicate) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + } + + public WhereObservable(IObservable source, Func predicateWithIndex) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicateWithIndex = predicateWithIndex; + } + + // Optimize for .Where().Where() + + public IObservable CombinePredicate(Func combinePredicate) + { + if (this.predicate != null) + { + return new WhereObservable(source, x => this.predicate(x) && combinePredicate(x)); + } + else + { + return new WhereObservable(this, combinePredicate); + } + } + + // Optimize for .Where().Select() + + public IObservable CombineSelector(Func selector) + { + if (this.predicate != null) + { + return new WhereSelectObservable(source, predicate, selector); + } + else + { + return new SelectObservable(this, selector); // can't combine + } + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + if (predicate != null) + { + return source.Subscribe(new Where(this, observer, cancel)); + } + else + { + return source.Subscribe(new Where_(this, observer, cancel)); + } + } + + class Where : OperatorObserverBase + { + readonly WhereObservable parent; + + public Where(WhereObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + var isPassed = false; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class Where_ : OperatorObserverBase + { + readonly WhereObservable parent; + int index; + + public Where_(WhereObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + this.index = 0; + } + + public override void OnNext(T value) + { + var isPassed = false; + try + { + isPassed = parent.predicateWithIndex(value, index++); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + observer.OnNext(value); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs.meta new file mode 100644 index 00000000..94769c87 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Where.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a035699dbe9572548afa47c460bad078 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs new file mode 100644 index 00000000..3a349124 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs @@ -0,0 +1,77 @@ +using System; + +namespace UniRx.Operators +{ + // Optimize for .Where().Select() + + internal class WhereSelectObservable : OperatorObservableBase + { + readonly IObservable source; + readonly Func predicate; + readonly Func selector; + + public WhereSelectObservable(IObservable source, Func predicate, Func selector) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.predicate = predicate; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return source.Subscribe(new WhereSelect(this, observer, cancel)); + } + + class WhereSelect : OperatorObserverBase + { + readonly WhereSelectObservable parent; + + public WhereSelect(WhereSelectObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public override void OnNext(T value) + { + var isPassed = false; + try + { + isPassed = parent.predicate(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + if (isPassed) + { + var v = default(TR); + try + { + v = parent.selector(value); + } + catch (Exception ex) + { + try { observer.OnError(ex); } finally { Dispose(); } + return; + } + + observer.OnNext(v); + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs.meta new file mode 100644 index 00000000..01b9e22c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WhereSelect.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f7453a184d42aa34c854977496f381b9 +timeCreated: 1468743755 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs new file mode 100644 index 00000000..e47be92b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + internal class WithLatestFromObservable : OperatorObservableBase + { + readonly IObservable left; + readonly IObservable right; + readonly Func selector; + + public WithLatestFromObservable(IObservable left, IObservable right, Func selector) + : base(left.IsRequiredSubscribeOnCurrentThread() || right.IsRequiredSubscribeOnCurrentThread()) + { + this.left = left; + this.right = right; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new WithLatestFrom(this, observer, cancel).Run(); + } + + class WithLatestFrom : OperatorObserverBase + { + readonly WithLatestFromObservable parent; + readonly object gate = new object(); + + volatile bool hasLatest; + TRight latestValue = default(TRight); + + public WithLatestFrom(WithLatestFromObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var l = parent.left.Subscribe(new LeftObserver(this)); + var rSubscription = new SingleAssignmentDisposable(); + rSubscription.Disposable = parent.right.Subscribe(new RightObserver(this, rSubscription)); + + return StableCompositeDisposable.Create(l, rSubscription); + } + + public override void OnNext(TResult value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class LeftObserver : IObserver + { + readonly WithLatestFrom parent; + + public LeftObserver(WithLatestFrom parent) + { + this.parent = parent; + } + + public void OnNext(TLeft value) + { + if (parent.hasLatest) + { + var result = default(TResult); + try + { + result = parent.parent.selector(value, parent.latestValue); + } + catch (Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + return; + } + + lock (parent.gate) + { + parent.OnNext(result); + } + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.OnCompleted(); + } + } + } + + class RightObserver : IObserver + { + readonly WithLatestFrom parent; + readonly IDisposable selfSubscription; + + public RightObserver(WithLatestFrom parent, IDisposable subscription) + { + this.parent = parent; + this.selfSubscription = subscription; + } + + public void OnNext(TRight value) + { + parent.latestValue = value; + parent.hasLatest = true; + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + selfSubscription.Dispose(); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs.meta new file mode 100644 index 00000000..1f6cafec --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/WithLatestFrom.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: eb0bc7125d343ed45bb7e36ff1a53362 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs new file mode 100644 index 00000000..05415e3a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs @@ -0,0 +1,1004 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + public delegate TR ZipFunc(T1 arg1, T2 arg2, T3 arg3); + public delegate TR ZipFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + public delegate TR ZipFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate TR ZipFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate TR ZipFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + // binary + internal class ZipObservable : OperatorObservableBase + { + readonly IObservable left; + readonly IObservable right; + readonly Func selector; + + public ZipObservable(IObservable left, IObservable right, Func selector) + : base(left.IsRequiredSubscribeOnCurrentThread() || right.IsRequiredSubscribeOnCurrentThread()) + { + this.left = left; + this.right = right; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : OperatorObserverBase + { + readonly ZipObservable parent; + + readonly object gate = new object(); + readonly Queue leftQ = new Queue(); + bool leftCompleted = false; + readonly Queue rightQ = new Queue(); + bool rightCompleted = false; + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var l = parent.left.Subscribe(new LeftZipObserver(this)); + var r = parent.right.Subscribe(new RightZipObserver(this)); + + return StableCompositeDisposable.Create(l, r, Disposable.Create(() => + { + lock (gate) + { + leftQ.Clear(); + rightQ.Clear(); + } + })); + } + + // dequeue is in the lock + void Dequeue() + { + TLeft lv; + TRight rv; + TResult v; + + if (leftQ.Count != 0 && rightQ.Count != 0) + { + lv = leftQ.Dequeue(); + rv = rightQ.Dequeue(); + } + else if (leftCompleted || rightCompleted) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + return; + } + + try + { + v = parent.selector(lv, rv); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + OnNext(v); + } + + public override void OnNext(TResult value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class LeftZipObserver : IObserver + { + readonly Zip parent; + + public LeftZipObserver(Zip parent) + { + this.parent = parent; + } + + public void OnNext(TLeft value) + { + lock (parent.gate) + { + parent.leftQ.Enqueue(value); + parent.Dequeue(); + } + } + + public void OnError(Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.leftCompleted = true; + if (parent.rightCompleted) parent.OnCompleted(); + } + } + } + + class RightZipObserver : IObserver + { + readonly Zip parent; + + public RightZipObserver(Zip parent) + { + this.parent = parent; + } + + public void OnNext(TRight value) + { + lock (parent.gate) + { + parent.rightQ.Enqueue(value); + parent.Dequeue(); + } + } + + public void OnError(Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.rightCompleted = true; + if (parent.leftCompleted) parent.OnCompleted(); + } + } + } + } + } + + // array + internal class ZipObservable : OperatorObservableBase> + { + readonly IObservable[] sources; + + public ZipObservable(IObservable[] sources) + : base(true) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : OperatorObserverBase, IList> + { + readonly ZipObservable parent; + readonly object gate = new object(); + + Queue[] queues; + bool[] isDone; + int length; + + public Zip(ZipObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + length = parent.sources.Length; + queues = new Queue[length]; + isDone = new bool[length]; + + for (int i = 0; i < length; i++) + { + queues[i] = new Queue(); + } + + var disposables = new IDisposable[length + 1]; + for (int i = 0; i < length; i++) + { + var source = parent.sources[i]; + disposables[i] = source.Subscribe(new ZipObserver(this, i)); + } + + disposables[length] = Disposable.Create(() => + { + lock (gate) + { + for (int i = 0; i < length; i++) + { + var q = queues[i]; + q.Clear(); + } + } + }); + + return StableCompositeDisposable.CreateUnsafe(disposables); + } + + // dequeue is in the lock + void Dequeue(int index) + { + var allQueueHasValue = true; + for (int i = 0; i < length; i++) + { + if (queues[i].Count == 0) + { + allQueueHasValue = false; + break; + } + } + + if (!allQueueHasValue) + { + var allCompletedWithoutSelf = true; + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (!isDone[i]) + { + allCompletedWithoutSelf = false; + break; + } + } + + if (allCompletedWithoutSelf) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + return; + } + } + + var array = new T[length]; + for (int i = 0; i < length; i++) + { + array[i] = queues[i].Dequeue(); + } + + OnNext(array); + } + + public override void OnNext(IList value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class ZipObserver : IObserver + { + readonly Zip parent; + readonly int index; + + public ZipObserver(Zip parent, int index) + { + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + parent.queues[index].Enqueue(value); + parent.Dequeue(index); + } + } + + public void OnError(Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.isDone[index] = true; + var allTrue = true; + for (int i = 0; i < parent.length; i++) + { + if (!parent.isDone[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + parent.OnCompleted(); + } + } + } + } + } + } + + // Generated from UniRx.Console.ZipGenerator.tt + #region NTH + + internal class ZipObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + ZipFunc resultSelector; + + public ZipObservable( + IObservable source1, + IObservable source2, + IObservable source3, + ZipFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : NthZipObserverBase + { + readonly ZipObservable parent; + readonly object gate = new object(); + readonly Queue q1 = new Queue(); + readonly Queue q2 = new Queue(); + readonly Queue q3 = new Queue(); + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + base.SetQueue(new System.Collections.ICollection[] { q1, q2, q3 }); + var s1 = parent.source1.Subscribe(new ZipObserver(gate, this, 0, q1)); + var s2 = parent.source2.Subscribe(new ZipObserver(gate, this, 1, q2)); + var s3 = parent.source3.Subscribe(new ZipObserver(gate, this, 2, q3)); + + return StableCompositeDisposable.Create(s1, s2, s3, Disposable.Create(() => + { + lock (gate) + { + q1.Clear(); q2.Clear(); q3.Clear(); + } + })); + } + + public override TR GetResult() + { + return parent.resultSelector(q1.Dequeue(), q2.Dequeue(), q3.Dequeue()); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + ZipFunc resultSelector; + + public ZipObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + ZipFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : NthZipObserverBase + { + readonly ZipObservable parent; + readonly object gate = new object(); + readonly Queue q1 = new Queue(); + readonly Queue q2 = new Queue(); + readonly Queue q3 = new Queue(); + readonly Queue q4 = new Queue(); + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + base.SetQueue(new System.Collections.ICollection[] { q1, q2, q3, q4 }); + var s1 = parent.source1.Subscribe(new ZipObserver(gate, this, 0, q1)); + var s2 = parent.source2.Subscribe(new ZipObserver(gate, this, 1, q2)); + var s3 = parent.source3.Subscribe(new ZipObserver(gate, this, 2, q3)); + var s4 = parent.source4.Subscribe(new ZipObserver(gate, this, 3, q4)); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, Disposable.Create(() => + { + lock (gate) + { + q1.Clear(); q2.Clear(); q3.Clear(); q4.Clear(); + } + })); + } + + public override TR GetResult() + { + return parent.resultSelector(q1.Dequeue(), q2.Dequeue(), q3.Dequeue(), q4.Dequeue()); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + ZipFunc resultSelector; + + public ZipObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + ZipFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : NthZipObserverBase + { + readonly ZipObservable parent; + readonly object gate = new object(); + readonly Queue q1 = new Queue(); + readonly Queue q2 = new Queue(); + readonly Queue q3 = new Queue(); + readonly Queue q4 = new Queue(); + readonly Queue q5 = new Queue(); + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + base.SetQueue(new System.Collections.ICollection[] { q1, q2, q3, q4, q5 }); + var s1 = parent.source1.Subscribe(new ZipObserver(gate, this, 0, q1)); + var s2 = parent.source2.Subscribe(new ZipObserver(gate, this, 1, q2)); + var s3 = parent.source3.Subscribe(new ZipObserver(gate, this, 2, q3)); + var s4 = parent.source4.Subscribe(new ZipObserver(gate, this, 3, q4)); + var s5 = parent.source5.Subscribe(new ZipObserver(gate, this, 4, q5)); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, Disposable.Create(() => + { + lock (gate) + { + q1.Clear(); q2.Clear(); q3.Clear(); q4.Clear(); q5.Clear(); + } + })); + } + + public override TR GetResult() + { + return parent.resultSelector(q1.Dequeue(), q2.Dequeue(), q3.Dequeue(), q4.Dequeue(), q5.Dequeue()); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + ZipFunc resultSelector; + + public ZipObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + ZipFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : NthZipObserverBase + { + readonly ZipObservable parent; + readonly object gate = new object(); + readonly Queue q1 = new Queue(); + readonly Queue q2 = new Queue(); + readonly Queue q3 = new Queue(); + readonly Queue q4 = new Queue(); + readonly Queue q5 = new Queue(); + readonly Queue q6 = new Queue(); + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + base.SetQueue(new System.Collections.ICollection[] { q1, q2, q3, q4, q5, q6 }); + var s1 = parent.source1.Subscribe(new ZipObserver(gate, this, 0, q1)); + var s2 = parent.source2.Subscribe(new ZipObserver(gate, this, 1, q2)); + var s3 = parent.source3.Subscribe(new ZipObserver(gate, this, 2, q3)); + var s4 = parent.source4.Subscribe(new ZipObserver(gate, this, 3, q4)); + var s5 = parent.source5.Subscribe(new ZipObserver(gate, this, 4, q5)); + var s6 = parent.source6.Subscribe(new ZipObserver(gate, this, 5, q6)); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6, Disposable.Create(() => + { + lock (gate) + { + q1.Clear(); q2.Clear(); q3.Clear(); q4.Clear(); q5.Clear(); q6.Clear(); + } + })); + } + + public override TR GetResult() + { + return parent.resultSelector(q1.Dequeue(), q2.Dequeue(), q3.Dequeue(), q4.Dequeue(), q5.Dequeue(), q6.Dequeue()); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + IObservable source7; + ZipFunc resultSelector; + + public ZipObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + IObservable source7, + ZipFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + source7.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.source7 = source7; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new Zip(this, observer, cancel).Run(); + } + + class Zip : NthZipObserverBase + { + readonly ZipObservable parent; + readonly object gate = new object(); + readonly Queue q1 = new Queue(); + readonly Queue q2 = new Queue(); + readonly Queue q3 = new Queue(); + readonly Queue q4 = new Queue(); + readonly Queue q5 = new Queue(); + readonly Queue q6 = new Queue(); + readonly Queue q7 = new Queue(); + + public Zip(ZipObservable parent, IObserver observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + base.SetQueue(new System.Collections.ICollection[] { q1, q2, q3, q4, q5, q6, q7 }); + var s1 = parent.source1.Subscribe(new ZipObserver(gate, this, 0, q1)); + var s2 = parent.source2.Subscribe(new ZipObserver(gate, this, 1, q2)); + var s3 = parent.source3.Subscribe(new ZipObserver(gate, this, 2, q3)); + var s4 = parent.source4.Subscribe(new ZipObserver(gate, this, 3, q4)); + var s5 = parent.source5.Subscribe(new ZipObserver(gate, this, 4, q5)); + var s6 = parent.source6.Subscribe(new ZipObserver(gate, this, 5, q6)); + var s7 = parent.source7.Subscribe(new ZipObserver(gate, this, 6, q7)); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6, s7, Disposable.Create(() => + { + lock (gate) + { + q1.Clear(); q2.Clear(); q3.Clear(); q4.Clear(); q5.Clear(); q6.Clear(); q7.Clear(); + } + })); + } + + public override TR GetResult() + { + return parent.resultSelector(q1.Dequeue(), q2.Dequeue(), q3.Dequeue(), q4.Dequeue(), q5.Dequeue(), q6.Dequeue(), q7.Dequeue()); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + #endregion + + // Nth infrastructure + + internal interface IZipObservable + { + void Dequeue(int index); + void Fail(Exception error); + void Done(int index); + } + + internal abstract class NthZipObserverBase : OperatorObserverBase, IZipObservable + { + System.Collections.ICollection[] queues; + bool[] isDone; + int length; + + public NthZipObserverBase(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + protected void SetQueue(System.Collections.ICollection[] queues) + { + this.queues = queues; + this.length = queues.Length; + this.isDone = new bool[length]; + } + + public abstract T GetResult(); + + // operators in lock + public void Dequeue(int index) + { + var allQueueHasValue = true; + for (int i = 0; i < length; i++) + { + if (queues[i].Count == 0) + { + allQueueHasValue = false; + break; + } + } + + if (!allQueueHasValue) + { + var allCompletedWithoutSelf = true; + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (!isDone[i]) + { + allCompletedWithoutSelf = false; + break; + } + } + + if (allCompletedWithoutSelf) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + return; + } + } + + var result = default(T); + try + { + result = GetResult(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + OnNext(result); + } + + public void Done(int index) + { + isDone[index] = true; + var allTrue = true; + for (int i = 0; i < length; i++) + { + if (!isDone[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + + public void Fail(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + } + + + // nth + internal class ZipObserver : IObserver + { + readonly object gate; + readonly IZipObservable parent; + readonly int index; + readonly Queue queue; + + public ZipObserver(object gate, IZipObservable parent, int index, Queue queue) + { + this.gate = gate; + this.parent = parent; + this.index = index; + this.queue = queue; + } + + public void OnNext(T value) + { + lock (gate) + { + queue.Enqueue(value); + parent.Dequeue(index); + } + } + + public void OnError(Exception error) + { + lock (gate) + { + parent.Fail(error); + } + } + + public void OnCompleted() + { + lock (gate) + { + parent.Done(index); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs.meta new file mode 100644 index 00000000..54caad4e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/Zip.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4e92e25f9bb221d478d4af5bcd8b8a2c +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs new file mode 100644 index 00000000..161a0367 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs @@ -0,0 +1,992 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniRx.Operators +{ + public delegate TR ZipLatestFunc(T1 arg1, T2 arg2, T3 arg3); + public delegate TR ZipLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + public delegate TR ZipLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate TR ZipLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate TR ZipLatestFunc(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + + // binary + internal class ZipLatestObservable : OperatorObservableBase + { + readonly IObservable left; + readonly IObservable right; + readonly Func selector; + + public ZipLatestObservable(IObservable left, IObservable right, Func selector) + : base(left.IsRequiredSubscribeOnCurrentThread() || right.IsRequiredSubscribeOnCurrentThread()) + { + this.left = left; + this.right = right; + this.selector = selector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(this, observer, cancel).Run(); + } + + class ZipLatest : OperatorObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + + TLeft leftValue = default(TLeft); + bool leftStarted = false; + bool leftCompleted = false; + + TRight rightValue = default(TRight); + bool rightStarted = false; + bool rightCompleted = false; + + public ZipLatest(ZipLatestObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + var l = parent.left.Subscribe(new LeftObserver(this)); + var r = parent.right.Subscribe(new RightObserver(this)); + + return StableCompositeDisposable.Create(l, r); + } + + // publish in lock + public void Publish() + { + if ((leftCompleted && !leftStarted) || (rightCompleted && !rightStarted)) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else if (!(leftStarted && rightStarted)) + { + return; + } + + TResult v; + try + { + v = parent.selector(leftValue, rightValue); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + + OnNext(v); + leftStarted = false; + rightStarted = false; + + if (leftCompleted || rightCompleted) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + } + + public override void OnNext(TResult value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class LeftObserver : IObserver + { + readonly ZipLatest parent; + + public LeftObserver(ZipLatest parent) + { + this.parent = parent; + } + + public void OnNext(TLeft value) + { + lock (parent.gate) + { + parent.leftStarted = true; + parent.leftValue = value; + parent.Publish(); + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.leftCompleted = true; + if (parent.rightCompleted) parent.OnCompleted(); + } + } + } + + class RightObserver : IObserver + { + readonly ZipLatest parent; + + public RightObserver(ZipLatest parent) + { + this.parent = parent; + } + + + public void OnNext(TRight value) + { + lock (parent.gate) + { + parent.rightStarted = true; + parent.rightValue = value; + parent.Publish(); + } + } + + public void OnError(Exception error) + { + lock (parent.gate) + { + parent.OnError(error); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.rightCompleted = true; + if (parent.leftCompleted) parent.OnCompleted(); + } + } + } + } + } + + // array + internal class ZipLatestObservable : OperatorObservableBase> + { + readonly IObservable[] sources; + + public ZipLatestObservable(IObservable[] sources) + : base(true) + { + this.sources = sources; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new ZipLatest(this, observer, cancel).Run(); + } + + class ZipLatest : OperatorObserverBase, IList> + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + + int length; + T[] values; + bool[] isStarted; + bool[] isCompleted; + + public ZipLatest(ZipLatestObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + length = parent.sources.Length; + values = new T[length]; + isStarted = new bool[length]; + isCompleted = new bool[length]; + + var disposables = new IDisposable[length]; + for (int i = 0; i < length; i++) + { + var source = parent.sources[i]; + disposables[i] = source.Subscribe(new ZipLatestObserver(this, i)); + } + + return StableCompositeDisposable.CreateUnsafe(disposables); + } + + // publish is in the lock + void Publish(int index) + { + isStarted[index] = true; + + var hasOnCompleted = false; + var allValueStarted = true; + for (int i = 0; i < length; i++) + { + if (!isStarted[i]) + { + allValueStarted = false; + break; + } + if (i == index) continue; + if (isCompleted[i]) hasOnCompleted = true; + } + + if (allValueStarted) + { + OnNext(new List(values)); + if (hasOnCompleted) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + Array.Clear(isStarted, 0, length); // reset + return; + } + } + else + { + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (isCompleted[i] && !isStarted[i]) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + } + } + } + + public override void OnNext(IList value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + + class ZipLatestObserver : IObserver + { + readonly ZipLatest parent; + readonly int index; + + public ZipLatestObserver(ZipLatest parent, int index) + { + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (parent.gate) + { + parent.values[index] = value; + parent.Publish(index); + } + } + + public void OnError(Exception ex) + { + lock (parent.gate) + { + parent.OnError(ex); + } + } + + public void OnCompleted() + { + lock (parent.gate) + { + parent.isCompleted[index] = true; + + var allTrue = true; + for (int i = 0; i < parent.length; i++) + { + if (!parent.isCompleted[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + parent.OnCompleted(); + } + } + } + } + } + } + + // generated from UniRx.Console.ZipLatestGenerator.tt + #region NTH + + internal class ZipLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + ZipLatestFunc resultSelector; + + public ZipLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + ZipLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(3, this, observer, cancel).Run(); + } + + class ZipLatest : NthZipLatestObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + ZipLatestObserver c1; + ZipLatestObserver c2; + ZipLatestObserver c3; + + public ZipLatest(int length, ZipLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new ZipLatestObserver(gate, this, 0); + c2 = new ZipLatestObserver(gate, this, 1); + c3 = new ZipLatestObserver(gate, this, 2); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + + return StableCompositeDisposable.Create(s1, s2, s3); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + ZipLatestFunc resultSelector; + + public ZipLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + ZipLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(4, this, observer, cancel).Run(); + } + + class ZipLatest : NthZipLatestObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + ZipLatestObserver c1; + ZipLatestObserver c2; + ZipLatestObserver c3; + ZipLatestObserver c4; + + public ZipLatest(int length, ZipLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new ZipLatestObserver(gate, this, 0); + c2 = new ZipLatestObserver(gate, this, 1); + c3 = new ZipLatestObserver(gate, this, 2); + c4 = new ZipLatestObserver(gate, this, 3); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + + return StableCompositeDisposable.Create(s1, s2, s3, s4); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + ZipLatestFunc resultSelector; + + public ZipLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + ZipLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(5, this, observer, cancel).Run(); + } + + class ZipLatest : NthZipLatestObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + ZipLatestObserver c1; + ZipLatestObserver c2; + ZipLatestObserver c3; + ZipLatestObserver c4; + ZipLatestObserver c5; + + public ZipLatest(int length, ZipLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new ZipLatestObserver(gate, this, 0); + c2 = new ZipLatestObserver(gate, this, 1); + c3 = new ZipLatestObserver(gate, this, 2); + c4 = new ZipLatestObserver(gate, this, 3); + c5 = new ZipLatestObserver(gate, this, 4); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + ZipLatestFunc resultSelector; + + public ZipLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + ZipLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(6, this, observer, cancel).Run(); + } + + class ZipLatest : NthZipLatestObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + ZipLatestObserver c1; + ZipLatestObserver c2; + ZipLatestObserver c3; + ZipLatestObserver c4; + ZipLatestObserver c5; + ZipLatestObserver c6; + + public ZipLatest(int length, ZipLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new ZipLatestObserver(gate, this, 0); + c2 = new ZipLatestObserver(gate, this, 1); + c3 = new ZipLatestObserver(gate, this, 2); + c4 = new ZipLatestObserver(gate, this, 3); + c5 = new ZipLatestObserver(gate, this, 4); + c6 = new ZipLatestObserver(gate, this, 5); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + var s6 = parent.source6.Subscribe(c6); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + + internal class ZipLatestObservable : OperatorObservableBase + { + IObservable source1; + IObservable source2; + IObservable source3; + IObservable source4; + IObservable source5; + IObservable source6; + IObservable source7; + ZipLatestFunc resultSelector; + + public ZipLatestObservable( + IObservable source1, + IObservable source2, + IObservable source3, + IObservable source4, + IObservable source5, + IObservable source6, + IObservable source7, + ZipLatestFunc resultSelector) + : base( + source1.IsRequiredSubscribeOnCurrentThread() || + source2.IsRequiredSubscribeOnCurrentThread() || + source3.IsRequiredSubscribeOnCurrentThread() || + source4.IsRequiredSubscribeOnCurrentThread() || + source5.IsRequiredSubscribeOnCurrentThread() || + source6.IsRequiredSubscribeOnCurrentThread() || + source7.IsRequiredSubscribeOnCurrentThread() || + false) + { + this.source1 = source1; + this.source2 = source2; + this.source3 = source3; + this.source4 = source4; + this.source5 = source5; + this.source6 = source6; + this.source7 = source7; + this.resultSelector = resultSelector; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ZipLatest(7, this, observer, cancel).Run(); + } + + class ZipLatest : NthZipLatestObserverBase + { + readonly ZipLatestObservable parent; + readonly object gate = new object(); + ZipLatestObserver c1; + ZipLatestObserver c2; + ZipLatestObserver c3; + ZipLatestObserver c4; + ZipLatestObserver c5; + ZipLatestObserver c6; + ZipLatestObserver c7; + + public ZipLatest(int length, ZipLatestObservable parent, IObserver observer, IDisposable cancel) + : base(length, observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + c1 = new ZipLatestObserver(gate, this, 0); + c2 = new ZipLatestObserver(gate, this, 1); + c3 = new ZipLatestObserver(gate, this, 2); + c4 = new ZipLatestObserver(gate, this, 3); + c5 = new ZipLatestObserver(gate, this, 4); + c6 = new ZipLatestObserver(gate, this, 5); + c7 = new ZipLatestObserver(gate, this, 6); + + var s1 = parent.source1.Subscribe(c1); + var s2 = parent.source2.Subscribe(c2); + var s3 = parent.source3.Subscribe(c3); + var s4 = parent.source4.Subscribe(c4); + var s5 = parent.source5.Subscribe(c5); + var s6 = parent.source6.Subscribe(c6); + var s7 = parent.source7.Subscribe(c7); + + return StableCompositeDisposable.Create(s1, s2, s3, s4, s5, s6, s7); + } + + public override TR GetResult() + { + return parent.resultSelector(c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value, c7.Value); + } + + public override void OnNext(TR value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + #endregion + + // Nth infrastructure + + internal interface IZipLatestObservable + { + void Publish(int index); + void Fail(Exception error); + void Done(int index); + } + + internal abstract class NthZipLatestObserverBase : OperatorObserverBase, IZipLatestObservable + { + readonly int length; + readonly bool[] isStarted; + readonly bool[] isCompleted; + + public NthZipLatestObserverBase(int length, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.length = length; + this.isStarted = new bool[length]; + this.isCompleted = new bool[length]; + } + + public abstract T GetResult(); + + // operators in lock + public void Publish(int index) + { + isStarted[index] = true; + + var hasOnCompleted = false; + var allValueStarted = true; + for (int i = 0; i < length; i++) + { + if (!isStarted[i]) + { + allValueStarted = false; + break; + } + if (i == index) continue; + if (isCompleted[i]) hasOnCompleted = true; + } + + if (allValueStarted) + { + var result = default(T); + try + { + result = GetResult(); + } + catch (Exception ex) + { + try { observer.OnError(ex); } + finally { Dispose(); } + return; + } + OnNext(result); + + if (hasOnCompleted) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + else + { + Array.Clear(isStarted, 0, length); // reset + return; + } + } + else + { + for (int i = 0; i < length; i++) + { + if (i == index) continue; + if (isCompleted[i] && !isStarted[i]) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + return; + } + } + } + } + + public void Done(int index) + { + isCompleted[index] = true; + + var allTrue = true; + for (int i = 0; i < length; i++) + { + if (!isCompleted[i]) + { + allTrue = false; + break; + } + } + + if (allTrue) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + + public void Fail(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + } + + // Nth + internal class ZipLatestObserver : IObserver + { + readonly object gate; + readonly IZipLatestObservable parent; + readonly int index; + T value; + + public T Value { get { return value; } } + + public ZipLatestObserver(object gate, IZipLatestObservable parent, int index) + { + this.gate = gate; + this.parent = parent; + this.index = index; + } + + public void OnNext(T value) + { + lock (gate) + { + this.value = value; + parent.Publish(index); + } + } + + public void OnError(Exception error) + { + lock (gate) + { + parent.Fail(error); + } + } + + public void OnCompleted() + { + lock (gate) + { + parent.Done(index); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs.meta new file mode 100644 index 00000000..bebb06b0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Operators/ZipLatest.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f84ea50040d682c43811d1d98ae7fec8 +timeCreated: 1455373908 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs new file mode 100644 index 00000000..df594d3a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; + +namespace UniRx +{ + // Pair is used for Observable.Pairwise + [Serializable] + public struct Pair : IEquatable> + { + readonly T previous; + readonly T current; + + public T Previous + { + get { return previous; } + } + + public T Current + { + get { return current; } + } + + public Pair(T previous, T current) + { + this.previous = previous; + this.current = current; + } + + public override int GetHashCode() + { + var comparer = EqualityComparer.Default; + + int h0; + h0 = comparer.GetHashCode(previous); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(current); + return h0; + } + + public override bool Equals(object obj) + { + if (!(obj is Pair)) return false; + + return Equals((Pair)obj); + } + + public bool Equals(Pair other) + { + var comparer = EqualityComparer.Default; + + return comparer.Equals(previous, other.Previous) && + comparer.Equals(current, other.Current); + } + + public override string ToString() + { + return string.Format("({0}, {1})", previous, current); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs.meta new file mode 100644 index 00000000..923587a3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Pair.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7947c520dfd9de94bb381e45dc105752 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers.meta new file mode 100644 index 00000000..e5395795 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ca4cbb2e99a69854d93ad929ef72117b +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs new file mode 100644 index 00000000..8e54c289 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs @@ -0,0 +1,135 @@ +// this code is borrowed from RxOfficial(rx.codeplex.com) and modified + +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System.ComponentModel; +using System.Threading; +using UniRx.InternalUtil; +using UniRx; +using System; +using System.Diagnostics; +using System.Collections.Generic; + +namespace UniRx +{ + + public static partial class Scheduler + { + public static readonly IScheduler CurrentThread = new CurrentThreadScheduler(); + + public static bool IsCurrentThreadSchedulerScheduleRequired { get { return CurrentThreadScheduler.IsScheduleRequired; } } + + /// + /// Represents an object that schedules units of work on the current thread. + /// + /// Singleton instance of this type exposed through this static property. + class CurrentThreadScheduler : IScheduler + { + [ThreadStatic] + static SchedulerQueue s_threadLocalQueue; + + [ThreadStatic] + static Stopwatch s_clock; + + private static SchedulerQueue GetQueue() + { + return s_threadLocalQueue; + } + + private static void SetQueue(SchedulerQueue newQueue) + { + s_threadLocalQueue = newQueue; + } + + private static TimeSpan Time + { + get + { + if (s_clock == null) + s_clock = Stopwatch.StartNew(); + + return s_clock.Elapsed; + } + } + + /// + /// Gets a value that indicates whether the caller must call a Schedule method. + /// + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static bool IsScheduleRequired + { + get + { + return GetQueue() == null; + } + } + + public IDisposable Schedule(Action action) + { + return Schedule(TimeSpan.Zero, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + if (action == null) + throw new ArgumentNullException("action"); + + var dt = Time + Scheduler.Normalize(dueTime); + + var si = new ScheduledItem(action, dt); + + var queue = GetQueue(); + + if (queue == null) + { + queue = new SchedulerQueue(4); + queue.Enqueue(si); + + CurrentThreadScheduler.SetQueue(queue); + try + { + Trampoline.Run(queue); + } + finally + { + CurrentThreadScheduler.SetQueue(null); + } + } + else + { + queue.Enqueue(si); + } + + return si.Cancellation; + } + + static class Trampoline + { + public static void Run(SchedulerQueue queue) + { + while (queue.Count > 0) + { + var item = queue.Dequeue(); + if (!item.IsCanceled) + { + var wait = item.DueTime - CurrentThreadScheduler.Time; + if (wait.Ticks > 0) + { + Thread.Sleep(wait); + } + + if (!item.IsCanceled) + item.Invoke(); + } + } + } + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + } + } +} + diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs.meta new file mode 100644 index 00000000..551399f0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/CurrentThreadScheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d547b5ee71b7284db1fecfcdfa59fac +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs new file mode 100644 index 00000000..61328977 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs @@ -0,0 +1,30 @@ +using System; + +namespace UniRx +{ + public interface IScheduler + { + DateTimeOffset Now { get; } + + // Interface is changed from official Rx for avoid iOS AOT problem (state is dangerous). + + IDisposable Schedule(Action action); + + IDisposable Schedule(TimeSpan dueTime, Action action); + } + + public interface ISchedulerPeriodic + { + IDisposable SchedulePeriodic(TimeSpan period, Action action); + } + + public interface ISchedulerLongRunning + { + IDisposable ScheduleLongRunning(Action action); + } + + public interface ISchedulerQueueing + { + void ScheduleQueueing(ICancelable cancel, T state, Action action); + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs.meta new file mode 100644 index 00000000..e356837f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/IScheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7409b202c20d3894b9677c8f2a27f3aa +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs new file mode 100644 index 00000000..0e64af55 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace UniRx +{ + public static partial class Scheduler + { + public static readonly IScheduler Immediate = new ImmediateScheduler(); + + class ImmediateScheduler : IScheduler + { + public ImmediateScheduler() + { + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + public IDisposable Schedule(Action action) + { + action(); + return Disposable.Empty; + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var wait = Scheduler.Normalize(dueTime); + if (wait.Ticks > 0) + { + Thread.Sleep(wait); + } + + action(); + return Disposable.Empty; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs.meta new file mode 100644 index 00000000..00163638 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ImmediateScheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 87be5fca34f9b44428b7fb1ce9147860 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs new file mode 100644 index 00000000..6f1a236c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace UniRx +{ + // Scheduler Extension + public static partial class Scheduler + { + // configurable defaults + public static class DefaultSchedulers + { + static IScheduler constantTime; + public static IScheduler ConstantTimeOperations + { + get + { + return constantTime ?? (constantTime = Scheduler.Immediate); + } + set + { + constantTime = value; + } + } + + static IScheduler tailRecursion; + public static IScheduler TailRecursion + { + get + { + return tailRecursion ?? (tailRecursion = Scheduler.Immediate); + } + set + { + tailRecursion = value; + } + } + + static IScheduler iteration; + public static IScheduler Iteration + { + get + { + return iteration ?? (iteration = Scheduler.CurrentThread); + } + set + { + iteration = value; + } + } + + static IScheduler timeBasedOperations; + public static IScheduler TimeBasedOperations + { + get + { +#if UniRxLibrary + return timeBasedOperations ?? (timeBasedOperations = Scheduler.ThreadPool); +#else + return timeBasedOperations ?? (timeBasedOperations = Scheduler.MainThread); // MainThread as default for TimeBased Operation +#endif + } + set + { + timeBasedOperations = value; + } + } + + static IScheduler asyncConversions; + public static IScheduler AsyncConversions + { + get + { +#if WEB_GL + // WebGL does not support threadpool + return asyncConversions ?? (asyncConversions = Scheduler.MainThread); +#else + return asyncConversions ?? (asyncConversions = Scheduler.ThreadPool); +#endif + } + set + { + asyncConversions = value; + } + } + + public static void SetDotNetCompatible() + { + ConstantTimeOperations = Scheduler.Immediate; + TailRecursion = Scheduler.Immediate; + Iteration = Scheduler.CurrentThread; + TimeBasedOperations = Scheduler.ThreadPool; + AsyncConversions = Scheduler.ThreadPool; + } + } + + // utils + + public static DateTimeOffset Now + { + get { return DateTimeOffset.UtcNow; } + } + + public static TimeSpan Normalize(TimeSpan timeSpan) + { + return timeSpan >= TimeSpan.Zero ? timeSpan : TimeSpan.Zero; + } + + public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action action) + { + return scheduler.Schedule(dueTime - scheduler.Now, action); + } + + public static IDisposable Schedule(this IScheduler scheduler, Action action) + { + // InvokeRec1 + var group = new CompositeDisposable(1); + var gate = new object(); + + Action recursiveAction = null; + recursiveAction = () => action(() => + { + var isAdded = false; + var isDone = false; + var d = default(IDisposable); + d = scheduler.Schedule(() => + { + lock (gate) + { + if (isAdded) + group.Remove(d); + else + isDone = true; + } + recursiveAction(); + }); + + lock (gate) + { + if (!isDone) + { + group.Add(d); + isAdded = true; + } + } + }); + + group.Add(scheduler.Schedule(recursiveAction)); + + return group; + } + + public static IDisposable Schedule(this IScheduler scheduler, TimeSpan dueTime, Action> action) + { + // InvokeRec2 + + var group = new CompositeDisposable(1); + var gate = new object(); + + Action recursiveAction = null; + recursiveAction = () => action(dt => + { + var isAdded = false; + var isDone = false; + var d = default(IDisposable); + d = scheduler.Schedule(dt, () => + { + lock (gate) + { + if (isAdded) + group.Remove(d); + else + isDone = true; + } + recursiveAction(); + }); + + lock (gate) + { + if (!isDone) + { + group.Add(d); + isAdded = true; + } + } + }); + + group.Add(scheduler.Schedule(dueTime, recursiveAction)); + + return group; + } + + public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action> action) + { + // InvokeRec3 + + var group = new CompositeDisposable(1); + var gate = new object(); + + Action recursiveAction = null; + recursiveAction = () => action(dt => + { + var isAdded = false; + var isDone = false; + var d = default(IDisposable); + d = scheduler.Schedule(dt, () => + { + lock (gate) + { + if (isAdded) + group.Remove(d); + else + isDone = true; + } + recursiveAction(); + }); + + lock (gate) + { + if (!isDone) + { + group.Add(d); + isAdded = true; + } + } + }); + + group.Add(scheduler.Schedule(dueTime, recursiveAction)); + + return group; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs.meta new file mode 100644 index 00000000..960463a0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/Scheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bfeb53a7ea29f714798ba6bb3bd70ba4 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs new file mode 100644 index 00000000..ac510a0c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs @@ -0,0 +1,197 @@ +#if !UNITY_METRO + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using UniRx.InternalUtil; + +namespace UniRx +{ + public static partial class Scheduler + { + public static readonly IScheduler ThreadPool = new ThreadPoolScheduler(); + + class ThreadPoolScheduler : IScheduler, ISchedulerPeriodic + { + public ThreadPoolScheduler() + { + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + public IDisposable Schedule(Action action) + { + var d = new BooleanDisposable(); + + System.Threading.ThreadPool.QueueUserWorkItem(_ => + { + if (!d.IsDisposed) + { + action(); + } + }); + + return d; + } + + public IDisposable Schedule(DateTimeOffset dueTime, Action action) + { + return Schedule(dueTime - Now, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + return new Timer(dueTime, action); + } + + public IDisposable SchedulePeriodic(TimeSpan period, Action action) + { + return new PeriodicTimer(period, action); + } + + public void ScheduleQueueing(ICancelable cancel, T state, Action action) + { + System.Threading.ThreadPool.QueueUserWorkItem(callBackState => + { + if (!cancel.IsDisposed) + { + action((T)callBackState); + } + }, state); + } + + // timer was borrwed from Rx Official + + sealed class Timer : IDisposable + { + static readonly HashSet s_timers = new HashSet(); + + private readonly SingleAssignmentDisposable _disposable; + + private Action _action; + private System.Threading.Timer _timer; + + private bool _hasAdded; + private bool _hasRemoved; + + public Timer(TimeSpan dueTime, Action action) + { + _disposable = new SingleAssignmentDisposable(); + _disposable.Disposable = Disposable.Create(Unroot); + + _action = action; + _timer = new System.Threading.Timer(Tick, null, dueTime, TimeSpan.FromMilliseconds(System.Threading.Timeout.Infinite)); + + lock (s_timers) + { + if (!_hasRemoved) + { + s_timers.Add(_timer); + + _hasAdded = true; + } + } + } + + private void Tick(object state) + { + try + { + if (!_disposable.IsDisposed) + { + _action(); + } + } + finally + { + Unroot(); + } + } + + private void Unroot() + { + _action = Stubs.Nop; + + var timer = default(System.Threading.Timer); + + lock (s_timers) + { + if (!_hasRemoved) + { + timer = _timer; + _timer = null; + + if (_hasAdded && timer != null) + s_timers.Remove(timer); + + _hasRemoved = true; + } + } + + if (timer != null) + timer.Dispose(); + } + + public void Dispose() + { + _disposable.Dispose(); + } + } + + sealed class PeriodicTimer : IDisposable + { + static readonly HashSet s_timers = new HashSet(); + + private Action _action; + private System.Threading.Timer _timer; + private readonly AsyncLock _gate; + + public PeriodicTimer(TimeSpan period, Action action) + { + this._action = action; + this._timer = new System.Threading.Timer(Tick, null, period, period); + this._gate = new AsyncLock(); + + lock (s_timers) + { + s_timers.Add(_timer); + } + } + + private void Tick(object state) + { + _gate.Wait(() => + { + _action(); + }); + } + + public void Dispose() + { + var timer = default(System.Threading.Timer); + + lock (s_timers) + { + timer = _timer; + _timer = null; + + if (timer != null) + s_timers.Remove(timer); + } + + if (timer != null) + { + timer.Dispose(); + _action = Stubs.Nop; + } + } + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs.meta new file mode 100644 index 00000000..b81b15e5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Schedulers/ThreadPoolScheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f8189a60f4619be489df10eca6a78fbb +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects.meta new file mode 100644 index 00000000..8341e0d3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 660d85cac8b3db241b8e6e333d493d38 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs new file mode 100644 index 00000000..3a005ef1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections.Generic; +using UniRx.InternalUtil; + +#if (NET_4_6 || NET_STANDARD_2_0) +using System.Runtime.CompilerServices; +using System.Threading; +#endif + +namespace UniRx +{ + public sealed class AsyncSubject : ISubject, IOptimizedObservable, IDisposable +#if (NET_4_6 || NET_STANDARD_2_0) + , INotifyCompletion +#endif + { + object observerLock = new object(); + + T lastValue; + bool hasValue; + bool isStopped; + bool isDisposed; + Exception lastError; + IObserver outObserver = EmptyObserver.Instance; + + public T Value + { + get + { + ThrowIfDisposed(); + if (!isStopped) throw new InvalidOperationException("AsyncSubject is not completed yet"); + if (lastError != null) lastError.Throw(); + return lastValue; + } + } + + public bool HasObservers + { + get + { + return !(outObserver is EmptyObserver) && !isStopped && !isDisposed; + } + } + + public bool IsCompleted { get { return isStopped; } } + + public void OnCompleted() + { + IObserver old; + T v; + bool hv; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + v = lastValue; + hv = hasValue; + } + + if (hv) + { + old.OnNext(v); + old.OnCompleted(); + } + else + { + old.OnCompleted(); + } + } + + public void OnError(Exception error) + { + if (error == null) throw new ArgumentNullException("error"); + + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + lastError = error; + } + + old.OnError(error); + } + + public void OnNext(T value) + { + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + this.hasValue = true; + this.lastValue = value; + } + } + + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) throw new ArgumentNullException("observer"); + + var ex = default(Exception); + var v = default(T); + var hv = false; + + lock (observerLock) + { + ThrowIfDisposed(); + if (!isStopped) + { + var listObserver = outObserver as ListObserver; + if (listObserver != null) + { + outObserver = listObserver.Add(observer); + } + else + { + var current = outObserver; + if (current is EmptyObserver) + { + outObserver = observer; + } + else + { + outObserver = new ListObserver(new ImmutableList>(new[] { current, observer })); + } + } + + return new Subscription(this, observer); + } + + ex = lastError; + v = lastValue; + hv = hasValue; + } + + if (ex != null) + { + observer.OnError(ex); + } + else if (hv) + { + observer.OnNext(v); + observer.OnCompleted(); + } + else + { + observer.OnCompleted(); + } + + return Disposable.Empty; + } + + public void Dispose() + { + lock (observerLock) + { + isDisposed = true; + outObserver = DisposedObserver.Instance; + lastError = null; + lastValue = default(T); + } + } + + void ThrowIfDisposed() + { + if (isDisposed) throw new ObjectDisposedException(""); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + class Subscription : IDisposable + { + readonly object gate = new object(); + AsyncSubject parent; + IObserver unsubscribeTarget; + + public Subscription(AsyncSubject parent, IObserver unsubscribeTarget) + { + this.parent = parent; + this.unsubscribeTarget = unsubscribeTarget; + } + + public void Dispose() + { + lock (gate) + { + if (parent != null) + { + lock (parent.observerLock) + { + var listObserver = parent.outObserver as ListObserver; + if (listObserver != null) + { + parent.outObserver = listObserver.Remove(unsubscribeTarget); + } + else + { + parent.outObserver = EmptyObserver.Instance; + } + + unsubscribeTarget = null; + parent = null; + } + } + } + } + } + + +#if (NET_4_6 || NET_STANDARD_2_0) + + /// + /// Gets an awaitable object for the current AsyncSubject. + /// + /// Object that can be awaited. + public AsyncSubject GetAwaiter() + { + return this; + } + + /// + /// Specifies a callback action that will be invoked when the subject completes. + /// + /// Callback action that will be invoked when the subject completes. + /// is null. + public void OnCompleted(Action continuation) + { + if (continuation == null) + throw new ArgumentNullException("continuation"); + + OnCompleted(continuation, true); + } + + void OnCompleted(Action continuation, bool originalContext) + { + // + // [OK] Use of unsafe Subscribe: this type's Subscribe implementation is safe. + // + this.Subscribe/*Unsafe*/(new AwaitObserver(continuation, originalContext)); + } + + class AwaitObserver : IObserver + { + private readonly SynchronizationContext _context; + private readonly Action _callback; + + public AwaitObserver(Action callback, bool originalContext) + { + if (originalContext) + _context = SynchronizationContext.Current; + + _callback = callback; + } + + public void OnCompleted() + { + InvokeOnOriginalContext(); + } + + public void OnError(Exception error) + { + InvokeOnOriginalContext(); + } + + public void OnNext(T value) + { + } + + private void InvokeOnOriginalContext() + { + if (_context != null) + { + // + // No need for OperationStarted and OperationCompleted calls here; + // this code is invoked through await support and will have a way + // to observe its start/complete behavior, either through returned + // Task objects or the async method builder's interaction with the + // SynchronizationContext object. + // + _context.Post(c => ((Action)c)(), _callback); + } + else + { + _callback(); + } + } + } + + /// + /// Gets the last element of the subject, potentially blocking until the subject completes successfully or exceptionally. + /// + /// The last element of the subject. Throws an InvalidOperationException if no element was received. + /// The source sequence is empty. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Await pattern for C# and VB compilers.")] + public T GetResult() + { + if (!isStopped) + { + var e = new ManualResetEvent(false); + OnCompleted(() => e.Set(), false); + e.WaitOne(); + } + + if (lastError != null) + { + lastError.Throw(); + } + + if (!hasValue) + throw new InvalidOperationException("NO_ELEMENTS"); + + return lastValue; + } +#endif + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs.meta new file mode 100644 index 00000000..4ef72d51 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/AsyncSubject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 137cd44250b484d4ba2390d510f8423f +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs new file mode 100644 index 00000000..906573bb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs @@ -0,0 +1,204 @@ +using System; +using UniRx.InternalUtil; + +namespace UniRx +{ + public sealed class BehaviorSubject : ISubject, IDisposable, IOptimizedObservable + { + object observerLock = new object(); + + bool isStopped; + bool isDisposed; + T lastValue; + Exception lastError; + IObserver outObserver = EmptyObserver.Instance; + + public BehaviorSubject(T defaultValue) + { + lastValue = defaultValue; + } + + public T Value + { + get + { + ThrowIfDisposed(); + if (lastError != null) lastError.Throw(); + return lastValue; + } + } + + public bool HasObservers + { + get + { + return !(outObserver is EmptyObserver) && !isStopped && !isDisposed; + } + } + + public void OnCompleted() + { + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + } + + old.OnCompleted(); + } + + public void OnError(Exception error) + { + if (error == null) throw new ArgumentNullException("error"); + + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + lastError = error; + } + + old.OnError(error); + } + + public void OnNext(T value) + { + IObserver current; + lock (observerLock) + { + if (isStopped) return; + + lastValue = value; + current = outObserver; + } + + current.OnNext(value); + } + + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) throw new ArgumentNullException("observer"); + + var ex = default(Exception); + var v = default(T); + var subscription = default(Subscription); + + lock (observerLock) + { + ThrowIfDisposed(); + if (!isStopped) + { + var listObserver = outObserver as ListObserver; + if (listObserver != null) + { + outObserver = listObserver.Add(observer); + } + else + { + var current = outObserver; + if (current is EmptyObserver) + { + outObserver = observer; + } + else + { + outObserver = new ListObserver(new ImmutableList>(new[] { current, observer })); + } + } + + v = lastValue; + subscription = new Subscription(this, observer); + } + else + { + ex = lastError; + } + } + + if (subscription != null) + { + observer.OnNext(v); + return subscription; + } + else if (ex != null) + { + observer.OnError(ex); + } + else + { + observer.OnCompleted(); + } + + return Disposable.Empty; + } + + public void Dispose() + { + lock (observerLock) + { + isDisposed = true; + outObserver = DisposedObserver.Instance; + lastError = null; + lastValue = default(T); + } + } + + void ThrowIfDisposed() + { + if (isDisposed) throw new ObjectDisposedException(""); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + class Subscription : IDisposable + { + readonly object gate = new object(); + BehaviorSubject parent; + IObserver unsubscribeTarget; + + public Subscription(BehaviorSubject parent, IObserver unsubscribeTarget) + { + this.parent = parent; + this.unsubscribeTarget = unsubscribeTarget; + } + + public void Dispose() + { + lock (gate) + { + if (parent != null) + { + lock (parent.observerLock) + { + var listObserver = parent.outObserver as ListObserver; + if (listObserver != null) + { + parent.outObserver = listObserver.Remove(unsubscribeTarget); + } + else + { + parent.outObserver = EmptyObserver.Instance; + } + + unsubscribeTarget = null; + parent = null; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs.meta new file mode 100644 index 00000000..03ce50ad --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/BehaviorSubject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2fa461d2fc0c4ec4999e0b9aff16dd47 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs new file mode 100644 index 00000000..70060af6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs @@ -0,0 +1,71 @@ +using System; + +namespace UniRx +{ + public interface IConnectableObservable : IObservable + { + IDisposable Connect(); + } + + public static partial class Observable + { + class ConnectableObservable : IConnectableObservable + { + readonly IObservable source; + readonly ISubject subject; + readonly object gate = new object(); + Connection connection; + + public ConnectableObservable(IObservable source, ISubject subject) + { + this.source = source.AsObservable(); + this.subject = subject; + } + + public IDisposable Connect() + { + lock (gate) + { + // don't subscribe twice + if (connection == null) + { + var subscription = source.Subscribe(subject); + connection = new Connection(this, subscription); + } + + return connection; + } + } + + public IDisposable Subscribe(IObserver observer) + { + return subject.Subscribe(observer); + } + + class Connection : IDisposable + { + readonly ConnectableObservable parent; + IDisposable subscription; + + public Connection(ConnectableObservable parent, IDisposable subscription) + { + this.parent = parent; + this.subscription = subscription; + } + + public void Dispose() + { + lock (parent.gate) + { + if (subscription != null) + { + subscription.Dispose(); + subscription = null; + parent.connection = null; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs.meta new file mode 100644 index 00000000..27713fe4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ConnectableObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8de419b467eded246bc4fc5e70859f73 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs new file mode 100644 index 00000000..b6caca70 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx +{ + public interface ISubject : IObserver, IObservable + { + } + + public interface ISubject : ISubject, IObserver, IObservable + { + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs.meta new file mode 100644 index 00000000..d58f5047 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ISubject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e9dbcd28e4f3965408744e0ee03b7bc8 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs new file mode 100644 index 00000000..0f495abe --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using UniRx.InternalUtil; + +namespace UniRx +{ + public sealed class ReplaySubject : ISubject, IOptimizedObservable, IDisposable + { + object observerLock = new object(); + + bool isStopped; + bool isDisposed; + Exception lastError; + IObserver outObserver = EmptyObserver.Instance; + + readonly int bufferSize; + readonly TimeSpan window; + readonly DateTimeOffset startTime; + readonly IScheduler scheduler; + Queue> queue = new Queue>(); + + + public ReplaySubject() + : this(int.MaxValue, TimeSpan.MaxValue, Scheduler.DefaultSchedulers.Iteration) + { + } + + public ReplaySubject(IScheduler scheduler) + : this(int.MaxValue, TimeSpan.MaxValue, scheduler) + { + } + + public ReplaySubject(int bufferSize) + : this(bufferSize, TimeSpan.MaxValue, Scheduler.DefaultSchedulers.Iteration) + { + } + + public ReplaySubject(int bufferSize, IScheduler scheduler) + : this(bufferSize, TimeSpan.MaxValue, scheduler) + { + } + + public ReplaySubject(TimeSpan window) + : this(int.MaxValue, window, Scheduler.DefaultSchedulers.Iteration) + { + } + + public ReplaySubject(TimeSpan window, IScheduler scheduler) + : this(int.MaxValue, window, scheduler) + { + } + + // full constructor + public ReplaySubject(int bufferSize, TimeSpan window, IScheduler scheduler) + { + if (bufferSize < 0) throw new ArgumentOutOfRangeException("bufferSize"); + if (window < TimeSpan.Zero) throw new ArgumentOutOfRangeException("window"); + if (scheduler == null) throw new ArgumentNullException("scheduler"); + + this.bufferSize = bufferSize; + this.window = window; + this.scheduler = scheduler; + startTime = scheduler.Now; + } + + void Trim() + { + var elapsedTime = Scheduler.Normalize(scheduler.Now - startTime); + + while (queue.Count > bufferSize) + { + queue.Dequeue(); + } + while (queue.Count > 0 && elapsedTime.Subtract(queue.Peek().Interval).CompareTo(window) > 0) + { + queue.Dequeue(); + } + } + + public void OnCompleted() + { + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + Trim(); + } + + old.OnCompleted(); + } + + public void OnError(Exception error) + { + if (error == null) throw new ArgumentNullException("error"); + + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + lastError = error; + Trim(); + } + + old.OnError(error); + } + + public void OnNext(T value) + { + IObserver current; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + // enQ + queue.Enqueue(new TimeInterval(value, scheduler.Now - startTime)); + Trim(); + + current = outObserver; + } + + current.OnNext(value); + } + + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) throw new ArgumentNullException("observer"); + + var ex = default(Exception); + var subscription = default(Subscription); + + lock (observerLock) + { + ThrowIfDisposed(); + if (!isStopped) + { + var listObserver = outObserver as ListObserver; + if (listObserver != null) + { + outObserver = listObserver.Add(observer); + } + else + { + var current = outObserver; + if (current is EmptyObserver) + { + outObserver = observer; + } + else + { + outObserver = new ListObserver(new ImmutableList>(new[] { current, observer })); + } + } + + subscription = new Subscription(this, observer); + } + + ex = lastError; + Trim(); + foreach (var item in queue) + { + observer.OnNext(item.Value); + } + } + + if (subscription != null) + { + return subscription; + } + else if (ex != null) + { + observer.OnError(ex); + } + else + { + observer.OnCompleted(); + } + + return Disposable.Empty; + } + + public void Dispose() + { + lock (observerLock) + { + isDisposed = true; + outObserver = DisposedObserver.Instance; + lastError = null; + queue = null; + } + } + + void ThrowIfDisposed() + { + if (isDisposed) throw new ObjectDisposedException(""); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + class Subscription : IDisposable + { + readonly object gate = new object(); + ReplaySubject parent; + IObserver unsubscribeTarget; + + public Subscription(ReplaySubject parent, IObserver unsubscribeTarget) + { + this.parent = parent; + this.unsubscribeTarget = unsubscribeTarget; + } + + public void Dispose() + { + lock (gate) + { + if (parent != null) + { + lock (parent.observerLock) + { + var listObserver = parent.outObserver as ListObserver; + if (listObserver != null) + { + parent.outObserver = listObserver.Remove(unsubscribeTarget); + } + else + { + parent.outObserver = EmptyObserver.Instance; + } + + unsubscribeTarget = null; + parent = null; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs.meta new file mode 100644 index 00000000..88be9ea9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/ReplaySubject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d9b0c2f29645e1f468259893bf9afb68 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs new file mode 100644 index 00000000..c6e61fda --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UniRx.InternalUtil; + +namespace UniRx +{ + public sealed class Subject : ISubject, IDisposable, IOptimizedObservable + { + object observerLock = new object(); + + bool isStopped; + bool isDisposed; + Exception lastError; + IObserver outObserver = EmptyObserver.Instance; + + public bool HasObservers + { + get + { + return !(outObserver is EmptyObserver) && !isStopped && !isDisposed; + } + } + + public void OnCompleted() + { + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + } + + old.OnCompleted(); + } + + public void OnError(Exception error) + { + if (error == null) throw new ArgumentNullException("error"); + + IObserver old; + lock (observerLock) + { + ThrowIfDisposed(); + if (isStopped) return; + + old = outObserver; + outObserver = EmptyObserver.Instance; + isStopped = true; + lastError = error; + } + + old.OnError(error); + } + + public void OnNext(T value) + { + outObserver.OnNext(value); + } + + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) throw new ArgumentNullException("observer"); + + var ex = default(Exception); + + lock (observerLock) + { + ThrowIfDisposed(); + if (!isStopped) + { + var listObserver = outObserver as ListObserver; + if (listObserver != null) + { + outObserver = listObserver.Add(observer); + } + else + { + var current = outObserver; + if (current is EmptyObserver) + { + outObserver = observer; + } + else + { + outObserver = new ListObserver(new ImmutableList>(new[] { current, observer })); + } + } + + return new Subscription(this, observer); + } + + ex = lastError; + } + + if (ex != null) + { + observer.OnError(ex); + } + else + { + observer.OnCompleted(); + } + + return Disposable.Empty; + } + + public void Dispose() + { + lock (observerLock) + { + isDisposed = true; + outObserver = DisposedObserver.Instance; + } + } + + void ThrowIfDisposed() + { + if (isDisposed) throw new ObjectDisposedException(""); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + + class Subscription : IDisposable + { + readonly object gate = new object(); + Subject parent; + IObserver unsubscribeTarget; + + public Subscription(Subject parent, IObserver unsubscribeTarget) + { + this.parent = parent; + this.unsubscribeTarget = unsubscribeTarget; + } + + public void Dispose() + { + lock (gate) + { + if (parent != null) + { + lock (parent.observerLock) + { + var listObserver = parent.outObserver as ListObserver; + if (listObserver != null) + { + parent.outObserver = listObserver.Remove(unsubscribeTarget); + } + else + { + parent.outObserver = EmptyObserver.Instance; + } + + unsubscribeTarget = null; + parent = null; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs.meta new file mode 100644 index 00000000..569d8ca3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/Subject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d5fdc90caca9cbe4b9cd9c3fae81e7f6 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs new file mode 100644 index 00000000..b85540cb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs @@ -0,0 +1,61 @@ +using System; + +namespace UniRx +{ + public static class SubjectExtensions + { + public static ISubject Synchronize(this ISubject subject) + { + return new AnonymousSubject((subject as IObserver).Synchronize(), subject); + } + + public static ISubject Synchronize(this ISubject subject, object gate) + { + return new AnonymousSubject((subject as IObserver).Synchronize(gate), subject); + } + + class AnonymousSubject : ISubject + { + readonly IObserver observer; + readonly IObservable observable; + + public AnonymousSubject(IObserver observer, IObservable observable) + { + this.observer = observer; + this.observable = observable; + } + + public void OnCompleted() + { + observer.OnCompleted(); + } + + public void OnError(Exception error) + { + if (error == null) throw new ArgumentNullException("error"); + + observer.OnError(error); + } + + public void OnNext(T value) + { + observer.OnNext(value); + } + + public IDisposable Subscribe(IObserver observer) + { + if (observer == null) throw new ArgumentNullException("observer"); + + return observable.Subscribe(observer); + } + } + + class AnonymousSubject : AnonymousSubject, ISubject + { + public AnonymousSubject(IObserver observer, IObservable observable) + : base(observer, observable) + { + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs.meta new file mode 100644 index 00000000..6a6ebf5b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Subjects/SubjectExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 359bf19588606a14fb0edc6efa97deaf +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System.meta new file mode 100644 index 00000000..82341908 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e38b8fd0fa968d0438280dbb22012b81 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs new file mode 100644 index 00000000..f590a3cb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs @@ -0,0 +1,23 @@ +// defined from .NET Framework 4.0 and NETFX_CORE + +using System; + +#if !(NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + +namespace UniRx +{ + public interface IObservable + { + IDisposable Subscribe(IObserver observer); + } +} + +#endif + +namespace UniRx +{ + public interface IGroupedObservable : IObservable + { + TKey Key { get; } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs.meta new file mode 100644 index 00000000..24b356c8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9703f7aad3c6b334badd37c1b41d0d8f +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs new file mode 100644 index 00000000..b8c8d0cd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs @@ -0,0 +1,17 @@ +// defined from .NET Framework 4.0 and NETFX_CORE + +#if !(NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + +using System; + +namespace UniRx +{ + public interface IObserver + { + void OnCompleted(); + void OnError(Exception error); + void OnNext(T value); + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs.meta new file mode 100644 index 00000000..7d8f9279 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IObserver.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1fc7a9cec9d3b644da7dbcf18ea16270 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs new file mode 100644 index 00000000..32408139 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs @@ -0,0 +1,27 @@ +using System; + +namespace UniRx +{ + public interface IOptimizedObservable : IObservable + { + bool IsRequiredSubscribeOnCurrentThread(); + } + + public static class OptimizedObservableExtensions + { + public static bool IsRequiredSubscribeOnCurrentThread(this IObservable source) + { + var obs = source as IOptimizedObservable; + if (obs == null) return true; + + return obs.IsRequiredSubscribeOnCurrentThread(); + } + + public static bool IsRequiredSubscribeOnCurrentThread(this IObservable source, IScheduler scheduler) + { + if (scheduler == Scheduler.CurrentThread) return true; + + return IsRequiredSubscribeOnCurrentThread(source); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs.meta new file mode 100644 index 00000000..67cd19b1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IOptimizedObservable.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5a2d3a7c73260e14a875d62586ae28f9 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs new file mode 100644 index 00000000..c90bea97 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs @@ -0,0 +1,30 @@ +// defined from .NET Framework 4.5 and NETFX_CORE + +#if !(NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + +using System; + +namespace UniRx +{ + public interface IProgress + { + void Report(T value); + } + + public class Progress : IProgress + { + readonly Action report; + + public Progress(Action report) + { + this.report = report; + } + + public void Report(T value) + { + report(value); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs.meta new file mode 100644 index 00000000..1fe98e2d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/IProgress.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a38a024b6babf8d48b7e32f2f8fb8686 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs new file mode 100644 index 00000000..22facac0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs @@ -0,0 +1,1195 @@ +// defined from .NET Framework 4.0 and NETFX_CORE +// This code is basaed from mono/mcs, but some performance modified +// 1. class to struct +// 2. implements IEquatable + +// note, we need to create ValueTuple or UniRxTuple... +#if !(NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UniRx +{ + public interface IStructuralEquatable + { + bool Equals(object other, IEqualityComparer comparer); + + int GetHashCode(IEqualityComparer comparer); + } + + public interface IStructuralComparable + { + int CompareTo(object other, IComparer comparer); + } + + interface ITuple + { + string ToString(); + } + + public static class Tuple + { + public static Tuple> Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7, + T8 item8) + { + return new Tuple>(item1, item2, item3, item4, item5, item6, item7, new Tuple(item8)); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6, + T7 item7) + { + return new Tuple(item1, item2, item3, item4, item5, item6, item7); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5, + T6 item6) + { + return new Tuple(item1, item2, item3, item4, item5, item6); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4, + T5 item5) + { + return new Tuple(item1, item2, item3, item4, item5); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3, + T4 item4) + { + return new Tuple(item1, item2, item3, item4); + } + + public static Tuple Create + ( + T1 item1, + T2 item2, + T3 item3) + { + return new Tuple(item1, item2, item3); + } + + public static Tuple Create + ( + T1 item1, + T2 item2) + { + return new Tuple(item1, item2); + } + + public static Tuple Create + ( + T1 item1) + { + return new Tuple(item1); + } + } + + public partial class Tuple + { + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + this.rest = rest; + + if (!(rest is ITuple)) + throw new ArgumentException("rest", "The last element of an eight element tuple must be a Tuple."); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + + public Tuple(T1 item1) + { + this.item1 = item1; + } + + public T1 Item1 + { + get { return item1; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + return comparer.Compare(item1, t.item1); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + + var t = (Tuple)other; + return comparer.Equals(item1, t.item1); + } + + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(item1); + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + return comparer.GetHashCode(item1); + } + + string ITuple.ToString() + { + return String.Format("{0}", item1); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + return EqualityComparer.Default.Equals(item1, other.item1); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + + public Tuple(T1 item1, T2 item2) + { + this.item1 = item1; + this.item2 = item2; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + return comparer.Compare(item2, t.item2); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + + var t = (Tuple)other; + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + + int h0; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}", item1, item2); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.item1) && + comparer2.Equals(item2, other.item2); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + + public Tuple(T1 item1, T2 item2, T3 item3) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + return comparer.Compare(item3, t.item3); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + + var t = (Tuple)other; + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + + int h0; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h0 = (h0 << 5) + h0 ^ comparer3.GetHashCode(item3); + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item3); + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}", item1, item2, item3); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.item1) && + comparer2.Equals(item2, other.item2) && + comparer3.Equals(item3, other.item3); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + public T4 Item4 + { + get { return item4; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + return comparer.Compare(item4, t.item4); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + var t = (Tuple)other; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + + int h0, h1; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h1 = comparer3.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer4.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0, h1; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h1 = comparer.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}, {3}", item1, item2, item3, item4); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.item1) && + comparer2.Equals(item2, other.item2) && + comparer3.Equals(item3, other.item3) && + comparer4.Equals(item4, other.item4); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + public T4 Item4 + { + get { return item4; } + } + + public T5 Item5 + { + get { return item5; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + return comparer.Compare(item5, t.item5); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + var t = (Tuple)other; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + + int h0, h1; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h1 = comparer3.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer4.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h0 = (h0 << 5) + h0 ^ comparer5.GetHashCode(item5); + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0, h1; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h1 = comparer.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item5); + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}, {3}, {4}", item1, item2, item3, item4, item5); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.Item1) && + comparer2.Equals(item2, other.Item2) && + comparer3.Equals(item3, other.Item3) && + comparer4.Equals(item4, other.Item4) && + comparer5.Equals(item5, other.Item5); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + public T4 Item4 + { + get { return item4; } + } + + public T5 Item5 + { + get { return item5; } + } + + public T6 Item6 + { + get { return item6; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + return comparer.Compare(item6, t.item6); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + var t = (Tuple)other; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + + int h0, h1; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h1 = comparer3.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer4.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer5.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer6.GetHashCode(item6); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0, h1; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h1 = comparer.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item6); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}, {3}, {4}, {5}", item1, item2, item3, item4, item5, item6); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.Item1) && + comparer2.Equals(item2, other.Item2) && + comparer3.Equals(item3, other.Item3) && + comparer4.Equals(item4, other.Item4) && + comparer5.Equals(item5, other.Item5) && + comparer6.Equals(item6, other.Item6); + } + } + + [Serializable] + public struct Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + + public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + this.item5 = item5; + this.item6 = item6; + this.item7 = item7; + } + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + public T4 Item4 + { + get { return item4; } + } + + public T5 Item5 + { + get { return item5; } + } + + public T6 Item6 + { + get { return item6; } + } + + public T7 Item7 + { + get { return item7; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + res = comparer.Compare(item6, t.item6); + if (res != 0) return res; + return comparer.Compare(item7, t.item7); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + var t = (Tuple)other; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6) && + comparer.Equals(item7, t.item7); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + var comparer7 = EqualityComparer.Default; + + int h0, h1; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h1 = comparer3.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer4.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer5.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer6.GetHashCode(item6); + h1 = (h1 << 5) + h1 ^ comparer7.GetHashCode(item7); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0, h1; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h1 = comparer.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item6); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item7); + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}", item1, item2, item3, item4, item5, item6, item7); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + var comparer7 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.Item1) && + comparer2.Equals(item2, other.Item2) && + comparer3.Equals(item3, other.Item3) && + comparer4.Equals(item4, other.Item4) && + comparer5.Equals(item5, other.Item5) && + comparer6.Equals(item6, other.Item6) && + comparer7.Equals(item7, other.Item7); + } + } + + [Serializable] + public partial class Tuple : IStructuralEquatable, IStructuralComparable, IComparable, ITuple, IEquatable> + { + T1 item1; + T2 item2; + T3 item3; + T4 item4; + T5 item5; + T6 item6; + T7 item7; + TRest rest; + + public T1 Item1 + { + get { return item1; } + } + + public T2 Item2 + { + get { return item2; } + } + + public T3 Item3 + { + get { return item3; } + } + + public T4 Item4 + { + get { return item4; } + } + + public T5 Item5 + { + get { return item5; } + } + + public T6 Item6 + { + get { return item6; } + } + + public T7 Item7 + { + get { return item7; } + } + + public TRest Rest + { + get { return rest; } + } + + int IComparable.CompareTo(object obj) + { + return ((IStructuralComparable)this).CompareTo(obj, Comparer.Default); + } + + int IStructuralComparable.CompareTo(object other, IComparer comparer) + { + if (other == null) return 1; + if (!(other is Tuple)) + { + throw new ArgumentException("other"); + } + var t = (Tuple)other; + + int res = comparer.Compare(item1, t.item1); + if (res != 0) return res; + res = comparer.Compare(item2, t.item2); + if (res != 0) return res; + res = comparer.Compare(item3, t.item3); + if (res != 0) return res; + res = comparer.Compare(item4, t.item4); + if (res != 0) return res; + res = comparer.Compare(item5, t.item5); + if (res != 0) return res; + res = comparer.Compare(item6, t.item6); + if (res != 0) return res; + res = comparer.Compare(item7, t.item7); + if (res != 0) return res; + return comparer.Compare(rest, t.rest); + } + + public override bool Equals(object obj) + { + return ((IStructuralEquatable)this).Equals(obj, EqualityComparer.Default); + } + + bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) + { + if (!(other is Tuple)) + return false; + var t = (Tuple)other; + + return comparer.Equals(item1, t.item1) && + comparer.Equals(item2, t.item2) && + comparer.Equals(item3, t.item3) && + comparer.Equals(item4, t.item4) && + comparer.Equals(item5, t.item5) && + comparer.Equals(item6, t.item6) && + comparer.Equals(item7, t.item7) && + comparer.Equals(rest, t.rest); + } + + public override int GetHashCode() + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + var comparer7 = EqualityComparer.Default; + var comparer8 = EqualityComparer.Default; + + int h0, h1, h2; + h0 = comparer1.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer2.GetHashCode(item2); + h1 = comparer3.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer4.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer5.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer6.GetHashCode(item6); + h2 = comparer7.GetHashCode(item7); + h2 = (h2 << 5) + h2 ^ comparer8.GetHashCode(rest); + h1 = (h1 << 5) + h1 ^ h2; + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) + { + int h0, h1, h2; + h0 = comparer.GetHashCode(item1); + h0 = (h0 << 5) + h0 ^ comparer.GetHashCode(item2); + h1 = comparer.GetHashCode(item3); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item4); + h0 = (h0 << 5) + h0 ^ h1; + h1 = comparer.GetHashCode(item5); + h1 = (h1 << 5) + h1 ^ comparer.GetHashCode(item6); + h2 = comparer.GetHashCode(item7); + h2 = (h2 << 5) + h2 ^ comparer.GetHashCode(rest); + h1 = (h1 << 5) + h1 ^ h2; + h0 = (h0 << 5) + h0 ^ h1; + return h0; + } + + string ITuple.ToString() + { + return String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}", item1, item2, item3, item4, item5, item6, item7, ((ITuple)rest).ToString()); + } + + public override string ToString() + { + return "(" + ((ITuple)this).ToString() + ")"; + } + + public bool Equals(Tuple other) + { + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + var comparer3 = EqualityComparer.Default; + var comparer4 = EqualityComparer.Default; + var comparer5 = EqualityComparer.Default; + var comparer6 = EqualityComparer.Default; + var comparer7 = EqualityComparer.Default; + var comparer8 = EqualityComparer.Default; + + return comparer1.Equals(item1, other.Item1) && + comparer2.Equals(item2, other.Item2) && + comparer3.Equals(item3, other.Item3) && + comparer4.Equals(item4, other.Item4) && + comparer5.Equals(item5, other.Item5) && + comparer6.Equals(item6, other.Item6) && + comparer7.Equals(item7, other.Item7) && + comparer8.Equals(rest, other.rest); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs.meta new file mode 100644 index 00000000..1eb6471f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/Tuple.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: be811500a5640704b92de622c9202d48 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs b/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs new file mode 100644 index 00000000..87b31c2d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs @@ -0,0 +1,41 @@ +using System; + +namespace UniRx +{ + [Serializable] + public struct Unit : IEquatable + { + static readonly Unit @default = new Unit(); + + public static Unit Default { get { return @default; } } + + public static bool operator ==(Unit first, Unit second) + { + return true; + } + + public static bool operator !=(Unit first, Unit second) + { + return false; + } + + public bool Equals(Unit other) + { + return true; + } + public override bool Equals(object obj) + { + return obj is Unit; + } + + public override int GetHashCode() + { + return 0; + } + + public override string ToString() + { + return "()"; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs.meta new file mode 100644 index 00000000..2a44d1ec --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/System/Unit.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 14f6907c0ae17e64c8fc34f08c3038a4 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Tasks.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks.meta new file mode 100644 index 00000000..f9d1da14 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f4389552ae1b4f54fb6d931c0a6efd08 +folderAsset: yes +timeCreated: 1475139656 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs new file mode 100644 index 00000000..2a5f713f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs @@ -0,0 +1,367 @@ +// this code is borrowed from RxOfficial(rx.codeplex.com) and modified + +#if (NET_4_6 || NET_STANDARD_2_0) + +using System; +using System.Threading.Tasks; +using System.Threading; + +namespace UniRx +{ + /// + /// Provides a set of static methods for converting tasks to observable sequences. + /// + public static class TaskObservableExtensions + { + /// + /// Returns an observable sequence that signals when the task completes. + /// + /// Task to convert to an observable sequence. + /// An observable sequence that produces a unit value when the task completes, or propagates the exception produced by the task. + /// is null. + /// If the specified task object supports cancellation, consider using instead. + public static IObservable ToObservable(this Task task) + { + if (task == null) + throw new ArgumentNullException("task"); + + return ToObservableImpl(task, null); + } + + /// + /// Returns an observable sequence that signals when the task completes. + /// + /// Task to convert to an observable sequence. + /// Scheduler on which to notify observers about completion, cancellation or failure. + /// An observable sequence that produces a unit value when the task completes, or propagates the exception produced by the task. + /// is null or is null. + /// If the specified task object supports cancellation, consider using instead. + public static IObservable ToObservable(this Task task, IScheduler scheduler) + { + if (task == null) + throw new ArgumentNullException("task"); + if (scheduler == null) + throw new ArgumentNullException("scheduler"); + + return ToObservableImpl(task, scheduler); + } + + private static IObservable ToObservableImpl(Task task, IScheduler scheduler) + { + var res = default(IObservable); + + if (task.IsCompleted) + { + scheduler = scheduler ?? Scheduler.Immediate; + + switch (task.Status) + { + case TaskStatus.RanToCompletion: + res = Observable.Return(Unit.Default, scheduler); + break; + case TaskStatus.Faulted: + res = Observable.Throw(task.Exception.InnerException, scheduler); + break; + case TaskStatus.Canceled: + res = Observable.Throw(new TaskCanceledException(task), scheduler); + break; + } + } + else + { + // + // Separate method to avoid closure in synchronous completion case. + // + res = ToObservableSlow(task, scheduler); + } + + return res; + } + + private static IObservable ToObservableSlow(Task task, IScheduler scheduler) + { + var subject = new AsyncSubject(); + + var options = GetTaskContinuationOptions(scheduler); + + task.ContinueWith(t => ToObservableDone(task, subject), options); + + return ToObservableResult(subject, scheduler); + } + + private static void ToObservableDone(Task task, IObserver subject) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: + subject.OnNext(Unit.Default); + subject.OnCompleted(); + break; + case TaskStatus.Faulted: + subject.OnError(task.Exception.InnerException); + break; + case TaskStatus.Canceled: + subject.OnError(new TaskCanceledException(task)); + break; + } + } + + /// + /// Returns an observable sequence that propagates the result of the task. + /// + /// The type of the result produced by the task. + /// Task to convert to an observable sequence. + /// An observable sequence that produces the task's result, or propagates the exception produced by the task. + /// is null. + /// If the specified task object supports cancellation, consider using instead. + public static IObservable ToObservable(this Task task) + { + if (task == null) + throw new ArgumentNullException("task"); + + return ToObservableImpl(task, null); + } + + /// + /// Returns an observable sequence that propagates the result of the task. + /// + /// The type of the result produced by the task. + /// Task to convert to an observable sequence. + /// Scheduler on which to notify observers about completion, cancellation or failure. + /// An observable sequence that produces the task's result, or propagates the exception produced by the task. + /// is null or is null. + /// If the specified task object supports cancellation, consider using instead. + public static IObservable ToObservable(this Task task, IScheduler scheduler) + { + if (task == null) + throw new ArgumentNullException("task"); + if (scheduler == null) + throw new ArgumentNullException("scheduler"); + + return ToObservableImpl(task, scheduler); + } + + private static IObservable ToObservableImpl(Task task, IScheduler scheduler) + { + var res = default(IObservable); + + if (task.IsCompleted) + { + scheduler = scheduler ?? Scheduler.Immediate; + + switch (task.Status) + { + case TaskStatus.RanToCompletion: + res = Observable.Return(task.Result, scheduler); + break; + case TaskStatus.Faulted: + res = Observable.Throw(task.Exception.InnerException, scheduler); + break; + case TaskStatus.Canceled: + res = Observable.Throw(new TaskCanceledException(task), scheduler); + break; + } + } + else + { + // + // Separate method to avoid closure in synchronous completion case. + // + res = ToObservableSlow(task, scheduler); + } + + return res; + } + + private static IObservable ToObservableSlow(Task task, IScheduler scheduler) + { + var subject = new AsyncSubject(); + + var options = GetTaskContinuationOptions(scheduler); + + task.ContinueWith(t => ToObservableDone(task, subject), options); + + return ToObservableResult(subject, scheduler); + } + + private static void ToObservableDone(Task task, IObserver subject) + { + switch (task.Status) + { + case TaskStatus.RanToCompletion: + subject.OnNext(task.Result); + subject.OnCompleted(); + break; + case TaskStatus.Faulted: + subject.OnError(task.Exception.InnerException); + break; + case TaskStatus.Canceled: + subject.OnError(new TaskCanceledException(task)); + break; + } + } + + private static TaskContinuationOptions GetTaskContinuationOptions(IScheduler scheduler) + { + var options = TaskContinuationOptions.None; + + if (scheduler != null) + { + // + // We explicitly don't special-case the immediate scheduler here. If the user asks for a + // synchronous completion, we'll try our best. However, there's no guarantee due to the + // internal stack probing in the TPL, which may cause asynchronous completion on a thread + // pool thread in order to avoid stack overflows. Therefore we can only attempt to be more + // efficient in the case where the user specified a scheduler, hence we know that the + // continuation will trigger a scheduling operation. In case of the immediate scheduler, + // it really becomes "immediate scheduling" wherever the TPL decided to run the continuation, + // i.e. not necessarily where the task was completed from. + // + options |= TaskContinuationOptions.ExecuteSynchronously; + } + + return options; + } + + private static IObservable ToObservableResult(AsyncSubject subject, IScheduler scheduler) + { + if (scheduler != null) + { + return subject.ObserveOn(scheduler); + } + else + { + return subject.AsObservable(); + } + } + + /// + /// Returns a task that will receive the last value or the exception produced by the observable sequence. + /// + /// The type of the elements in the source sequence. + /// Observable sequence to convert to a task. + /// A task that will receive the last element or the exception produced by the observable sequence. + /// is null. + public static Task ToTask(this IObservable observable) + { + if (observable == null) + throw new ArgumentNullException("observable"); + + return observable.ToTask(new CancellationToken(), null); + } + + /// + /// Returns a task that will receive the last value or the exception produced by the observable sequence. + /// + /// The type of the elements in the source sequence. + /// Observable sequence to convert to a task. + /// The state to use as the underlying task's AsyncState. + /// A task that will receive the last element or the exception produced by the observable sequence. + /// is null. + public static Task ToTask(this IObservable observable, object state) + { + if (observable == null) + throw new ArgumentNullException("observable"); + + return observable.ToTask(new CancellationToken(), state); + } + + /// + /// Returns a task that will receive the last value or the exception produced by the observable sequence. + /// + /// The type of the elements in the source sequence. + /// Observable sequence to convert to a task. + /// Cancellation token that can be used to cancel the task, causing unsubscription from the observable sequence. + /// A task that will receive the last element or the exception produced by the observable sequence. + /// is null. + public static Task ToTask(this IObservable observable, CancellationToken cancellationToken) + { + if (observable == null) + throw new ArgumentNullException("observable"); + + return observable.ToTask(cancellationToken, null); + } + + /// + /// Returns a task that will receive the last value or the exception produced by the observable sequence. + /// + /// The type of the elements in the source sequence. + /// Observable sequence to convert to a task. + /// Cancellation token that can be used to cancel the task, causing unsubscription from the observable sequence. + /// The state to use as the underlying task's AsyncState. + /// A task that will receive the last element or the exception produced by the observable sequence. + /// is null. + public static Task ToTask(this IObservable observable, CancellationToken cancellationToken, object state) + { + if (observable == null) + throw new ArgumentNullException("observable"); + + var hasValue = false; + var lastValue = default(TResult); + + var tcs = new TaskCompletionSource(state); + + var disposable = new SingleAssignmentDisposable(); + + var ctr = default(CancellationTokenRegistration); + + if (cancellationToken.CanBeCanceled) + { + ctr = cancellationToken.Register(() => + { + disposable.Dispose(); + tcs.TrySetCanceled(cancellationToken); + }); + } + + var taskCompletionObserver = Observer.Create( + value => + { + hasValue = true; + lastValue = value; + }, + ex => + { + tcs.TrySetException(ex); + + ctr.Dispose(); // no null-check needed (struct) + disposable.Dispose(); + }, + () => + { + if (hasValue) + tcs.TrySetResult(lastValue); + else + tcs.TrySetException(new InvalidOperationException("Strings_Linq.NO_ELEMENTS")); + + ctr.Dispose(); // no null-check needed (struct) + disposable.Dispose(); + } + ); + + // + // Subtle race condition: if the source completes before we reach the line below, the SingleAssigmentDisposable + // will already have been disposed. Upon assignment, the disposable resource being set will be disposed on the + // spot, which may throw an exception. (Similar to TFS 487142) + // + try + { + // + // [OK] Use of unsafe Subscribe: we're catching the exception here to set the TaskCompletionSource. + // + // Notice we could use a safe subscription to route errors through OnError, but we still need the + // exception handling logic here for the reason explained above. We cannot afford to throw here + // and as a result never set the TaskCompletionSource, so we tunnel everything through here. + // + disposable.Disposable = observable.Subscribe/*Unsafe*/(taskCompletionObserver); + } + catch (Exception ex) + { + tcs.TrySetException(ex); + } + + return tcs.Task; + } + } +} +#endif diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs.meta new file mode 100644 index 00000000..e3bf3108 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Tasks/TaskObservableExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d4f80d45cec56574e990cc840d1ac16b +timeCreated: 1475139656 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs b/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs new file mode 100644 index 00000000..dc507289 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs @@ -0,0 +1,117 @@ +// original code from rx.codeplex.com + +/* ------------------ */ + +// 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.Globalization; + +namespace UniRx +{ + /// + /// Represents a value associated with time interval information. + /// The time interval can represent the time it took to produce the value, the interval relative to a previous value, the value's delivery time relative to a base, etc. + /// + /// The type of the value being annotated with time interval information. + [Serializable] + public struct TimeInterval : IEquatable> + { + private readonly TimeSpan _interval; + private readonly T _value; + + /// + /// Constructs a time interval value. + /// + /// The value to be annotated with a time interval. + /// Time interval associated with the value. + public TimeInterval(T value, TimeSpan interval) + { + _interval = interval; + _value = value; + } + + /// + /// Gets the value. + /// + public T Value + { + get { return _value; } + } + + /// + /// Gets the interval. + /// + public TimeSpan Interval + { + get { return _interval; } + } + + /// + /// Determines whether the current TimeInterval<T> value has the same Value and Interval as a specified TimeInterval<T> value. + /// + /// An object to compare to the current TimeInterval<T> value. + /// true if both TimeInterval<T> values have the same Value and Interval; otherwise, false. + public bool Equals(TimeInterval other) + { + return other.Interval.Equals(Interval) && EqualityComparer.Default.Equals(Value, other.Value); + } + + /// + /// Determines whether the two specified TimeInterval<T> values have the same Value and Interval. + /// + /// The first TimeInterval<T> value to compare. + /// The second TimeInterval<T> value to compare. + /// true if the first TimeInterval<T> value has the same Value and Interval as the second TimeInterval<T> value; otherwise, false. + public static bool operator ==(TimeInterval first, TimeInterval second) + { + return first.Equals(second); + } + + /// + /// Determines whether the two specified TimeInterval<T> values don't have the same Value and Interval. + /// + /// The first TimeInterval<T> value to compare. + /// The second TimeInterval<T> value to compare. + /// true if the first TimeInterval<T> value has a different Value or Interval as the second TimeInterval<T> value; otherwise, false. + public static bool operator !=(TimeInterval first, TimeInterval second) + { + return !first.Equals(second); + } + + /// + /// Determines whether the specified System.Object is equal to the current TimeInterval<T>. + /// + /// The System.Object to compare with the current TimeInterval<T>. + /// true if the specified System.Object is equal to the current TimeInterval<T>; otherwise, false. + public override bool Equals(object obj) + { + if (!(obj is TimeInterval)) + return false; + + var other = (TimeInterval)obj; + return this.Equals(other); + } + + /// + /// Returns the hash code for the current TimeInterval<T> value. + /// + /// A hash code for the current TimeInterval<T> value. + public override int GetHashCode() + { + var valueHashCode = Value == null ? 1963 : Value.GetHashCode(); + + return Interval.GetHashCode() ^ valueHashCode; + } + + /// + /// Returns a string representation of the current TimeInterval<T> value. + /// + /// String representation of the current TimeInterval<T> value. + public override string ToString() + { + return String.Format(CultureInfo.CurrentCulture, "{0}@{1}", Value, Interval); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs.meta new file mode 100644 index 00000000..0a0da67e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/TimeInterval.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dd48622e783cadc47af9a6b456ac8438 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs b/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs new file mode 100644 index 00000000..8eca1ec9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs @@ -0,0 +1,135 @@ +// original code from rx.codeplex.com + +/* ------------------ */ + +// 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.Globalization; + +namespace UniRx +{ + /// + /// Represents value with a timestamp on it. + /// The timestamp typically represents the time the value was received, using an IScheduler's clock to obtain the current time. + /// + /// The type of the value being timestamped. + [Serializable] + public struct Timestamped : IEquatable> + { + private readonly DateTimeOffset _timestamp; + private readonly T _value; + + /// + /// Constructs a timestamped value. + /// + /// The value to be annotated with a timestamp. + /// Timestamp associated with the value. + public Timestamped(T value, DateTimeOffset timestamp) + { + _timestamp = timestamp; + _value = value; + } + + /// + /// Gets the value. + /// + public T Value + { + get { return _value; } + } + + /// + /// Gets the timestamp. + /// + public DateTimeOffset Timestamp + { + get { return _timestamp; } + } + + /// + /// Determines whether the current Timestamped<T> value has the same Value and Timestamp as a specified Timestamped<T> value. + /// + /// An object to compare to the current Timestamped<T> value. + /// true if both Timestamped<T> values have the same Value and Timestamp; otherwise, false. + public bool Equals(Timestamped other) + { + return other.Timestamp.Equals(Timestamp) && EqualityComparer.Default.Equals(Value, other.Value); + } + + /// + /// Determines whether the two specified Timestamped<T> values have the same Value and Timestamp. + /// + /// The first Timestamped<T> value to compare. + /// The second Timestamped<T> value to compare. + /// true if the first Timestamped<T> value has the same Value and Timestamp as the second Timestamped<T> value; otherwise, false. + public static bool operator ==(Timestamped first, Timestamped second) + { + return first.Equals(second); + } + + /// + /// Determines whether the two specified Timestamped<T> values don't have the same Value and Timestamp. + /// + /// The first Timestamped<T> value to compare. + /// The second Timestamped<T> value to compare. + /// true if the first Timestamped<T> value has a different Value or Timestamp as the second Timestamped<T> value; otherwise, false. + public static bool operator !=(Timestamped first, Timestamped second) + { + return !first.Equals(second); + } + + /// + /// Determines whether the specified System.Object is equal to the current Timestamped<T>. + /// + /// The System.Object to compare with the current Timestamped<T>. + /// true if the specified System.Object is equal to the current Timestamped<T>; otherwise, false. + public override bool Equals(object obj) + { + if (!(obj is Timestamped)) + return false; + + var other = (Timestamped)obj; + return this.Equals(other); + } + + /// + /// Returns the hash code for the current Timestamped<T> value. + /// + /// A hash code for the current Timestamped<T> value. + public override int GetHashCode() + { + var valueHashCode = Value == null ? 1979 : Value.GetHashCode(); + + return _timestamp.GetHashCode() ^ valueHashCode; + } + + /// + /// Returns a string representation of the current Timestamped<T> value. + /// + /// String representation of the current Timestamped<T> value. + public override string ToString() + { + return String.Format(CultureInfo.CurrentCulture, "{0}@{1}", Value, Timestamp); + } + } + + /// + /// A helper class with a factory method for creating Timestamped<T> instances. + /// + public static class Timestamped + { + /// + /// Creates an instance of a Timestamped<T>. This is syntactic sugar that uses type inference + /// to avoid specifying a type in a constructor call, which is very useful when using anonymous types. + /// + /// The value to be annotated with a timestamp. + /// Timestamp associated with the value. + /// Creates a new timestamped value. + public static Timestamped Create(T value, DateTimeOffset timestamp) + { + return new Timestamped(value, timestamp); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs.meta new file mode 100644 index 00000000..4ee8734b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/Timestamped.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c1d908b82d0e2b4489d3351a484e5eae +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef b/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef new file mode 100644 index 00000000..faf74ce6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef @@ -0,0 +1,12 @@ +{ + "name": "UniRx", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [] +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef.meta new file mode 100644 index 00000000..329a03e0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UniRx.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 560b04d1a97f54a4e82edc0cbbb69285 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge.meta new file mode 100644 index 00000000..2ae50b23 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c6fa31db6d33195438d3a9c49effc512 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs new file mode 100644 index 00000000..ab876a3b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections; +using System.Threading; +using UnityEngine; + +#if !UniRxLibrary +using ObservableUnity = UniRx.Observable; +#endif + +namespace UniRx +{ + public static partial class AsyncOperationExtensions + { + /// + /// If you needs return value, use AsAsyncOperationObservable instead. + /// + public static IObservable AsObservable(this AsyncOperation asyncOperation, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => AsObservableCore(asyncOperation, observer, progress, cancellation)); + } + + // T: where T : AsyncOperation is ambigious with IObservable.AsObservable + public static IObservable AsAsyncOperationObservable(this T asyncOperation, IProgress progress = null) + where T : AsyncOperation + { + return ObservableUnity.FromCoroutine((observer, cancellation) => AsObservableCore(asyncOperation, observer, progress, cancellation)); + } + + static IEnumerator AsObservableCore(T asyncOperation, IObserver observer, IProgress reportProgress, CancellationToken cancel) + where T : AsyncOperation + { + if (reportProgress != null) + { + while (!asyncOperation.isDone && !cancel.IsCancellationRequested) + { + try + { + reportProgress.Report(asyncOperation.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + yield return null; + } + } + else + { + if (!asyncOperation.isDone) + { + yield return asyncOperation; + } + } + + if (cancel.IsCancellationRequested) yield break; + + if (reportProgress != null) + { + try + { + reportProgress.Report(asyncOperation.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + + observer.OnNext(asyncOperation); + observer.OnCompleted(); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs.meta new file mode 100644 index 00000000..784792e0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/AsyncOperationExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 245d77a29b1ece34e96bfc80f8c825d8 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs new file mode 100644 index 00000000..225eb2e3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs @@ -0,0 +1,40 @@ +#if !(NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + +using System; + +namespace UniRx +{ + public struct CancellationToken + { + readonly ICancelable source; + + public static readonly CancellationToken Empty = new CancellationToken(null); + + /// Same as Empty. + public static readonly CancellationToken None = new CancellationToken(null); + + public CancellationToken(ICancelable source) + { + this.source = source; + } + + public bool IsCancellationRequested + { + get + { + return (source == null) ? false : source.IsDisposed; + } + } + + public void ThrowIfCancellationRequested() + { + if (IsCancellationRequested) + { + throw new OperationCanceledException(); + } + } + } +} + +#endif + diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs.meta new file mode 100644 index 00000000..36f30ea2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CancellationToken.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e02a1bf45f8861048a6014cf7eab1825 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs new file mode 100644 index 00000000..db1ac7b1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs @@ -0,0 +1,125 @@ +#if (NET_4_6 || NET_STANDARD_2_0) + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace UniRx +{ + public class CoroutineAsyncBridge : INotifyCompletion + { + Action continuation; + public bool IsCompleted { get; private set; } + + CoroutineAsyncBridge() + { + IsCompleted = false; + } + + public static CoroutineAsyncBridge Start(T awaitTarget) + { + var bridge = new CoroutineAsyncBridge(); + MainThreadDispatcher.StartCoroutine(bridge.Run(awaitTarget)); + return bridge; + } + + IEnumerator Run(T target) + { + yield return target; + IsCompleted = true; + continuation(); + } + + public void OnCompleted(Action continuation) + { + this.continuation = continuation; + } + + public void GetResult() + { + if (!IsCompleted) throw new InvalidOperationException("coroutine not yet completed"); + } + } + + public class CoroutineAsyncBridge : INotifyCompletion + { + readonly T result; + Action continuation; + public bool IsCompleted { get; private set; } + + CoroutineAsyncBridge(T result) + { + IsCompleted = false; + this.result = result; + } + + public static CoroutineAsyncBridge Start(T awaitTarget) + { + var bridge = new CoroutineAsyncBridge(awaitTarget); + MainThreadDispatcher.StartCoroutine(bridge.Run(awaitTarget)); + return bridge; + } + + IEnumerator Run(T target) + { + yield return target; + IsCompleted = true; + continuation(); + } + + public void OnCompleted(Action continuation) + { + this.continuation = continuation; + } + + public T GetResult() + { + if (!IsCompleted) throw new InvalidOperationException("coroutine not yet completed"); + return result; + } + } + + public static class CoroutineAsyncExtensions + { + public static CoroutineAsyncBridge GetAwaiter(this Coroutine coroutine) + { + return CoroutineAsyncBridge.Start(coroutine); + } + +#if !(CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))) + + // should use UniRx.Async in C# 7.0 + +#if UNITY_2018_3_OR_NEWER +#pragma warning disable CS0618 +#endif + public static CoroutineAsyncBridge GetAwaiter(this WWW www) + { + return CoroutineAsyncBridge.Start(www); + } +#if UNITY_2018_3_OR_NEWER +#pragma warning restore CS0618 +#endif + + + + public static CoroutineAsyncBridge GetAwaiter(this AsyncOperation asyncOperation) + { + return CoroutineAsyncBridge.Start(asyncOperation); + } + + public static CoroutineAsyncBridge GetAwaiter(this IEnumerator coroutine) + { + return CoroutineAsyncBridge.Start(coroutine); + } + +#endif + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs.meta new file mode 100644 index 00000000..750a96d3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/CoroutineAsyncBridge.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 93ca3de3810199947871ab4a77014fa3 +timeCreated: 1475193276 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics.meta new file mode 100644 index 00000000..578aba81 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 125ca82be137b8544a2b65f7150ee2d4 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs new file mode 100644 index 00000000..deb5e656 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace UniRx.Diagnostics +{ + public struct LogEntry + { + // requires + public string LoggerName { get; private set; } + public LogType LogType { get; private set; } + public string Message { get; private set; } + public DateTime Timestamp { get; private set; } + + // options + + /// [Optional] + public UnityEngine.Object Context { get; private set; } + /// [Optional] + public Exception Exception { get; private set; } + /// [Optional] + public string StackTrace { get; private set; } + /// [Optional] + public object State { get; private set; } + + public LogEntry(string loggerName, LogType logType, DateTime timestamp, string message, UnityEngine.Object context = null, Exception exception = null, string stackTrace = null, object state = null) + : this() + { + this.LoggerName = loggerName; + this.LogType = logType; + this.Timestamp = timestamp; + this.Message = message; + this.Context = context; + this.Exception = exception; + this.StackTrace = stackTrace; + this.State = state; + } + + public override string ToString() + { + var plusEx = (Exception != null) ? (Environment.NewLine + Exception.ToString()) : ""; + return "[" + Timestamp.ToString() + "]" + + "[" + LoggerName + "]" + + "[" + LogType.ToString() + "]" + + Message + + plusEx; + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs.meta new file mode 100644 index 00000000..95439220 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntry.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 53917e87e91c0e4449402e5d85a04765 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs new file mode 100644 index 00000000..87a0ca42 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace UniRx.Diagnostics +{ + public static partial class LogEntryExtensions + { + public static IDisposable LogToUnityDebug(this IObservable source) + { + return source.Subscribe(new UnityDebugSink()); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs.meta new file mode 100644 index 00000000..e9fa9307 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/LogEntryExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8706ef5a13e53ec46b4848a7eec5e826 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs new file mode 100644 index 00000000..1313c54d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace UniRx.Diagnostics +{ + public partial class Logger + { + static bool isInitialized = false; + static bool isDebugBuild = false; + + public string Name { get; private set; } + protected readonly Action logPublisher; + + public Logger(string loggerName) + { + this.Name = loggerName; + this.logPublisher = ObservableLogger.RegisterLogger(this); + } + + /// Output LogType.Log but only enables isDebugBuild + public virtual void Debug(object message, UnityEngine.Object context = null) + { + if (!isInitialized) + { + isInitialized = true; + isDebugBuild = UnityEngine.Debug.isDebugBuild; + } + + if (isDebugBuild) + { + logPublisher(new LogEntry( + message: (message != null) ? message.ToString() : "", + logType: LogType.Log, + timestamp: DateTime.Now, + loggerName: Name, + context: context)); + } + } + + /// Output LogType.Log but only enables isDebugBuild + public virtual void DebugFormat(string format, params object[] args) + { + if (!isInitialized) + { + isInitialized = true; + isDebugBuild = UnityEngine.Debug.isDebugBuild; + } + + if (isDebugBuild) + { + logPublisher(new LogEntry( + message: (format != null) ? string.Format(format, args) : "", + logType: LogType.Log, + timestamp: DateTime.Now, + loggerName: Name, + context: null)); + } + } + + public virtual void Log(object message, UnityEngine.Object context = null) + { + logPublisher(new LogEntry( + message: (message != null) ? message.ToString() : "", + logType: LogType.Log, + timestamp: DateTime.Now, + loggerName: Name, + context: context)); + } + + public virtual void LogFormat(string format, params object[] args) + { + logPublisher(new LogEntry( + message: (format != null) ? string.Format(format, args) : "", + logType: LogType.Log, + timestamp: DateTime.Now, + loggerName: Name, + context: null)); + } + + public virtual void Warning(object message, UnityEngine.Object context = null) + { + logPublisher(new LogEntry( + message: (message != null) ? message.ToString() : "", + logType: LogType.Warning, + timestamp: DateTime.Now, + loggerName: Name, + context: context)); + } + + public virtual void WarningFormat(string format, params object[] args) + { + logPublisher(new LogEntry( + message: (format != null) ? string.Format(format, args) : "", + logType: LogType.Warning, + timestamp: DateTime.Now, + loggerName: Name, + context: null)); + } + + public virtual void Error(object message, UnityEngine.Object context = null) + { + logPublisher(new LogEntry( + message: (message != null) ? message.ToString() : "", + logType: LogType.Error, + timestamp: DateTime.Now, + loggerName: Name, + context: context)); + } + + public virtual void ErrorFormat(string format, params object[] args) + { + logPublisher(new LogEntry( + message: (format != null) ? string.Format(format, args) : "", + logType: LogType.Error, + timestamp: DateTime.Now, + loggerName: Name, + context: null)); + } + + public virtual void Exception(Exception exception, UnityEngine.Object context = null) + { + logPublisher(new LogEntry( + message: (exception != null) ? exception.ToString() : "", + exception: exception, + logType: LogType.Exception, + timestamp: DateTime.Now, + loggerName: Name, + context: context)); + } + + /// Publish raw LogEntry. + public virtual void Raw(LogEntry logEntry) + { + logPublisher(logEntry); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs.meta new file mode 100644 index 00000000..19135829 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/Logger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f0ecf366503cb0644bdd90934d24da62 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs new file mode 100644 index 00000000..0b1c05cf --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs @@ -0,0 +1,42 @@ +using System; + +namespace UniRx.Diagnostics +{ + public static class ObservableDebugExtensions + { + /// + /// Debug helper of observbale stream. Works for only DEBUG symbol. + /// + public static IObservable Debug(this IObservable source, string label = null) + { +#if DEBUG + var l = (label == null) ? "" : "[" + label + "]"; + return source.Materialize() + .Do(x => UnityEngine.Debug.Log(l + x.ToString())) + .Dematerialize() + .DoOnCancel(() => UnityEngine.Debug.Log(l + "OnCancel")) + .DoOnSubscribe(() => UnityEngine.Debug.Log(l + "OnSubscribe")); + +#else + return source; +#endif + } + + /// + /// Debug helper of observbale stream. Works for only DEBUG symbol. + /// + public static IObservable Debug(this IObservable source, UniRx.Diagnostics.Logger logger) + { +#if DEBUG + return source.Materialize() + .Do(x => logger.Debug(x.ToString())) + .Dematerialize() + .DoOnCancel(() => logger.Debug("OnCancel")) + .DoOnSubscribe(() => logger.Debug("OnSubscribe")); + +#else + return source; +#endif + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs.meta new file mode 100644 index 00000000..052c254a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableDebugExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b43f948e095c3e749a0506709be90d68 +timeCreated: 1468662620 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs new file mode 100644 index 00000000..91d5d5fb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace UniRx.Diagnostics +{ + public class ObservableLogger : IObservable + { + static readonly Subject logPublisher = new Subject(); + + public static readonly ObservableLogger Listener = new ObservableLogger(); + + private ObservableLogger() + { + + } + + public static Action RegisterLogger(Logger logger) + { + if (logger.Name == null) throw new ArgumentNullException("logger.Name is null"); + + return logPublisher.OnNext; + } + + public IDisposable Subscribe(IObserver observer) + { + return logPublisher.Subscribe(observer); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs.meta new file mode 100644 index 00000000..701a4ceb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/ObservableLogger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 063f79dc45f902c459f0955d27b445d7 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs new file mode 100644 index 00000000..a40a3d29 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace UniRx.Diagnostics +{ + public class UnityDebugSink : IObserver + { + public void OnCompleted() + { + // do nothing + } + + public void OnError(Exception error) + { + // do nothing + } + + public void OnNext(LogEntry value) + { + // avoid multithread exception. + // (value.Context == null) can only be called from the main thread. + var ctx = (System.Object)value.Context; + + switch (value.LogType) + { + case LogType.Error: + if (ctx == null) + { + Debug.LogError(value.Message); + } + else + { + Debug.LogError(value.Message, value.Context); + } + break; + case LogType.Exception: + if (ctx == null) + { + Debug.LogException(value.Exception); + } + else + { + Debug.LogException(value.Exception, value.Context); + } + break; + case LogType.Log: + if (ctx == null) + { + Debug.Log(value.Message); + } + else + { + Debug.Log(value.Message, value.Context); + } + break; + case LogType.Warning: + if (ctx == null) + { + Debug.LogWarning(value.Message); + } + else + { + Debug.LogWarning(value.Message, value.Context); + } + break; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs.meta new file mode 100644 index 00000000..e1db329d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Diagnostics/UnityDebugSink.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 882166c30c3bff841b1e12d62c392e02 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs new file mode 100644 index 00000000..8b1190b6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace UniRx +{ + /// + /// Represents a value associated with time interval information. + /// The time interval can represent the time it took to produce the value, the interval relative to a previous value, the value's delivery time relative to a base, etc. + /// + /// The type of the value being annotated with time interval information. + [Serializable] + public struct FrameInterval : IEquatable> + { + private readonly int _interval; + private readonly T _value; + + /// + /// Constructs a time interval value. + /// + /// The value to be annotated with a time interval. + /// Time interval associated with the value. + public FrameInterval(T value, int interval) + { + _interval = interval; + _value = value; + } + + /// + /// Gets the value. + /// + public T Value + { + get { return _value; } + } + + /// + /// Gets the interval. + /// + public int Interval + { + get { return _interval; } + } + + /// + /// Determines whether the current FrameInterval<T> value has the same Value and Interval as a specified FrameInterval<T> value. + /// + /// An object to compare to the current FrameInterval<T> value. + /// true if both FrameInterval<T> values have the same Value and Interval; otherwise, false. + public bool Equals(FrameInterval other) + { + return other.Interval.Equals(Interval) && EqualityComparer.Default.Equals(Value, other.Value); + } + + /// + /// Determines whether the two specified FrameInterval<T> values have the same Value and Interval. + /// + /// The first FrameInterval<T> value to compare. + /// The second FrameInterval<T> value to compare. + /// true if the first FrameInterval<T> value has the same Value and Interval as the second FrameInterval<T> value; otherwise, false. + public static bool operator ==(FrameInterval first, FrameInterval second) + { + return first.Equals(second); + } + + /// + /// Determines whether the two specified FrameInterval<T> values don't have the same Value and Interval. + /// + /// The first FrameInterval<T> value to compare. + /// The second FrameInterval<T> value to compare. + /// true if the first FrameInterval<T> value has a different Value or Interval as the second FrameInterval<T> value; otherwise, false. + public static bool operator !=(FrameInterval first, FrameInterval second) + { + return !first.Equals(second); + } + + /// + /// Determines whether the specified System.Object is equal to the current FrameInterval<T>. + /// + /// The System.Object to compare with the current FrameInterval<T>. + /// true if the specified System.Object is equal to the current FrameInterval<T>; otherwise, false. + public override bool Equals(object obj) + { + if (!(obj is FrameInterval)) + return false; + + var other = (FrameInterval)obj; + return this.Equals(other); + } + + /// + /// Returns the hash code for the current FrameInterval<T> value. + /// + /// A hash code for the current FrameInterval<T> value. + public override int GetHashCode() + { + var valueHashCode = Value == null ? 1963 : Value.GetHashCode(); + + return Interval.GetHashCode() ^ valueHashCode; + } + + /// + /// Returns a string representation of the current FrameInterval<T> value. + /// + /// String representation of the current FrameInterval<T> value. + public override string ToString() + { + return String.Format(CultureInfo.CurrentCulture, "{0}@{1}", Value, Interval); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs.meta new file mode 100644 index 00000000..1f6ba3bf --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/FrameInterval.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 266d1e44d71e7774c9abc5b23773e3f1 +timeCreated: 1467771656 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs new file mode 100644 index 00000000..90ddeabc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; +using UniRx.InternalUtil; +using UnityEngine; + +namespace UniRx +{ + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class IntReactiveProperty : ReactiveProperty + { + public IntReactiveProperty() + : base() + { + + } + + public IntReactiveProperty(int initialValue) + : base(initialValue) + { + + } + } + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class LongReactiveProperty : ReactiveProperty + { + public LongReactiveProperty() + : base() + { + + } + + public LongReactiveProperty(long initialValue) + : base(initialValue) + { + + } + } + + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class ByteReactiveProperty : ReactiveProperty + { + public ByteReactiveProperty() + : base() + { + + } + + public ByteReactiveProperty(byte initialValue) + : base(initialValue) + { + + } + } + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class FloatReactiveProperty : ReactiveProperty + { + public FloatReactiveProperty() + : base() + { + + } + + public FloatReactiveProperty(float initialValue) + : base(initialValue) + { + + } + } + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class DoubleReactiveProperty : ReactiveProperty + { + public DoubleReactiveProperty() + : base() + { + + } + + public DoubleReactiveProperty(double initialValue) + : base(initialValue) + { + + } + } + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class StringReactiveProperty : ReactiveProperty + { + public StringReactiveProperty() + : base() + { + + } + + public StringReactiveProperty(string initialValue) + : base(initialValue) + { + + } + } + + /// + /// Inspectable ReactiveProperty. + /// + [Serializable] + public class BoolReactiveProperty : ReactiveProperty + { + public BoolReactiveProperty() + : base() + { + + } + + public BoolReactiveProperty(bool initialValue) + : base(initialValue) + { + + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class Vector2ReactiveProperty : ReactiveProperty + { + public Vector2ReactiveProperty() + { + + } + + public Vector2ReactiveProperty(Vector2 initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Vector2; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class Vector3ReactiveProperty : ReactiveProperty + { + public Vector3ReactiveProperty() + { + + } + + public Vector3ReactiveProperty(Vector3 initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Vector3; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class Vector4ReactiveProperty : ReactiveProperty + { + public Vector4ReactiveProperty() + { + + } + + public Vector4ReactiveProperty(Vector4 initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Vector4; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class ColorReactiveProperty : ReactiveProperty + { + public ColorReactiveProperty() + { + + } + + public ColorReactiveProperty(Color initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Color; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class RectReactiveProperty : ReactiveProperty + { + public RectReactiveProperty() + { + + } + + public RectReactiveProperty(Rect initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Rect; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class AnimationCurveReactiveProperty : ReactiveProperty + { + public AnimationCurveReactiveProperty() + { + + } + + public AnimationCurveReactiveProperty(AnimationCurve initialValue) + : base(initialValue) + { + + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class BoundsReactiveProperty : ReactiveProperty + { + public BoundsReactiveProperty() + { + + } + + public BoundsReactiveProperty(Bounds initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Bounds; + } + } + } + + /// Inspectable ReactiveProperty. + [Serializable] + public class QuaternionReactiveProperty : ReactiveProperty + { + public QuaternionReactiveProperty() + { + + } + + public QuaternionReactiveProperty(Quaternion initialValue) + : base(initialValue) + { + + } + + protected override IEqualityComparer EqualityComparer + { + get + { + return UnityEqualityComparer.Quaternion; + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs.meta new file mode 100644 index 00000000..db9dddee --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectableReactiveProperty.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 13c690f353ea23141aca4090d28aaa9c +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs new file mode 100644 index 00000000..028d70da --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs @@ -0,0 +1,306 @@ +using System; +using System.Reflection; +using UnityEngine; +using System.Text.RegularExpressions; +using System.Collections; +using System.Linq; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace UniRx +{ + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + public class InspectorDisplayAttribute : PropertyAttribute + { + public string FieldName { get; private set; } + public bool NotifyPropertyChanged { get; private set; } + + public InspectorDisplayAttribute(string fieldName = "value", bool notifyPropertyChanged = true) + { + FieldName = fieldName; + NotifyPropertyChanged = notifyPropertyChanged; + } + } + + /// + /// Enables multiline input field for StringReactiveProperty. Default line is 3. + /// + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + public class MultilineReactivePropertyAttribute : PropertyAttribute + { + public int Lines { get; private set; } + + public MultilineReactivePropertyAttribute() + { + Lines = 3; + } + + public MultilineReactivePropertyAttribute(int lines) + { + this.Lines = lines; + } + } + + /// + /// Enables range input field for Int/FloatReactiveProperty. + /// + [System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + public class RangeReactivePropertyAttribute : PropertyAttribute + { + public float Min { get; private set; } + public float Max { get; private set; } + + public RangeReactivePropertyAttribute(float min, float max) + { + this.Min = min; + this.Max = max; + } + } + +#if UNITY_EDITOR + + + // InspectorDisplay and for Specialized ReactiveProperty + // If you want to customize other specialized ReactiveProperty + // [UnityEditor.CustomPropertyDrawer(typeof(YourSpecializedReactiveProperty))] + // public class ExtendInspectorDisplayDrawer : InspectorDisplayDrawer { } + + [UnityEditor.CustomPropertyDrawer(typeof(InspectorDisplayAttribute))] + [UnityEditor.CustomPropertyDrawer(typeof(IntReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(LongReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(ByteReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(FloatReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(DoubleReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(StringReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(BoolReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(Vector2ReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(Vector3ReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(Vector4ReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(ColorReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(RectReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(AnimationCurveReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(BoundsReactiveProperty))] + [UnityEditor.CustomPropertyDrawer(typeof(QuaternionReactiveProperty))] + public class InspectorDisplayDrawer : UnityEditor.PropertyDrawer + { + public override void OnGUI(Rect position, UnityEditor.SerializedProperty property, GUIContent label) + { + string fieldName; + bool notifyPropertyChanged; + { + var attr = this.attribute as InspectorDisplayAttribute; + fieldName = (attr == null) ? "value" : attr.FieldName; + notifyPropertyChanged = (attr == null) ? true : attr.NotifyPropertyChanged; + } + + if (notifyPropertyChanged) + { + EditorGUI.BeginChangeCheck(); + } + var targetSerializedProperty = property.FindPropertyRelative(fieldName); + if (targetSerializedProperty == null) + { + UnityEditor.EditorGUI.LabelField(position, label, new GUIContent() { text = "InspectorDisplay can't find target:" + fieldName }); + if (notifyPropertyChanged) + { + EditorGUI.EndChangeCheck(); + } + return; + } + else + { + EmitPropertyField(position, targetSerializedProperty, label); + } + + if (notifyPropertyChanged) + { + if (EditorGUI.EndChangeCheck()) + { + property.serializedObject.ApplyModifiedProperties(); // deserialize to field + + var paths = property.propertyPath.Split('.'); // X.Y.Z... + var attachedComponent = property.serializedObject.targetObject; + + var targetProp = (paths.Length == 1) + ? fieldInfo.GetValue(attachedComponent) + : GetValueRecursive(attachedComponent, 0, paths); + if (targetProp == null) return; + var propInfo = targetProp.GetType().GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var modifiedValue = propInfo.GetValue(targetProp, null); // retrieve new value + + var methodInfo = targetProp.GetType().GetMethod("SetValueAndForceNotify", BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (methodInfo != null) + { + methodInfo.Invoke(targetProp, new object[] { modifiedValue }); + } + } + else + { + property.serializedObject.ApplyModifiedProperties(); + } + } + } + + object GetValueRecursive(object obj, int index, string[] paths) + { + var path = paths[index]; + + FieldInfo fldInfo = null; + var type = obj.GetType(); + while (fldInfo == null) + { + // attempt to get information about the field + fldInfo = type.GetField(path, BindingFlags.IgnoreCase | BindingFlags.GetField | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + + if (fldInfo != null || + type.BaseType == null || + type.BaseType.IsSubclassOf(typeof(ReactiveProperty<>))) break; + + // if the field information is missing, it may be in the base class + type = type.BaseType; + } + + // If array, path = Array.data[index] + if (fldInfo == null && path == "Array") + { + try + { + path = paths[++index]; + var m = Regex.Match(path, @"(.+)\[([0-9]+)*\]"); + var arrayIndex = int.Parse(m.Groups[2].Value); + var arrayValue = (obj as System.Collections.IList)[arrayIndex]; + if (index < paths.Length - 1) + { + return GetValueRecursive(arrayValue, ++index, paths); + } + else + { + return arrayValue; + } + } + catch + { + Debug.Log("InspectorDisplayDrawer Exception, objType:" + obj.GetType().Name + " path:" + string.Join(", ", paths)); + throw; + } + } + else if (fldInfo == null) + { + throw new Exception("Can't decode path, please report to UniRx's GitHub issues:" + string.Join(", ", paths)); + } + + var v = fldInfo.GetValue(obj); + if (index < paths.Length - 1) + { + return GetValueRecursive(v, ++index, paths); + } + + return v; + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + var attr = this.attribute as InspectorDisplayAttribute; + var fieldName = (attr == null) ? "value" : attr.FieldName; + + var height = base.GetPropertyHeight(property, label); + var valueProperty = property.FindPropertyRelative(fieldName); + if (valueProperty == null) + { + return height; + } + + if (valueProperty.propertyType == SerializedPropertyType.Rect) + { + return height * 2; + } + if (valueProperty.propertyType == SerializedPropertyType.Bounds) + { + return height * 3; + } + if (valueProperty.propertyType == SerializedPropertyType.String) + { + var multilineAttr = GetMultilineAttribute(); + if (multilineAttr != null) + { + return ((!EditorGUIUtility.wideMode) ? 16f : 0f) + 16f + (float)((multilineAttr.Lines - 1) * 13); + }; + } + + if (valueProperty.isExpanded) + { + var count = 0; + var e = valueProperty.GetEnumerator(); + while (e.MoveNext()) count++; + return ((height + 4) * count) + 6; // (Line = 20 + Padding) ? + } + + return height; + } + + protected virtual void EmitPropertyField(Rect position, UnityEditor.SerializedProperty targetSerializedProperty, GUIContent label) + { + var multiline = GetMultilineAttribute(); + if (multiline == null) + { + var range = GetRangeAttribute(); + if (range == null) + { + UnityEditor.EditorGUI.PropertyField(position, targetSerializedProperty, label, includeChildren: true); + } + else + { + if (targetSerializedProperty.propertyType == SerializedPropertyType.Float) + { + EditorGUI.Slider(position, targetSerializedProperty, range.Min, range.Max, label); + } + else if (targetSerializedProperty.propertyType == SerializedPropertyType.Integer) + { + EditorGUI.IntSlider(position, targetSerializedProperty, (int)range.Min, (int)range.Max, label); + } + else + { + EditorGUI.LabelField(position, label.text, "Use Range with float or int."); + } + } + } + else + { + var property = targetSerializedProperty; + + label = EditorGUI.BeginProperty(position, label, property); + var method = typeof(EditorGUI).GetMethod("MultiFieldPrefixLabel", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic); + position = (Rect)method.Invoke(null, new object[] { position, 0, label, 1 }); + + EditorGUI.BeginChangeCheck(); + int indentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + var stringValue = EditorGUI.TextArea(position, property.stringValue); + EditorGUI.indentLevel = indentLevel; + if (EditorGUI.EndChangeCheck()) + { + property.stringValue = stringValue; + } + EditorGUI.EndProperty(); + } + } + + MultilineReactivePropertyAttribute GetMultilineAttribute() + { + var fi = this.fieldInfo; + if (fi == null) return null; + return fi.GetCustomAttributes(false).OfType().FirstOrDefault(); + } + + RangeReactivePropertyAttribute GetRangeAttribute() + { + var fi = this.fieldInfo; + if (fi == null) return null; + return fi.GetCustomAttributes(false).OfType().FirstOrDefault(); + } + } + +#endif +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs.meta new file mode 100644 index 00000000..7e1c0062 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/InspectorDisplayDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6180f9fd2198dee44ae7f4a617529ffa +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs new file mode 100644 index 00000000..9103e437 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UniRx.Triggers; +using UnityEngine; + +namespace UniRx +{ + public static partial class DisposableExtensions + { + /// Dispose self on target gameObject has been destroyed. Return value is self disposable. + public static T AddTo(this T disposable, GameObject gameObject) + where T : IDisposable + { + if (gameObject == null) + { + disposable.Dispose(); + return disposable; + } + + var trigger = gameObject.GetComponent(); + if (trigger == null) + { + trigger = gameObject.AddComponent(); + } + +#pragma warning disable 618 + + // If gameObject is deactive, does not raise OnDestroy, watch and invoke trigger. + if (!trigger.IsActivated && !trigger.IsMonitoredActivate && !trigger.gameObject.activeInHierarchy) + { + trigger.IsMonitoredActivate = true; + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(MonitorTriggerHealth(trigger, gameObject)); + } + +#pragma warning restore 618 + + trigger.AddDisposableOnDestroy(disposable); + return disposable; + } + + static IEnumerator MonitorTriggerHealth(ObservableDestroyTrigger trigger, GameObject targetGameObject) + { + while (true) + { + yield return null; + if (trigger.IsActivated) yield break; + + if (targetGameObject == null) // isDestroy + { + trigger.ForceRaiseOnDestroy(); // Force publish OnDestroy + yield break; + } + } + } + + /// Dispose self on target gameObject has been destroyed. Return value is self disposable. + public static T AddTo(this T disposable, Component gameObjectComponent) + where T : IDisposable + { + if (gameObjectComponent == null) + { + disposable.Dispose(); + return disposable; + } + + return AddTo(disposable, gameObjectComponent.gameObject); + } + + /// + /// Add disposable(self) to CompositeDisposable(or other ICollection) and Dispose self on target gameObject has been destroyed. + /// Return value is self disposable. + /// + public static T AddTo(this T disposable, ICollection container, GameObject gameObject) + where T : IDisposable + { + return disposable.AddTo(container).AddTo(gameObject); + } + + /// + /// Add disposable(self) to CompositeDisposable(or other ICollection) and Dispose self on target gameObject has been destroyed. + /// Return value is self disposable. + /// + public static T AddTo(this T disposable, ICollection container, Component gameObjectComponent) + where T : IDisposable + { + return disposable.AddTo(container).AddTo(gameObjectComponent); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs.meta new file mode 100644 index 00000000..5ffd46a1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/LifetimeDisposableExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a7474e4acdc541340a1f566b2df46355 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs new file mode 100644 index 00000000..741a5a5f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs @@ -0,0 +1,683 @@ +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2) +#define SupportCustomYieldInstruction +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using UniRx.InternalUtil; +using UnityEngine; + +namespace UniRx +{ + public sealed class MainThreadDispatcher : MonoBehaviour + { + public enum CullingMode + { + /// + /// Won't remove any MainThreadDispatchers. + /// + Disabled, + + /// + /// Checks if there is an existing MainThreadDispatcher on Awake(). If so, the new dispatcher removes itself. + /// + Self, + + /// + /// Search for excess MainThreadDispatchers and removes them all on Awake(). + /// + All + } + + public static CullingMode cullingMode = CullingMode.Self; + +#if UNITY_EDITOR + + // In UnityEditor's EditorMode can't instantiate and work MonoBehaviour.Update. + // EditorThreadDispatcher use EditorApplication.update instead of MonoBehaviour.Update. + class EditorThreadDispatcher + { + static object gate = new object(); + static EditorThreadDispatcher instance; + + public static EditorThreadDispatcher Instance + { + get + { + // Activate EditorThreadDispatcher is dangerous, completely Lazy. + lock (gate) + { + if (instance == null) + { + instance = new EditorThreadDispatcher(); + } + + return instance; + } + } + } + + ThreadSafeQueueWorker editorQueueWorker = new ThreadSafeQueueWorker(); + + EditorThreadDispatcher() + { + UnityEditor.EditorApplication.update += Update; + } + + public void Enqueue(Action action, object state) + { + editorQueueWorker.Enqueue(action, state); + } + + public void UnsafeInvoke(Action action) + { + try + { + action(); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + public void UnsafeInvoke(Action action, T state) + { + try + { + action(state); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + + public void PseudoStartCoroutine(IEnumerator routine) + { + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(routine), null); + } + + void Update() + { + editorQueueWorker.ExecuteAll(x => Debug.LogException(x)); + } + + void ConsumeEnumerator(IEnumerator routine) + { + if (routine.MoveNext()) + { + var current = routine.Current; + if (current == null) + { + goto ENQUEUE; + } + + var type = current.GetType(); +#if UNITY_2018_3_OR_NEWER +#pragma warning disable CS0618 +#endif + if (type == typeof(WWW)) + { + var www = (WWW)current; + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(UnwrapWaitWWW(www, routine)), null); + return; + } +#if UNITY_2018_3_OR_NEWER +#pragma warning restore CS0618 +#endif + else if (type == typeof(AsyncOperation)) + { + var asyncOperation = (AsyncOperation)current; + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(UnwrapWaitAsyncOperation(asyncOperation, routine)), null); + return; + } + else if (type == typeof(WaitForSeconds)) + { + var waitForSeconds = (WaitForSeconds)current; + var accessor = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic); + var second = (float)accessor.GetValue(waitForSeconds); + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(UnwrapWaitForSeconds(second, routine)), null); + return; + } + else if (type == typeof(Coroutine)) + { + Debug.Log("Can't wait coroutine on UnityEditor"); + goto ENQUEUE; + } +#if SupportCustomYieldInstruction + else if (current is IEnumerator) + { + var enumerator = (IEnumerator)current; + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(UnwrapEnumerator(enumerator, routine)), null); + return; + } +#endif + + ENQUEUE: + editorQueueWorker.Enqueue(_ => ConsumeEnumerator(routine), null); // next update + } + } + +#if UNITY_2018_3_OR_NEWER +#pragma warning disable CS0618 +#endif + IEnumerator UnwrapWaitWWW(WWW www, IEnumerator continuation) + { + while (!www.isDone) + { + yield return null; + } + ConsumeEnumerator(continuation); + } +#if UNITY_2018_3_OR_NEWER +#pragma warning restore CS0618 +#endif + + IEnumerator UnwrapWaitAsyncOperation(AsyncOperation asyncOperation, IEnumerator continuation) + { + while (!asyncOperation.isDone) + { + yield return null; + } + ConsumeEnumerator(continuation); + } + + IEnumerator UnwrapWaitForSeconds(float second, IEnumerator continuation) + { + var startTime = DateTimeOffset.UtcNow; + while (true) + { + yield return null; + + var elapsed = (DateTimeOffset.UtcNow - startTime).TotalSeconds; + if (elapsed >= second) + { + break; + } + }; + ConsumeEnumerator(continuation); + } + + IEnumerator UnwrapEnumerator(IEnumerator enumerator, IEnumerator continuation) + { + while (enumerator.MoveNext()) + { + yield return null; + } + ConsumeEnumerator(continuation); + } + } + +#endif + + /// Dispatch Asyncrhonous action. + public static void Post(Action action, object state) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.Enqueue(action, state); return; } + +#endif + + var dispatcher = Instance; + if (!isQuitting && !object.ReferenceEquals(dispatcher, null)) + { + dispatcher.queueWorker.Enqueue(action, state); + } + } + + /// Dispatch Synchronous action if possible. + public static void Send(Action action, object state) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.Enqueue(action, state); return; } +#endif + + if (mainThreadToken != null) + { + try + { + action(state); + } + catch (Exception ex) + { + var dispatcher = MainThreadDispatcher.Instance; + if (dispatcher != null) + { + dispatcher.unhandledExceptionCallback(ex); + } + } + } + else + { + Post(action, state); + } + } + + /// Run Synchronous action. + public static void UnsafeSend(Action action) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.UnsafeInvoke(action); return; } +#endif + + try + { + action(); + } + catch (Exception ex) + { + var dispatcher = MainThreadDispatcher.Instance; + if (dispatcher != null) + { + dispatcher.unhandledExceptionCallback(ex); + } + } + } + + /// Run Synchronous action. + public static void UnsafeSend(Action action, T state) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.UnsafeInvoke(action, state); return; } +#endif + + try + { + action(state); + } + catch (Exception ex) + { + var dispatcher = MainThreadDispatcher.Instance; + if (dispatcher != null) + { + dispatcher.unhandledExceptionCallback(ex); + } + } + } + + /// ThreadSafe StartCoroutine. + public static void SendStartCoroutine(IEnumerator routine) + { + if (mainThreadToken != null) + { + StartCoroutine(routine); + } + else + { +#if UNITY_EDITOR + // call from other thread + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.PseudoStartCoroutine(routine); return; } +#endif + + var dispatcher = Instance; + if (!isQuitting && !object.ReferenceEquals(dispatcher, null)) + { + dispatcher.queueWorker.Enqueue(_ => + { + var dispacher2 = Instance; + if (dispacher2 != null) + { + (dispacher2 as MonoBehaviour).StartCoroutine(routine); + } + }, null); + } + } + } + + public static void StartUpdateMicroCoroutine(IEnumerator routine) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.PseudoStartCoroutine(routine); return; } +#endif + + var dispatcher = Instance; + if (dispatcher != null) + { + dispatcher.updateMicroCoroutine.AddCoroutine(routine); + } + } + + public static void StartFixedUpdateMicroCoroutine(IEnumerator routine) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.PseudoStartCoroutine(routine); return; } +#endif + + var dispatcher = Instance; + if (dispatcher != null) + { + dispatcher.fixedUpdateMicroCoroutine.AddCoroutine(routine); + } + } + + public static void StartEndOfFrameMicroCoroutine(IEnumerator routine) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.PseudoStartCoroutine(routine); return; } +#endif + + var dispatcher = Instance; + if (dispatcher != null) + { + dispatcher.endOfFrameMicroCoroutine.AddCoroutine(routine); + } + } + + new public static Coroutine StartCoroutine(IEnumerator routine) + { +#if UNITY_EDITOR + if (!ScenePlaybackDetector.IsPlaying) { EditorThreadDispatcher.Instance.PseudoStartCoroutine(routine); return null; } +#endif + + var dispatcher = Instance; + if (dispatcher != null) + { + return (dispatcher as MonoBehaviour).StartCoroutine(routine); + } + else + { + return null; + } + } + + public static void RegisterUnhandledExceptionCallback(Action exceptionCallback) + { + if (exceptionCallback == null) + { + // do nothing + Instance.unhandledExceptionCallback = Stubs.Ignore; + } + else + { + Instance.unhandledExceptionCallback = exceptionCallback; + } + } + + ThreadSafeQueueWorker queueWorker = new ThreadSafeQueueWorker(); + Action unhandledExceptionCallback = ex => Debug.LogException(ex); // default + + MicroCoroutine updateMicroCoroutine = null; + MicroCoroutine fixedUpdateMicroCoroutine = null; + MicroCoroutine endOfFrameMicroCoroutine = null; + + static MainThreadDispatcher instance; + static bool initialized; + static bool isQuitting = false; + + public static string InstanceName + { + get + { + if (instance == null) + { + throw new NullReferenceException("MainThreadDispatcher is not initialized."); + } + return instance.name; + } + } + + public static bool IsInitialized + { + get { return initialized && instance != null; } + } + + [ThreadStatic] + static object mainThreadToken; + + static MainThreadDispatcher Instance + { + get + { + Initialize(); + return instance; + } + } + + public static void Initialize() + { + if (!initialized) + { +#if UNITY_EDITOR + // Don't try to add a GameObject when the scene is not playing. Only valid in the Editor, EditorView. + if (!ScenePlaybackDetector.IsPlaying) return; +#endif + MainThreadDispatcher dispatcher = null; + + try + { + dispatcher = GameObject.FindObjectOfType(); + } + catch + { + // Throw exception when calling from a worker thread. + var ex = new Exception("UniRx requires a MainThreadDispatcher component created on the main thread. Make sure it is added to the scene before calling UniRx from a worker thread."); + UnityEngine.Debug.LogException(ex); + throw ex; + } + + if (isQuitting) + { + // don't create new instance after quitting + // avoid "Some objects were not cleaned up when closing the scene find target" error. + return; + } + + if (dispatcher == null) + { + // awake call immediately from UnityEngine + new GameObject("MainThreadDispatcher").AddComponent(); + } + else + { + dispatcher.Awake(); // force awake + } + } + } + + public static bool IsInMainThread + { + get + { + return (mainThreadToken != null); + } + } + + void Awake() + { + if (instance == null) + { + instance = this; + mainThreadToken = new object(); + initialized = true; + + updateMicroCoroutine = new MicroCoroutine(ex => unhandledExceptionCallback(ex)); + fixedUpdateMicroCoroutine = new MicroCoroutine(ex => unhandledExceptionCallback(ex)); + endOfFrameMicroCoroutine = new MicroCoroutine(ex => unhandledExceptionCallback(ex)); + + StartCoroutine(RunUpdateMicroCoroutine()); + StartCoroutine(RunFixedUpdateMicroCoroutine()); + StartCoroutine(RunEndOfFrameMicroCoroutine()); + + DontDestroyOnLoad(gameObject); + } + else + { + if (this != instance) + { + if (cullingMode == CullingMode.Self) + { + // Try to destroy this dispatcher if there's already one in the scene. + Debug.LogWarning("There is already a MainThreadDispatcher in the scene. Removing myself..."); + DestroyDispatcher(this); + } + else if (cullingMode == CullingMode.All) + { + Debug.LogWarning("There is already a MainThreadDispatcher in the scene. Cleaning up all excess dispatchers..."); + CullAllExcessDispatchers(); + } + else + { + Debug.LogWarning("There is already a MainThreadDispatcher in the scene."); + } + } + } + } + + IEnumerator RunUpdateMicroCoroutine() + { + while (true) + { + yield return null; + updateMicroCoroutine.Run(); + } + } + + IEnumerator RunFixedUpdateMicroCoroutine() + { + while (true) + { + yield return YieldInstructionCache.WaitForFixedUpdate; + fixedUpdateMicroCoroutine.Run(); + } + } + + IEnumerator RunEndOfFrameMicroCoroutine() + { + while (true) + { + yield return YieldInstructionCache.WaitForEndOfFrame; + endOfFrameMicroCoroutine.Run(); + } + } + + static void DestroyDispatcher(MainThreadDispatcher aDispatcher) + { + if (aDispatcher != instance) + { + // Try to remove game object if it's empty + var components = aDispatcher.gameObject.GetComponents(); + if (aDispatcher.gameObject.transform.childCount == 0 && components.Length == 2) + { + if (components[0] is Transform && components[1] is MainThreadDispatcher) + { + Destroy(aDispatcher.gameObject); + } + } + else + { + // Remove component + MonoBehaviour.Destroy(aDispatcher); + } + } + } + + public static void CullAllExcessDispatchers() + { + var dispatchers = GameObject.FindObjectsOfType(); + for (int i = 0; i < dispatchers.Length; i++) + { + DestroyDispatcher(dispatchers[i]); + } + } + + void OnDestroy() + { + if (instance == this) + { + instance = GameObject.FindObjectOfType(); + initialized = instance != null; + + /* + // Although `this` still refers to a gameObject, it won't be found. + var foundDispatcher = GameObject.FindObjectOfType(); + + if (foundDispatcher != null) + { + // select another game object + Debug.Log("new instance: " + foundDispatcher.name); + instance = foundDispatcher; + initialized = true; + } + */ + } + } + + void Update() + { + if (update != null) + { + try + { + update.OnNext(Unit.Default); + } + catch (Exception ex) + { + unhandledExceptionCallback(ex); + } + } + queueWorker.ExecuteAll(unhandledExceptionCallback); + } + + // for Lifecycle Management + + Subject update; + + public static IObservable UpdateAsObservable() + { + return Instance.update ?? (Instance.update = new Subject()); + } + + Subject lateUpdate; + + void LateUpdate() + { + if (lateUpdate != null) lateUpdate.OnNext(Unit.Default); + } + + public static IObservable LateUpdateAsObservable() + { + return Instance.lateUpdate ?? (Instance.lateUpdate = new Subject()); + } + + Subject onApplicationFocus; + + void OnApplicationFocus(bool focus) + { + if (onApplicationFocus != null) onApplicationFocus.OnNext(focus); + } + + public static IObservable OnApplicationFocusAsObservable() + { + return Instance.onApplicationFocus ?? (Instance.onApplicationFocus = new Subject()); + } + + Subject onApplicationPause; + + void OnApplicationPause(bool pause) + { + if (onApplicationPause != null) onApplicationPause.OnNext(pause); + } + + public static IObservable OnApplicationPauseAsObservable() + { + return Instance.onApplicationPause ?? (Instance.onApplicationPause = new Subject()); + } + + Subject onApplicationQuit; + + void OnApplicationQuit() + { + isQuitting = true; + if (onApplicationQuit != null) onApplicationQuit.OnNext(Unit.Default); + } + + public static IObservable OnApplicationQuitAsObservable() + { + return Instance.onApplicationQuit ?? (Instance.onApplicationQuit = new Subject()); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs.meta new file mode 100644 index 00000000..66bb9ba3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadDispatcher.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c3cd207057515c4438a31a6a7b548fe7 +timeCreated: 1465903910 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: -16000 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs new file mode 100644 index 00000000..cf6262d6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs @@ -0,0 +1,579 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using UnityEngine; + +namespace UniRx +{ +#if UniRxLibrary + public static partial class SchedulerUnity + { +#else + public static partial class Scheduler + { + public static void SetDefaultForUnity() + { + Scheduler.DefaultSchedulers.ConstantTimeOperations = Scheduler.Immediate; + Scheduler.DefaultSchedulers.TailRecursion = Scheduler.Immediate; + Scheduler.DefaultSchedulers.Iteration = Scheduler.CurrentThread; + Scheduler.DefaultSchedulers.TimeBasedOperations = MainThread; + Scheduler.DefaultSchedulers.AsyncConversions = Scheduler.ThreadPool; + } +#endif + static IScheduler mainThread; + + /// + /// Unity native MainThread Queue Scheduler. Run on mainthread and delayed on coroutine update loop, elapsed time is calculated based on Time.time. + /// + public static IScheduler MainThread + { + get + { + return mainThread ?? (mainThread = new MainThreadScheduler()); + } + } + + static IScheduler mainThreadIgnoreTimeScale; + + /// + /// Another MainThread scheduler, delay elapsed time is calculated based on Time.unscaledDeltaTime. + /// + public static IScheduler MainThreadIgnoreTimeScale + { + get + { + return mainThreadIgnoreTimeScale ?? (mainThreadIgnoreTimeScale = new IgnoreTimeScaleMainThreadScheduler()); + } + } + + static IScheduler mainThreadFixedUpdate; + + /// + /// Run on fixed update mainthread, delay elapsed time is calculated based on Time.fixedTime. + /// + public static IScheduler MainThreadFixedUpdate + { + get + { + return mainThreadFixedUpdate ?? (mainThreadFixedUpdate = new FixedUpdateMainThreadScheduler()); + } + } + + static IScheduler mainThreadEndOfFrame; + + /// + /// Run on end of frame mainthread, delay elapsed time is calculated based on Time.deltaTime. + /// + public static IScheduler MainThreadEndOfFrame + { + get + { + return mainThreadEndOfFrame ?? (mainThreadEndOfFrame = new EndOfFrameMainThreadScheduler()); + } + } + + class MainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing + { + readonly Action scheduleAction; + + public MainThreadScheduler() + { + MainThreadDispatcher.Initialize(); + scheduleAction = new Action(Schedule); + } + + // delay action is run in StartCoroutine + // Okay to action run synchronous and guaranteed run on MainThread + IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation) + { + // zero == every frame + if (dueTime == TimeSpan.Zero) + { + yield return null; // not immediately, run next frame + } + else + { + yield return new WaitForSeconds((float)dueTime.TotalSeconds); + } + + if (cancellation.IsDisposed) yield break; + MainThreadDispatcher.UnsafeSend(action); + } + + IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation) + { + // zero == every frame + if (period == TimeSpan.Zero) + { + while (true) + { + yield return null; // not immediately, run next frame + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + } + else + { + var seconds = (float)(period.TotalMilliseconds / 1000.0); + var yieldInstruction = new WaitForSeconds(seconds); // cache single instruction object + + while (true) + { + yield return yieldInstruction; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + } + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + void Schedule(object state) + { + var t = (Tuple)state; + if (!t.Item1.IsDisposed) + { + t.Item2(); + } + } + + public IDisposable Schedule(Action action) + { + var d = new BooleanDisposable(); + MainThreadDispatcher.Post(scheduleAction, Tuple.Create(d, action)); + return d; + } + + public IDisposable Schedule(DateTimeOffset dueTime, Action action) + { + return Schedule(dueTime - Now, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(dueTime); + + MainThreadDispatcher.SendStartCoroutine(DelayAction(time, action, d)); + + return d; + } + + public IDisposable SchedulePeriodic(TimeSpan period, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(period); + + MainThreadDispatcher.SendStartCoroutine(PeriodicAction(time, action, d)); + + return d; + } + + void ScheduleQueueing(object state) + { + var t = (Tuple>)state; + if (!t.Item1.IsDisposed) + { + t.Item3(t.Item2); + } + } + + public void ScheduleQueueing(ICancelable cancel, T state, Action action) + { + MainThreadDispatcher.Post(QueuedAction.Instance, Tuple.Create(cancel, state, action)); + } + + static class QueuedAction + { + public static readonly Action Instance = new Action(Invoke); + + public static void Invoke(object state) + { + var t = (Tuple>)state; + + if (!t.Item1.IsDisposed) + { + t.Item3(t.Item2); + } + } + } + } + + class IgnoreTimeScaleMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing + { + readonly Action scheduleAction; + + public IgnoreTimeScaleMainThreadScheduler() + { + MainThreadDispatcher.Initialize(); + scheduleAction = new Action(Schedule); + } + + IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation) + { + if (dueTime == TimeSpan.Zero) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + else + { + var elapsed = 0f; + var dt = (float)dueTime.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + elapsed += Time.unscaledDeltaTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + break; + } + } + } + } + + IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation) + { + // zero == every frame + if (period == TimeSpan.Zero) + { + while (true) + { + yield return null; // not immediately, run next frame + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + } + else + { + var elapsed = 0f; + var dt = (float)period.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + elapsed += Time.unscaledDeltaTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + elapsed = 0; + } + } + } + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + void Schedule(object state) + { + var t = (Tuple)state; + if (!t.Item1.IsDisposed) + { + t.Item2(); + } + } + + public IDisposable Schedule(Action action) + { + var d = new BooleanDisposable(); + MainThreadDispatcher.Post(scheduleAction, Tuple.Create(d, action)); + return d; + } + + public IDisposable Schedule(DateTimeOffset dueTime, Action action) + { + return Schedule(dueTime - Now, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(dueTime); + + MainThreadDispatcher.SendStartCoroutine(DelayAction(time, action, d)); + + return d; + } + + public IDisposable SchedulePeriodic(TimeSpan period, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(period); + + MainThreadDispatcher.SendStartCoroutine(PeriodicAction(time, action, d)); + + return d; + } + + public void ScheduleQueueing(ICancelable cancel, T state, Action action) + { + MainThreadDispatcher.Post(QueuedAction.Instance, Tuple.Create(cancel, state, action)); + } + + static class QueuedAction + { + public static readonly Action Instance = new Action(Invoke); + + public static void Invoke(object state) + { + var t = (Tuple>)state; + + if (!t.Item1.IsDisposed) + { + t.Item3(t.Item2); + } + } + } + } + + class FixedUpdateMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing + { + public FixedUpdateMainThreadScheduler() + { + MainThreadDispatcher.Initialize(); + } + + IEnumerator ImmediateAction(T state, Action action, ICancelable cancellation) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action, state); + } + + IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation) + { + if (dueTime == TimeSpan.Zero) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + else + { + var startTime = Time.fixedTime; + var dt = (float)dueTime.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + var elapsed = Time.fixedTime - startTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + break; + } + } + } + } + + IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation) + { + // zero == every frame + if (period == TimeSpan.Zero) + { + while (true) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + } + else + { + var startTime = Time.fixedTime; + var dt = (float)period.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + var ft = Time.fixedTime; + var elapsed = ft - startTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + startTime = ft; + } + } + } + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + public IDisposable Schedule(Action action) + { + return Schedule(TimeSpan.Zero, action); + } + + public IDisposable Schedule(DateTimeOffset dueTime, Action action) + { + return Schedule(dueTime - Now, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(dueTime); + + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(DelayAction(time, action, d)); + + return d; + } + + public IDisposable SchedulePeriodic(TimeSpan period, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(period); + + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(PeriodicAction(time, action, d)); + + return d; + } + + public void ScheduleQueueing(ICancelable cancel, T state, Action action) + { + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(ImmediateAction(state, action, cancel)); + } + } + + class EndOfFrameMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing + { + public EndOfFrameMainThreadScheduler() + { + MainThreadDispatcher.Initialize(); + } + + IEnumerator ImmediateAction(T state, Action action, ICancelable cancellation) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action, state); + } + + IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation) + { + if (dueTime == TimeSpan.Zero) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + else + { + var elapsed = 0f; + var dt = (float)dueTime.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + elapsed += Time.deltaTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + break; + } + } + } + } + + IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation) + { + // zero == every frame + if (period == TimeSpan.Zero) + { + while (true) + { + yield return null; + if (cancellation.IsDisposed) yield break; + + MainThreadDispatcher.UnsafeSend(action); + } + } + else + { + var elapsed = 0f; + var dt = (float)period.TotalSeconds; + while (true) + { + yield return null; + if (cancellation.IsDisposed) break; + + elapsed += Time.deltaTime; + if (elapsed >= dt) + { + MainThreadDispatcher.UnsafeSend(action); + elapsed = 0; + } + } + } + } + + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + public IDisposable Schedule(Action action) + { + return Schedule(TimeSpan.Zero, action); + } + + public IDisposable Schedule(DateTimeOffset dueTime, Action action) + { + return Schedule(dueTime - Now, action); + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(dueTime); + + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(DelayAction(time, action, d)); + + return d; + } + + public IDisposable SchedulePeriodic(TimeSpan period, Action action) + { + var d = new BooleanDisposable(); + var time = Scheduler.Normalize(period); + + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(PeriodicAction(time, action, d)); + + return d; + } + + public void ScheduleQueueing(ICancelable cancel, T state, Action action) + { + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(ImmediateAction(state, action, cancel)); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs.meta new file mode 100644 index 00000000..534aacb1 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/MainThreadScheduler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f141c5dc72b97084a85631367a946ee8 +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs new file mode 100644 index 00000000..c91af941 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs @@ -0,0 +1,1168 @@ +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2) +#define SupportCustomYieldInstruction +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using UniRx.InternalUtil; +using UniRx.Triggers; +using UnityEngine; +using System.Threading; + +#if !UniRxLibrary +using SchedulerUnity = UniRx.Scheduler; +#endif + +namespace UniRx +{ + public enum FrameCountType + { + Update, + FixedUpdate, + EndOfFrame, + } + + public enum MainThreadDispatchType + { + /// yield return null + Update, + FixedUpdate, + EndOfFrame, + GameObjectUpdate, + LateUpdate, + } + + public static class FrameCountTypeExtensions + { + public static YieldInstruction GetYieldInstruction(this FrameCountType frameCountType) + { + switch (frameCountType) + { + case FrameCountType.FixedUpdate: + return YieldInstructionCache.WaitForFixedUpdate; + case FrameCountType.EndOfFrame: + return YieldInstructionCache.WaitForEndOfFrame; + case FrameCountType.Update: + default: + return null; + } + } + } + + internal interface ICustomYieldInstructionErrorHandler + { + bool HasError { get; } + Exception Error { get; } + bool IsReThrowOnError { get; } + void ForceDisableRethrowOnError(); + void ForceEnableRethrowOnError(); + } + + public class ObservableYieldInstruction : IEnumerator, ICustomYieldInstructionErrorHandler + { + readonly IDisposable subscription; + readonly CancellationToken cancel; + bool reThrowOnError; + T current; + T result; + bool moveNext; + bool hasResult; + Exception error; + + public ObservableYieldInstruction(IObservable source, bool reThrowOnError, CancellationToken cancel) + { + this.moveNext = true; + this.reThrowOnError = reThrowOnError; + this.cancel = cancel; + try + { + this.subscription = source.Subscribe(new ToYieldInstruction(this)); + } + catch + { + moveNext = false; + throw; + } + } + + public bool HasError + { + get { return error != null; } + } + + public bool HasResult + { + get { return hasResult; } + } + + public bool IsCanceled + { + get + { + if (hasResult) return false; + if (error != null) return false; + return cancel.IsCancellationRequested; + } + } + + /// + /// HasResult || IsCanceled || HasError + /// + public bool IsDone + { + get + { + return HasResult || HasError || (cancel.IsCancellationRequested); + } + } + + public T Result + { + get { return result; } + } + + T IEnumerator.Current + { + get + { + return current; + } + } + + object IEnumerator.Current + { + get + { + return current; + } + } + + public Exception Error + { + get + { + return error; + } + } + + bool IEnumerator.MoveNext() + { + if (!moveNext) + { + if (reThrowOnError && HasError) + { + Error.Throw(); + } + + return false; + } + + if (cancel.IsCancellationRequested) + { + subscription.Dispose(); + return false; + } + + return true; + } + + bool ICustomYieldInstructionErrorHandler.IsReThrowOnError + { + get { return reThrowOnError; } + } + + void ICustomYieldInstructionErrorHandler.ForceDisableRethrowOnError() + { + this.reThrowOnError = false; + } + + void ICustomYieldInstructionErrorHandler.ForceEnableRethrowOnError() + { + this.reThrowOnError = true; + } + + public void Dispose() + { + subscription.Dispose(); + } + + void IEnumerator.Reset() + { + throw new NotSupportedException(); + } + + class ToYieldInstruction : IObserver + { + readonly ObservableYieldInstruction parent; + + public ToYieldInstruction(ObservableYieldInstruction parent) + { + this.parent = parent; + } + + public void OnNext(T value) + { + parent.current = value; + } + + public void OnError(Exception error) + { + parent.moveNext = false; + parent.error = error; + } + + public void OnCompleted() + { + parent.moveNext = false; + parent.hasResult = true; + parent.result = parent.current; + } + } + } + +#if UniRxLibrary + public static partial class ObservableUnity +#else + public static partial class Observable +#endif + { + readonly static HashSet YieldInstructionTypes = new HashSet + { + #if UNITY_2018_3_OR_NEWER +#pragma warning disable CS0618 +#endif + typeof(WWW), + #if UNITY_2018_3_OR_NEWER +#pragma warning restore CS0618 +#endif + typeof(WaitForEndOfFrame), + typeof(WaitForFixedUpdate), + typeof(WaitForSeconds), + typeof(AsyncOperation), + typeof(Coroutine) + }; + +#if SupportCustomYieldInstruction + + class EveryAfterUpdateInvoker : IEnumerator + { + long count = -1; + readonly IObserver observer; + readonly CancellationToken cancellationToken; + + public EveryAfterUpdateInvoker(IObserver observer, CancellationToken cancellationToken) + { + this.observer = observer; + this.cancellationToken = cancellationToken; + } + + public bool MoveNext() + { + if (!cancellationToken.IsCancellationRequested) + { + if (count != -1) // ignore first/immediate invoke + { + observer.OnNext(count++); + } + else + { + count++; + } + return true; + } + else + { + return false; + } + } + + public object Current + { + get + { + return null; + } + } + + public void Reset() + { + throw new NotSupportedException(); + } + } + +#endif + + + + /// From has no callback coroutine to IObservable. If publishEveryYield = true then publish OnNext every yield return else return once on enumeration completed. + public static IObservable FromCoroutine(Func coroutine, bool publishEveryYield = false) + { + return FromCoroutine((observer, cancellationToken) => WrapEnumerator(coroutine(), observer, cancellationToken, publishEveryYield)); + } + + /// From has no callback coroutine to IObservable. If publishEveryYield = true then publish OnNext every yield return else return once on enumeration completed. + public static IObservable FromCoroutine(Func coroutine, bool publishEveryYield = false) + { + return FromCoroutine((observer, cancellationToken) => WrapEnumerator(coroutine(cancellationToken), observer, cancellationToken, publishEveryYield)); + } + + /// + /// MicroCoroutine is lightweight, fast coroutine dispatcher. + /// IEnumerator supports only yield return null. + /// If publishEveryYield = true then publish OnNext every yield return else return once on enumeration completed. + /// + public static IObservable FromMicroCoroutine(Func coroutine, bool publishEveryYield = false, FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellationToken) => WrapEnumerator(coroutine(), observer, cancellationToken, publishEveryYield), frameCountType); + } + + /// + /// MicroCoroutine is lightweight, fast coroutine dispatcher. + /// IEnumerator supports only yield return null. + /// If publishEveryYield = true then publish OnNext every yield return else return once on enumeration completed. + /// + public static IObservable FromMicroCoroutine(Func coroutine, bool publishEveryYield = false, FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellationToken) => WrapEnumerator(coroutine(cancellationToken), observer, cancellationToken, publishEveryYield), frameCountType); + } + + static IEnumerator WrapEnumerator(IEnumerator enumerator, IObserver observer, CancellationToken cancellationToken, bool publishEveryYield) + { + var hasNext = default(bool); + var raisedError = false; + do + { + try + { + hasNext = enumerator.MoveNext(); + } + catch (Exception ex) + { + try + { + raisedError = true; + observer.OnError(ex); + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + yield break; + } + if (hasNext && publishEveryYield) + { + try + { + observer.OnNext(Unit.Default); + } + catch + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + throw; + } + } + if (hasNext) + { +#if SupportCustomYieldInstruction + var current = enumerator.Current; + var customHandler = current as ICustomYieldInstructionErrorHandler; + if (customHandler != null && customHandler.IsReThrowOnError) + { + // If throws exception in Custom YieldInsrtuction, can't handle parent coroutine. + // It is C# limitation. + // so store error info and retrieve from parent. + customHandler.ForceDisableRethrowOnError(); + yield return current; + customHandler.ForceEnableRethrowOnError(); + + if (customHandler.HasError) + { + try + { + raisedError = true; + observer.OnError(customHandler.Error); + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + yield break; + } + } + else + { + yield return enumerator.Current; // yield inner YieldInstruction + } +#else + yield return enumerator.Current; // yield inner YieldInstruction +#endif + } + } while (hasNext && !cancellationToken.IsCancellationRequested); + + try + { + if (!raisedError && !cancellationToken.IsCancellationRequested) + { + observer.OnNext(Unit.Default); // last one + observer.OnCompleted(); + } + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + } + + /// Convert coroutine to typed IObservable. If nullAsNextUpdate = true then yield return null when Enumerator.Current and no null publish observer.OnNext. + public static IObservable FromCoroutineValue(Func coroutine, bool nullAsNextUpdate = true) + { + return FromCoroutine((observer, cancellationToken) => WrapEnumeratorYieldValue(coroutine(), observer, cancellationToken, nullAsNextUpdate)); + } + + /// Convert coroutine to typed IObservable. If nullAsNextUpdate = true then yield return null when Enumerator.Current and no null publish observer.OnNext. + public static IObservable FromCoroutineValue(Func coroutine, bool nullAsNextUpdate = true) + { + return FromCoroutine((observer, cancellationToken) => WrapEnumeratorYieldValue(coroutine(cancellationToken), observer, cancellationToken, nullAsNextUpdate)); + } + + static IEnumerator WrapEnumeratorYieldValue(IEnumerator enumerator, IObserver observer, CancellationToken cancellationToken, bool nullAsNextUpdate) + { + var hasNext = default(bool); + var current = default(object); + var raisedError = false; + do + { + try + { + hasNext = enumerator.MoveNext(); + if (hasNext) current = enumerator.Current; + } + catch (Exception ex) + { + try + { + raisedError = true; + observer.OnError(ex); + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + yield break; + } + + if (hasNext) + { + if (current != null && YieldInstructionTypes.Contains(current.GetType())) + { + yield return current; + } +#if SupportCustomYieldInstruction + else if (current is IEnumerator) + { + var customHandler = current as ICustomYieldInstructionErrorHandler; + if (customHandler != null && customHandler.IsReThrowOnError) + { + // If throws exception in Custom YieldInsrtuction, can't handle parent coroutine. + // It is C# limitation. + // so store error info and retrieve from parent. + customHandler.ForceDisableRethrowOnError(); + yield return current; + customHandler.ForceEnableRethrowOnError(); + + if (customHandler.HasError) + { + try + { + raisedError = true; + observer.OnError(customHandler.Error); + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + yield break; + } + } + else + { + yield return current; + } + } +#endif + else if (current == null && nullAsNextUpdate) + { + yield return null; + } + else + { + try + { + observer.OnNext((T)current); + } + catch + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + throw; + } + } + } + } while (hasNext && !cancellationToken.IsCancellationRequested); + + try + { + if (!raisedError && !cancellationToken.IsCancellationRequested) + { + observer.OnCompleted(); + } + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + } + + public static IObservable FromCoroutine(Func, IEnumerator> coroutine) + { + return FromCoroutine((observer, cancellationToken) => WrapToCancellableEnumerator(coroutine(observer), observer, cancellationToken)); + } + + /// + /// MicroCoroutine is lightweight, fast coroutine dispatcher. + /// IEnumerator supports only yield return null. + /// + public static IObservable FromMicroCoroutine(Func, IEnumerator> coroutine, FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellationToken) => WrapToCancellableEnumerator(coroutine(observer), observer, cancellationToken), frameCountType); + } + + static IEnumerator WrapToCancellableEnumerator(IEnumerator enumerator, IObserver observer, CancellationToken cancellationToken) + { + var hasNext = default(bool); + do + { + try + { + hasNext = enumerator.MoveNext(); + } + catch (Exception ex) + { + try + { + observer.OnError(ex); + } + finally + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + yield break; + } + + yield return enumerator.Current; // yield inner YieldInstruction + } while (hasNext && !cancellationToken.IsCancellationRequested); + + { + var d = enumerator as IDisposable; + if (d != null) + { + d.Dispose(); + } + } + } + + public static IObservable FromCoroutine(Func, CancellationToken, IEnumerator> coroutine) + { + return new UniRx.Operators.FromCoroutineObservable(coroutine); + } + + /// + /// MicroCoroutine is lightweight, fast coroutine dispatcher. + /// IEnumerator supports only yield return null. + /// + public static IObservable FromMicroCoroutine(Func, CancellationToken, IEnumerator> coroutine, FrameCountType frameCountType = FrameCountType.Update) + { + return new UniRx.Operators.FromMicroCoroutineObservable(coroutine, frameCountType); + } + + public static IObservable SelectMany(this IObservable source, IEnumerator coroutine, bool publishEveryYield = false) + { + return source.SelectMany(FromCoroutine(() => coroutine, publishEveryYield)); + } + + public static IObservable SelectMany(this IObservable source, Func selector, bool publishEveryYield = false) + { + return source.SelectMany(FromCoroutine(() => selector(), publishEveryYield)); + } + + /// + /// Note: publishEveryYield is always false. If you want to set true, use Observable.FromCoroutine(() => selector(x), true). This is workaround of Unity compiler's bug. + /// + public static IObservable SelectMany(this IObservable source, Func selector) + { + return source.SelectMany(x => FromCoroutine(() => selector(x), false)); + } + + public static IObservable ToObservable(this IEnumerator coroutine, bool publishEveryYield = false) + { + return FromCoroutine((observer, cancellationToken) => WrapEnumerator(coroutine, observer, cancellationToken, publishEveryYield)); + } + +#if SupportCustomYieldInstruction + + public static ObservableYieldInstruction ToYieldInstruction(this IEnumerator coroutine) + { + return ToObservable(coroutine, false).ToYieldInstruction(); + } + + public static ObservableYieldInstruction ToYieldInstruction(this IEnumerator coroutine, bool throwOnError) + { + return ToObservable(coroutine, false).ToYieldInstruction(throwOnError); + } + + public static ObservableYieldInstruction ToYieldInstruction(this IEnumerator coroutine, CancellationToken cancellationToken) + { + return ToObservable(coroutine, false).ToYieldInstruction(cancellationToken); + } + + public static ObservableYieldInstruction ToYieldInstruction(this IEnumerator coroutine, bool throwOnError, CancellationToken cancellationToken) + { + return ToObservable(coroutine, false).ToYieldInstruction(throwOnError, cancellationToken); + } + +#endif + + // variation of FromCoroutine + + /// + /// EveryUpdate calls coroutine's yield return null timing. It is after all Update and before LateUpdate. + /// + public static IObservable EveryUpdate() + { + return FromMicroCoroutine((observer, cancellationToken) => EveryCycleCore(observer, cancellationToken), FrameCountType.Update); + } + + public static IObservable EveryFixedUpdate() + { + return FromMicroCoroutine((observer, cancellationToken) => EveryCycleCore(observer, cancellationToken), FrameCountType.FixedUpdate); + } + + public static IObservable EveryEndOfFrame() + { + return FromMicroCoroutine((observer, cancellationToken) => EveryCycleCore(observer, cancellationToken), FrameCountType.EndOfFrame); + } + + static IEnumerator EveryCycleCore(IObserver observer, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) yield break; + var count = 0L; + while (true) + { + yield return null; + if (cancellationToken.IsCancellationRequested) yield break; + + observer.OnNext(count++); + } + } + + /// + /// EveryGameObjectUpdate calls from MainThreadDispatcher's Update. + /// + public static IObservable EveryGameObjectUpdate() + { + return MainThreadDispatcher.UpdateAsObservable().Scan(-1L, (x, y) => x + 1); + } + + /// + /// EveryLateUpdate calls from MainThreadDispatcher's OnLateUpdate. + /// + public static IObservable EveryLateUpdate() + { + return MainThreadDispatcher.LateUpdateAsObservable().Scan(-1L, (x, y) => x + 1); + } + +#if SupportCustomYieldInstruction + + /// + /// [Obsolete]Same as EveryUpdate. + /// + [Obsolete] + public static IObservable EveryAfterUpdate() + { + return FromCoroutine((observer, cancellationToken) => new EveryAfterUpdateInvoker(observer, cancellationToken)); + } + +#endif + + #region Observable.Time Frame Extensions + + // Interval, Timer, Delay, Sample, Throttle, Timeout + + public static IObservable NextFrame(FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellation) => NextFrameCore(observer, cancellation), frameCountType); + } + + static IEnumerator NextFrameCore(IObserver observer, CancellationToken cancellation) + { + yield return null; + + if (!cancellation.IsCancellationRequested) + { + observer.OnNext(Unit.Default); + observer.OnCompleted(); + } + } + + public static IObservable IntervalFrame(int intervalFrameCount, FrameCountType frameCountType = FrameCountType.Update) + { + return TimerFrame(intervalFrameCount, intervalFrameCount, frameCountType); + } + + public static IObservable TimerFrame(int dueTimeFrameCount, FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellation) => TimerFrameCore(observer, dueTimeFrameCount, cancellation), frameCountType); + } + + public static IObservable TimerFrame(int dueTimeFrameCount, int periodFrameCount, FrameCountType frameCountType = FrameCountType.Update) + { + return FromMicroCoroutine((observer, cancellation) => TimerFrameCore(observer, dueTimeFrameCount, periodFrameCount, cancellation), frameCountType); + } + + static IEnumerator TimerFrameCore(IObserver observer, int dueTimeFrameCount, CancellationToken cancel) + { + // normalize + if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0; + + var currentFrame = 0; + + // initial phase + while (!cancel.IsCancellationRequested) + { + if (currentFrame++ == dueTimeFrameCount) + { + observer.OnNext(0); + observer.OnCompleted(); + break; + } + yield return null; + } + } + + static IEnumerator TimerFrameCore(IObserver observer, int dueTimeFrameCount, int periodFrameCount, CancellationToken cancel) + { + // normalize + if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0; + if (periodFrameCount <= 0) periodFrameCount = 1; + + var sendCount = 0L; + var currentFrame = 0; + + // initial phase + while (!cancel.IsCancellationRequested) + { + if (currentFrame++ == dueTimeFrameCount) + { + observer.OnNext(sendCount++); + currentFrame = -1; + break; + } + yield return null; + } + + // period phase + while (!cancel.IsCancellationRequested) + { + if (++currentFrame == periodFrameCount) + { + observer.OnNext(sendCount++); + currentFrame = 0; + } + yield return null; + } + } + + public static IObservable DelayFrame(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.DelayFrameObservable(source, frameCount, frameCountType); + } + + public static IObservable Sample(this IObservable source, IObservable sampler) + { + return new UniRx.Operators.SampleObservable(source, sampler); + } + + public static IObservable SampleFrame(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.SampleFrameObservable(source, frameCount, frameCountType); + } + + public static IObservable ThrottleFrame(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.ThrottleFrameObservable(source, frameCount, frameCountType); + } + + public static IObservable ThrottleFirstFrame(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.ThrottleFirstFrameObservable(source, frameCount, frameCountType); + } + + public static IObservable TimeoutFrame(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.TimeoutFrameObservable(source, frameCount, frameCountType); + } + + public static IObservable DelayFrameSubscription(this IObservable source, int frameCount, FrameCountType frameCountType = FrameCountType.Update) + { + if (frameCount < 0) throw new ArgumentOutOfRangeException("frameCount"); + return new UniRx.Operators.DelayFrameSubscriptionObservable(source, frameCount, frameCountType); + } + + #endregion + +#if SupportCustomYieldInstruction + + /// + /// Convert to yieldable IEnumerator. e.g. yield return source.ToYieldInstruction();. + /// If needs last result, you can take ObservableYieldInstruction.HasResult/Result property. + /// This overload throws exception if received OnError events(same as coroutine). + /// + public static ObservableYieldInstruction ToYieldInstruction(this IObservable source) + { + return new ObservableYieldInstruction(source, true, CancellationToken.None); + } + + /// + /// Convert to yieldable IEnumerator. e.g. yield return source.ToYieldInstruction();. + /// If needs last result, you can take ObservableYieldInstruction.HasResult/Result property. + /// This overload throws exception if received OnError events(same as coroutine). + /// + public static ObservableYieldInstruction ToYieldInstruction(this IObservable source, CancellationToken cancel) + { + return new ObservableYieldInstruction(source, true, cancel); + } + + /// + /// Convert to yieldable IEnumerator. e.g. yield return source.ToYieldInstruction();. + /// If needs last result, you can take ObservableYieldInstruction.HasResult/Result property. + /// If throwOnError = false, you can take ObservableYieldInstruction.HasError/Error property. + /// + public static ObservableYieldInstruction ToYieldInstruction(this IObservable source, bool throwOnError) + { + return new ObservableYieldInstruction(source, throwOnError, CancellationToken.None); + } + + /// + /// Convert to yieldable IEnumerator. e.g. yield return source.ToYieldInstruction();. + /// If needs last result, you can take ObservableYieldInstruction.HasResult/Result property. + /// If throwOnError = false, you can take ObservableYieldInstruction.HasError/Error property. + /// + public static ObservableYieldInstruction ToYieldInstruction(this IObservable source, bool throwOnError, CancellationToken cancel) + { + return new ObservableYieldInstruction(source, throwOnError, cancel); + } + +#endif + + /// Convert to awaitable IEnumerator. + public static IEnumerator ToAwaitableEnumerator(this IObservable source, CancellationToken cancel = default(CancellationToken)) + { + return ToAwaitableEnumerator(source, Stubs.Ignore, Stubs.Throw, cancel); + } + + /// Convert to awaitable IEnumerator. + public static IEnumerator ToAwaitableEnumerator(this IObservable source, Action onResult, CancellationToken cancel = default(CancellationToken)) + { + return ToAwaitableEnumerator(source, onResult, Stubs.Throw, cancel); + } + + /// Convert to awaitable IEnumerator. + public static IEnumerator ToAwaitableEnumerator(this IObservable source, Action onError, CancellationToken cancel = default(CancellationToken)) + { + return ToAwaitableEnumerator(source, Stubs.Ignore, onError, cancel); + } + + /// Convert to awaitable IEnumerator. + public static IEnumerator ToAwaitableEnumerator(this IObservable source, Action onResult, Action onError, CancellationToken cancel = default(CancellationToken)) + { + var enumerator = new ObservableYieldInstruction(source, false, cancel); + var e = (IEnumerator)enumerator; + while (e.MoveNext() && !cancel.IsCancellationRequested) + { + yield return null; + } + + if (cancel.IsCancellationRequested) + { + enumerator.Dispose(); + yield break; + } + + if (enumerator.HasResult) + { + onResult(enumerator.Result); + } + else if (enumerator.HasError) + { + onError(enumerator.Error); + } + } + + /// AutoStart observable as coroutine. + public static Coroutine StartAsCoroutine(this IObservable source, CancellationToken cancel = default(CancellationToken)) + { + return StartAsCoroutine(source, Stubs.Ignore, Stubs.Throw, cancel); + } + + /// AutoStart observable as coroutine. + public static Coroutine StartAsCoroutine(this IObservable source, Action onResult, CancellationToken cancel = default(CancellationToken)) + { + return StartAsCoroutine(source, onResult, Stubs.Throw, cancel); + } + + /// AutoStart observable as coroutine. + public static Coroutine StartAsCoroutine(this IObservable source, Action onError, CancellationToken cancel = default(CancellationToken)) + { + return StartAsCoroutine(source, Stubs.Ignore, onError, cancel); + } + + /// AutoStart observable as coroutine. + public static Coroutine StartAsCoroutine(this IObservable source, Action onResult, Action onError, CancellationToken cancel = default(CancellationToken)) + { + return MainThreadDispatcher.StartCoroutine(source.ToAwaitableEnumerator(onResult, onError, cancel)); + } + + public static IObservable ObserveOnMainThread(this IObservable source) + { + return source.ObserveOn(SchedulerUnity.MainThread); + } + + public static IObservable ObserveOnMainThread(this IObservable source, MainThreadDispatchType dispatchType) + { + switch (dispatchType) + { + case MainThreadDispatchType.Update: + return source.ObserveOnMainThread(); // faster path + + // others, bit slower + + case MainThreadDispatchType.FixedUpdate: + return source.SelectMany(_ => EveryFixedUpdate().Take(1), (x, _) => x); + case MainThreadDispatchType.EndOfFrame: + return source.SelectMany(_ => EveryEndOfFrame().Take(1), (x, _) => x); + case MainThreadDispatchType.GameObjectUpdate: + return source.SelectMany(_ => MainThreadDispatcher.UpdateAsObservable().Take(1), (x, _) => x); + case MainThreadDispatchType.LateUpdate: + return source.SelectMany(_ => MainThreadDispatcher.LateUpdateAsObservable().Take(1), (x, _) => x); + default: + throw new ArgumentException("type is invalid"); + } + } + + public static IObservable SubscribeOnMainThread(this IObservable source) + { + return source.SubscribeOn(SchedulerUnity.MainThread); + } + + // I can't avoid Unity 5.3's uNET weaver bug, pending... + + //public static IObservable SubscribeOnMainThread(this IObservable source, MainThreadDispatchType dispatchType) + //{ + // switch (dispatchType) + // { + // case MainThreadDispatchType.Update: + // return source.SubscribeOnMainThread(); // faster path + + // // others, bit slower + + // case MainThreadDispatchType.FixedUpdate: + // return new UniRx.Operators.SubscribeOnMainThreadObservable(source, EveryFixedUpdate().Take(1)); + // case MainThreadDispatchType.EndOfFrame: + // return new UniRx.Operators.SubscribeOnMainThreadObservable(source, EveryEndOfFrame().Take(1)); + // case MainThreadDispatchType.GameObjectUpdate: + // return new UniRx.Operators.SubscribeOnMainThreadObservable(source, MainThreadDispatcher.UpdateAsObservable().Select(_ => 0L).Take(1)); + // case MainThreadDispatchType.LateUpdate: + // return new UniRx.Operators.SubscribeOnMainThreadObservable(source, MainThreadDispatcher.LateUpdateAsObservable().Select(_ => 0L).Take(1)); + // case MainThreadDispatchType.AfterUpdate: + // return new UniRx.Operators.SubscribeOnMainThreadObservable(source, EveryAfterUpdate().Take(1)); + // default: + // throw new ArgumentException("type is invalid"); + // } + //} + + public static IObservable EveryApplicationPause() + { + return MainThreadDispatcher.OnApplicationPauseAsObservable().AsObservable(); + } + + public static IObservable EveryApplicationFocus() + { + return MainThreadDispatcher.OnApplicationFocusAsObservable().AsObservable(); + } + + /// publish OnNext(Unit) and OnCompleted() on application quit. + public static IObservable OnceApplicationQuit() + { + return MainThreadDispatcher.OnApplicationQuitAsObservable().Take(1); + } + + public static IObservable TakeUntilDestroy(this IObservable source, Component target) + { + return source.TakeUntil(target.OnDestroyAsObservable()); + } + + public static IObservable TakeUntilDestroy(this IObservable source, GameObject target) + { + return source.TakeUntil(target.OnDestroyAsObservable()); + } + + public static IObservable TakeUntilDisable(this IObservable source, Component target) + { + return source.TakeUntil(target.OnDisableAsObservable()); + } + + public static IObservable TakeUntilDisable(this IObservable source, GameObject target) + { + return source.TakeUntil(target.OnDisableAsObservable()); + } + + public static IObservable RepeatUntilDestroy(this IObservable source, GameObject target) + { + return RepeatUntilCore(RepeatInfinite(source), target.OnDestroyAsObservable(), target); + } + + public static IObservable RepeatUntilDestroy(this IObservable source, Component target) + { + return RepeatUntilCore(RepeatInfinite(source), target.OnDestroyAsObservable(), (target != null) ? target.gameObject : null); + } + + public static IObservable RepeatUntilDisable(this IObservable source, GameObject target) + { + return RepeatUntilCore(RepeatInfinite(source), target.OnDisableAsObservable(), target); + } + + public static IObservable RepeatUntilDisable(this IObservable source, Component target) + { + return RepeatUntilCore(RepeatInfinite(source), target.OnDisableAsObservable(), (target != null) ? target.gameObject : null); + } + + static IObservable RepeatUntilCore(this IEnumerable> sources, IObservable trigger, GameObject lifeTimeChecker) + { + return new UniRx.Operators.RepeatUntilObservable(sources, trigger, lifeTimeChecker); + } + + public static IObservable> FrameInterval(this IObservable source) + { + return new UniRx.Operators.FrameIntervalObservable(source); + } + + public static IObservable> FrameTimeInterval(this IObservable source, bool ignoreTimeScale = false) + { + return new UniRx.Operators.FrameTimeIntervalObservable(source, ignoreTimeScale); + } + + /// + /// Buffer elements in during target frame counts. Default raise same frame of end(frameCount = 0, frameCountType = EndOfFrame). + /// + public static IObservable> BatchFrame(this IObservable source) + { + // if use default argument, comiler errors ambiguous(Unity's limitation) + return BatchFrame(source, 0, FrameCountType.EndOfFrame); + } + + /// + /// Buffer elements in during target frame counts. + /// + public static IObservable> BatchFrame(this IObservable source, int frameCount, FrameCountType frameCountType) + { + if (frameCount < 0) throw new ArgumentException("frameCount must be >= 0, frameCount:" + frameCount); + return new UniRx.Operators.BatchFrameObservable(source, frameCount, frameCountType); + } + + /// + /// Wait command in during target frame counts. Default raise same frame of end(frameCount = 0, frameCountType = EndOfFrame). + /// + public static IObservable BatchFrame(this IObservable source) + { + return BatchFrame(source, 0, FrameCountType.EndOfFrame); + } + + /// + /// Wait command in during target frame counts. + /// + public static IObservable BatchFrame(this IObservable source, int frameCount, FrameCountType frameCountType) + { + if (frameCount < 0) throw new ArgumentException("frameCount must be >= 0, frameCount:" + frameCount); + return new UniRx.Operators.BatchFrameObservable(source, frameCount, frameCountType); + } + +#if UniRxLibrary + + static IEnumerable> RepeatInfinite(IObservable source) + { + while (true) + { + yield return source; + } + } + + internal static class Stubs + { + public static readonly Action Nop = () => { }; + public static readonly Action Throw = ex => { ex.Throw(); }; + + // Stubs.Ignore can't avoid iOS AOT problem. + public static void Ignore(T t) + { + } + + // marker for CatchIgnore and Catch avoid iOS AOT problem. + public static IObservable CatchIgnore(Exception ex) + { + return Observable.Empty(); + } + } +#endif + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs.meta new file mode 100644 index 00000000..848c2c17 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Observable.Unity.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c6ef0a186b9ceaf41af7f2a9f4006216 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs new file mode 100644 index 00000000..820a6d6c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs @@ -0,0 +1,442 @@ +using System; +using System.Collections; +using UnityEngine; + +#if !UniRxLibrary +using ObservableUnity = UniRx.Observable; +#endif + +#if UNITY_2018_3_OR_NEWER +#pragma warning disable CS0618 +#endif + +namespace UniRx +{ + using System.Threading; +#if !(UNITY_METRO || UNITY_WP8) && (UNITY_4_4 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5 || UNITY_3_4 || UNITY_3_3 || UNITY_3_2 || UNITY_3_1 || UNITY_3_0_0 || UNITY_3_0 || UNITY_2_6_1 || UNITY_2_6) + // Fallback for Unity versions below 4.5 + using Hash = System.Collections.Hashtable; + using HashEntry = System.Collections.DictionaryEntry; +#else + // Unity 4.5 release notes: + // WWW: deprecated 'WWW(string url, byte[] postData, Hashtable headers)', + // use 'public WWW(string url, byte[] postData, Dictionary headers)' instead. + using Hash = System.Collections.Generic.Dictionary; + using HashEntry = System.Collections.Generic.KeyValuePair; +#endif + +#if UNITY_2018_3_OR_NEWER + [Obsolete("Use UnityWebRequest, a fully featured replacement which is more efficient and has additional features")] +#endif + public static partial class ObservableWWW + { + public static IObservable Get(string url, Hash headers = null, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation)); + } + + public static IObservable GetAndGetBytes(string url, Hash headers = null, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchBytes(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation)); + } + public static IObservable GetWWW(string url, Hash headers = null, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => Fetch(new WWW(url, null, (headers ?? new Hash())), observer, progress, cancellation)); + } + + public static IObservable Post(string url, byte[] postData, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, postData), observer, progress, cancellation)); + } + + public static IObservable Post(string url, byte[] postData, Hash headers, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, postData, headers), observer, progress, cancellation)); + } + + public static IObservable Post(string url, WWWForm content, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, content), observer, progress, cancellation)); + } + + public static IObservable Post(string url, WWWForm content, Hash headers, IProgress progress = null) + { + var contentHeaders = content.headers; + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchText(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation)); + } + + public static IObservable PostAndGetBytes(string url, byte[] postData, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchBytes(new WWW(url, postData), observer, progress, cancellation)); + } + + public static IObservable PostAndGetBytes(string url, byte[] postData, Hash headers, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchBytes(new WWW(url, postData, headers), observer, progress, cancellation)); + } + + public static IObservable PostAndGetBytes(string url, WWWForm content, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchBytes(new WWW(url, content), observer, progress, cancellation)); + } + + public static IObservable PostAndGetBytes(string url, WWWForm content, Hash headers, IProgress progress = null) + { + var contentHeaders = content.headers; + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchBytes(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation)); + } + + public static IObservable PostWWW(string url, byte[] postData, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => Fetch(new WWW(url, postData), observer, progress, cancellation)); + } + + public static IObservable PostWWW(string url, byte[] postData, Hash headers, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => Fetch(new WWW(url, postData, headers), observer, progress, cancellation)); + } + + public static IObservable PostWWW(string url, WWWForm content, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => Fetch(new WWW(url, content), observer, progress, cancellation)); + } + + public static IObservable PostWWW(string url, WWWForm content, Hash headers, IProgress progress = null) + { + var contentHeaders = content.headers; + return ObservableUnity.FromCoroutine((observer, cancellation) => Fetch(new WWW(url, content.data, MergeHash(contentHeaders, headers)), observer, progress, cancellation)); + } + + public static IObservable LoadFromCacheOrDownload(string url, int version, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, version), observer, progress, cancellation)); + } + + public static IObservable LoadFromCacheOrDownload(string url, int version, uint crc, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, version, crc), observer, progress, cancellation)); + } + + // over Unity5 supports Hash128 +#if !(UNITY_4_7 || UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5 || UNITY_3_4 || UNITY_3_3 || UNITY_3_2 || UNITY_3_1 || UNITY_3_0_0 || UNITY_3_0 || UNITY_2_6_1 || UNITY_2_6) + public static IObservable LoadFromCacheOrDownload(string url, Hash128 hash128, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, hash128), observer, progress, cancellation)); + } + + public static IObservable LoadFromCacheOrDownload(string url, Hash128 hash128, uint crc, IProgress progress = null) + { + return ObservableUnity.FromCoroutine((observer, cancellation) => FetchAssetBundle(WWW.LoadFromCacheOrDownload(url, hash128, crc), observer, progress, cancellation)); + } +#endif + + // over 4.5, Hash define is Dictionary. + // below Unity 4.5, WWW only supports Hashtable. + // Unity 4.5, 4.6 WWW supports Dictionary and [Obsolete]Hashtable but WWWForm.content is Hashtable. + // Unity 5.0 WWW only supports Dictionary and WWWForm.content is also Dictionary. +#if !(UNITY_METRO || UNITY_WP8) && (UNITY_4_5 || UNITY_4_6 || UNITY_4_7) + static Hash MergeHash(Hashtable wwwFormHeaders, Hash externalHeaders) + { + var newHeaders = new Hash(); + foreach (DictionaryEntry item in wwwFormHeaders) + { + newHeaders[item.Key.ToString()] = item.Value.ToString(); + } + foreach (HashEntry item in externalHeaders) + { + newHeaders[item.Key] = item.Value; + } + return newHeaders; + } +#else + static Hash MergeHash(Hash wwwFormHeaders, Hash externalHeaders) + { + foreach (HashEntry item in externalHeaders) + { + wwwFormHeaders[item.Key] = item.Value; + } + return wwwFormHeaders; + } +#endif + + static IEnumerator Fetch(WWW www, IObserver observer, IProgress reportProgress, CancellationToken cancel) + { + using (www) + { + if (reportProgress != null) + { + while (!www.isDone && !cancel.IsCancellationRequested) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + yield return null; + } + } + else + { + if (!www.isDone) + { + yield return www; + } + } + + if (cancel.IsCancellationRequested) + { + yield break; + } + + if (reportProgress != null) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + + if (!string.IsNullOrEmpty(www.error)) + { + observer.OnError(new WWWErrorException(www, www.text)); + } + else + { + observer.OnNext(www); + observer.OnCompleted(); + } + } + } + + static IEnumerator FetchText(WWW www, IObserver observer, IProgress reportProgress, CancellationToken cancel) + { + using (www) + { + if (reportProgress != null) + { + while (!www.isDone && !cancel.IsCancellationRequested) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + yield return null; + } + } + else + { + if (!www.isDone) + { + yield return www; + } + } + + if (cancel.IsCancellationRequested) + { + yield break; + } + + if (reportProgress != null) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + + if (!string.IsNullOrEmpty(www.error)) + { + observer.OnError(new WWWErrorException(www, www.text)); + } + else + { + observer.OnNext(www.text); + observer.OnCompleted(); + } + } + } + + static IEnumerator FetchBytes(WWW www, IObserver observer, IProgress reportProgress, CancellationToken cancel) + { + using (www) + { + if (reportProgress != null) + { + while (!www.isDone && !cancel.IsCancellationRequested) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + yield return null; + } + } + else + { + if (!www.isDone) + { + yield return www; + } + } + + if (cancel.IsCancellationRequested) + { + yield break; + } + + if (reportProgress != null) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + + if (!string.IsNullOrEmpty(www.error)) + { + observer.OnError(new WWWErrorException(www, www.text)); + } + else + { + observer.OnNext(www.bytes); + observer.OnCompleted(); + } + } + } + + static IEnumerator FetchAssetBundle(WWW www, IObserver observer, IProgress reportProgress, CancellationToken cancel) + { + using (www) + { + if (reportProgress != null) + { + while (!www.isDone && !cancel.IsCancellationRequested) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + yield return null; + } + } + else + { + if (!www.isDone) + { + yield return www; + } + } + + if (cancel.IsCancellationRequested) + { + yield break; + } + + if (reportProgress != null) + { + try + { + reportProgress.Report(www.progress); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + + if (!string.IsNullOrEmpty(www.error)) + { + observer.OnError(new WWWErrorException(www, "")); + } + else + { + observer.OnNext(www.assetBundle); + observer.OnCompleted(); + } + } + } + } + + public class WWWErrorException : Exception + { + public string RawErrorMessage { get; private set; } + public bool HasResponse { get; private set; } + public string Text { get; private set; } + public System.Net.HttpStatusCode StatusCode { get; private set; } + public System.Collections.Generic.Dictionary ResponseHeaders { get; private set; } + public WWW WWW { get; private set; } + + // cache the text because if www was disposed, can't access it. + public WWWErrorException(WWW www, string text) + { + this.WWW = www; + this.RawErrorMessage = www.error; + this.ResponseHeaders = www.responseHeaders; + this.HasResponse = false; + this.Text = text; + + var splitted = RawErrorMessage.Split(' ', ':'); + if (splitted.Length != 0) + { + int statusCode; + if (int.TryParse(splitted[0], out statusCode)) + { + this.HasResponse = true; + this.StatusCode = (System.Net.HttpStatusCode)statusCode; + } + } + } + + public override string ToString() + { + var text = this.Text; + if (string.IsNullOrEmpty(text)) + { + return RawErrorMessage; + } + else + { + return RawErrorMessage + " " + text; + } + } + } +} + +#if UNITY_2018_3_OR_NEWER +#pragma warning restore CS0618 +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs.meta new file mode 100644 index 00000000..85856c66 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObservableWWW.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ba71e5544e233dd4b83d4c5a6c696d05 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs new file mode 100644 index 00000000..eca17691 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using UniRx.InternalUtil; +using UniRx.Triggers; + +#if !UniRxLibrary +using ObservableUnity = UniRx.Observable; +#endif + +namespace UniRx +{ + public static partial class ObserveExtensions + { + /// + /// Publish target property when value is changed. If source is destroyed/destructed, publish OnCompleted. + /// + /// If true and target is UnityObject, use destroyed check by additional component. It is faster check for lifecycle but needs initial cost. + public static IObservable ObserveEveryValueChanged(this TSource source, Func propertySelector, FrameCountType frameCountType = FrameCountType.Update, bool fastDestroyCheck = false) + where TSource : class + { + return ObserveEveryValueChanged(source, propertySelector, frameCountType, UnityEqualityComparer.GetDefault(), fastDestroyCheck); + } + + /// + /// Publish target property when value is changed. If source is destroyed/destructed, publish OnCompleted. + /// + public static IObservable ObserveEveryValueChanged(this TSource source, Func propertySelector, FrameCountType frameCountType, IEqualityComparer comparer) + where TSource : class + { + return ObserveEveryValueChanged(source, propertySelector, frameCountType, comparer, false); + } + + /// + /// Publish target property when value is changed. If source is destroyed/destructed, publish OnCompleted. + /// + /// If true and target is UnityObject, use destroyed check by additional component. It is faster check for lifecycle but needs initial cost. + public static IObservable ObserveEveryValueChanged(this TSource source, Func propertySelector, FrameCountType frameCountType, IEqualityComparer comparer, bool fastDestroyCheck) + where TSource : class + { + if (source == null) return Observable.Empty(); + if (comparer == null) comparer = UnityEqualityComparer.GetDefault(); + + var unityObject = source as UnityEngine.Object; + var isUnityObject = source is UnityEngine.Object; + if (isUnityObject && unityObject == null) return Observable.Empty(); + + // MicroCoroutine does not publish value immediately, so publish value on subscribe. + if (isUnityObject) + { + return ObservableUnity.FromMicroCoroutine((observer, cancellationToken) => + { + if (unityObject != null) + { + var firstValue = default(TProperty); + try + { + firstValue = propertySelector((TSource)(object)unityObject); + } + catch (Exception ex) + { + observer.OnError(ex); + return EmptyEnumerator(); + } + + observer.OnNext(firstValue); + return PublishUnityObjectValueChanged(unityObject, firstValue, propertySelector, comparer, observer, cancellationToken, fastDestroyCheck); + } + else + { + observer.OnCompleted(); + return EmptyEnumerator(); + } + }, frameCountType); + } + else + { + var reference = new WeakReference(source); + source = null; + + return ObservableUnity.FromMicroCoroutine((observer, cancellationToken) => + { + var target = reference.Target; + if (target != null) + { + var firstValue = default(TProperty); + try + { + firstValue = propertySelector((TSource)target); + } + catch (Exception ex) + { + observer.OnError(ex); + return EmptyEnumerator(); + } + finally + { + target = null; + } + + observer.OnNext(firstValue); + return PublishPocoValueChanged(reference, firstValue, propertySelector, comparer, observer, cancellationToken); + } + else + { + observer.OnCompleted(); + return EmptyEnumerator(); + } + }, frameCountType); + } + } + + static IEnumerator EmptyEnumerator() + { + yield break; + } + + static IEnumerator PublishPocoValueChanged(WeakReference sourceReference, TProperty firstValue, Func propertySelector, IEqualityComparer comparer, IObserver observer, CancellationToken cancellationToken) + { + var currentValue = default(TProperty); + var prevValue = firstValue; + + while (!cancellationToken.IsCancellationRequested) + { + var target = sourceReference.Target; + if (target != null) + { + try + { + currentValue = propertySelector((TSource)target); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + finally + { + target = null; // remove reference(must need!) + } + } + else + { + observer.OnCompleted(); + yield break; + } + + if (!comparer.Equals(currentValue, prevValue)) + { + observer.OnNext(currentValue); + prevValue = currentValue; + } + + yield return null; + } + } + + static IEnumerator PublishUnityObjectValueChanged(UnityEngine.Object unityObject, TProperty firstValue, Func propertySelector, IEqualityComparer comparer, IObserver observer, CancellationToken cancellationToken, bool fastDestroyCheck) + { + var currentValue = default(TProperty); + var prevValue = firstValue; + + var source = (TSource)(object)unityObject; + + if (fastDestroyCheck) + { + ObservableDestroyTrigger destroyTrigger = null; + { + var gameObject = unityObject as UnityEngine.GameObject; + if (gameObject == null) + { + var comp = unityObject as UnityEngine.Component; + if (comp != null) + { + gameObject = comp.gameObject; + } + } + + // can't use faster path + if (gameObject == null) goto STANDARD_LOOP; + + destroyTrigger = GetOrAddDestroyTrigger(gameObject); + } + + // fast compare path + while (!cancellationToken.IsCancellationRequested) + { + var isDestroyed = destroyTrigger.IsActivated + ? !destroyTrigger.IsCalledOnDestroy + : (unityObject != null); + + if (isDestroyed) + { + try + { + currentValue = propertySelector(source); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + else + { + observer.OnCompleted(); + yield break; + } + + if (!comparer.Equals(currentValue, prevValue)) + { + observer.OnNext(currentValue); + prevValue = currentValue; + } + + yield return null; + } + + yield break; + } + + STANDARD_LOOP: + while (!cancellationToken.IsCancellationRequested) + { + if (unityObject != null) + { + try + { + currentValue = propertySelector(source); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + else + { + observer.OnCompleted(); + yield break; + } + + if (!comparer.Equals(currentValue, prevValue)) + { + observer.OnNext(currentValue); + prevValue = currentValue; + } + + yield return null; + } + } + + static ObservableDestroyTrigger GetOrAddDestroyTrigger(UnityEngine.GameObject go) + { + var dt = go.GetComponent(); + if (dt == null) + { + dt = go.AddComponent(); + } + return dt; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs.meta new file mode 100644 index 00000000..25ae7c41 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ObserveExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8741793924a6c2f4ea22ba27031d531f +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators.meta new file mode 100644 index 00000000..0377038e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4d126dc4a05228e418759d57f7661329 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs new file mode 100644 index 00000000..7d29dca9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class BatchFrameObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public BatchFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return new BatchFrame(this, observer, cancel).Run(); + } + + class BatchFrame : OperatorObserverBase> + { + readonly BatchFrameObservable parent; + readonly object gate = new object(); + readonly BooleanDisposable cancellationToken = new BooleanDisposable(); + readonly System.Collections.IEnumerator timer; + bool isRunning; + bool isCompleted; + List list; + + public BatchFrame(BatchFrameObservable parent, IObserver> observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.timer = new ReusableEnumerator(this); + } + + public IDisposable Run() + { + list = new List(); + var sourceSubscription = parent.source.Subscribe(this); + return StableCompositeDisposable.Create(sourceSubscription, cancellationToken); + } + + public override void OnNext(T value) + { + lock (gate) + { + if (isCompleted) return; + list.Add(value); + if (!isRunning) + { + isRunning = true; + timer.Reset(); // reuse + + switch (parent.frameCountType) + { + case FrameCountType.Update: + MainThreadDispatcher.StartUpdateMicroCoroutine(timer); + break; + case FrameCountType.FixedUpdate: + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(timer); + break; + case FrameCountType.EndOfFrame: + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(timer); + break; + default: + break; + } + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + List currentList; + lock (gate) + { + isCompleted = true; + currentList = list; + } + if (currentList.Count != 0) + { + observer.OnNext(currentList); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + + // reuse, no gc allocate + class ReusableEnumerator : System.Collections.IEnumerator + { + readonly BatchFrame parent; + int currentFrame; + + public ReusableEnumerator(BatchFrame parent) + { + this.parent = parent; + } + + public object Current + { + get { return null; } + } + + public bool MoveNext() + { + if (parent.cancellationToken.IsDisposed) return false; + + List currentList; + lock (parent.gate) + { + if (currentFrame++ == parent.parent.frameCount) + { + if (parent.isCompleted) return false; + + currentList = parent.list; + parent.list = new List(); + parent.isRunning = false; + + // exit lock + } + else + { + return true; + } + } + + parent.observer.OnNext(currentList); + return false; + } + + public void Reset() + { + currentFrame = 0; + } + } + } + } + + internal class BatchFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public BatchFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new BatchFrame(this, observer, cancel).Run(); + } + + class BatchFrame : OperatorObserverBase + { + readonly BatchFrameObservable parent; + readonly object gate = new object(); + readonly BooleanDisposable cancellationToken = new BooleanDisposable(); + readonly System.Collections.IEnumerator timer; + + bool isRunning; + bool isCompleted; + + public BatchFrame(BatchFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + this.timer = new ReusableEnumerator(this); + } + + public IDisposable Run() + { + var sourceSubscription = parent.source.Subscribe(this); + return StableCompositeDisposable.Create(sourceSubscription, cancellationToken); + } + + public override void OnNext(Unit value) + { + lock (gate) + { + if (!isRunning) + { + isRunning = true; + timer.Reset(); // reuse + + switch (parent.frameCountType) + { + case FrameCountType.Update: + MainThreadDispatcher.StartUpdateMicroCoroutine(timer); + break; + case FrameCountType.FixedUpdate: + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(timer); + break; + case FrameCountType.EndOfFrame: + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(timer); + break; + default: + break; + } + } + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + bool running; + lock (gate) + { + running = isRunning; + isCompleted = true; + } + if (running) + { + observer.OnNext(Unit.Default); + } + try { observer.OnCompleted(); } finally { Dispose(); } + } + + // reuse, no gc allocate + class ReusableEnumerator : System.Collections.IEnumerator + { + readonly BatchFrame parent; + int currentFrame; + + public ReusableEnumerator(BatchFrame parent) + { + this.parent = parent; + } + + public object Current + { + get { return null; } + } + + public bool MoveNext() + { + if (parent.cancellationToken.IsDisposed) return false; + + lock (parent.gate) + { + if (currentFrame++ == parent.parent.frameCount) + { + if (parent.isCompleted) return false; + parent.isRunning = false; + + // exit lock + } + else + { + return true; + } + } + + parent.observer.OnNext(Unit.Default); + return false; + } + + public void Reset() + { + currentFrame = 0; + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs.meta new file mode 100644 index 00000000..f691b543 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/BatchFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 74a2b6b8c63d1144f914c7f0d6719a36 +timeCreated: 1467771656 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs new file mode 100644 index 00000000..98ccac7e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UniRx.Operators +{ + internal class DelayFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public DelayFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new DelayFrame(this, observer, cancel).Run(); + } + + class DelayFrame : OperatorObserverBase + { + readonly DelayFrameObservable parent; + readonly object gate = new object(); + readonly QueuePool pool = new QueuePool(); + int runningEnumeratorCount; + bool readyDrainEnumerator; + bool running; + IDisposable sourceSubscription; + Queue currentQueueReference; + bool calledCompleted; + bool hasError; + Exception error; + BooleanDisposable cancelationToken; + + public DelayFrame(DelayFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + cancelationToken = new BooleanDisposable(); + + var _sourceSubscription = new SingleAssignmentDisposable(); + sourceSubscription = _sourceSubscription; + _sourceSubscription.Disposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(cancelationToken, sourceSubscription); + } + + IEnumerator DrainQueue(Queue q, int frameCount) + { + lock (gate) + { + readyDrainEnumerator = false; // use next queue. + running = false; + } + + while (!cancelationToken.IsDisposed && frameCount-- != 0) + { + yield return null; + } + + try + { + if (q != null) + { + while (q.Count > 0 && !hasError) + { + if (cancelationToken.IsDisposed) break; + + lock (gate) + { + running = true; + } + + var value = q.Dequeue(); + observer.OnNext(value); + + lock (gate) + { + running = false; + } + } + + if (q.Count == 0) + { + pool.Return(q); + } + } + + if (hasError) + { + if (!cancelationToken.IsDisposed) + { + cancelationToken.Dispose(); + + try { observer.OnError(error); } finally { Dispose(); } + } + } + else if (calledCompleted) + { + lock (gate) + { + // not self only + if (runningEnumeratorCount != 1) yield break; + } + + if (!cancelationToken.IsDisposed) + { + cancelationToken.Dispose(); + + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + finally + { + lock (gate) + { + runningEnumeratorCount--; + } + } + } + + public override void OnNext(T value) + { + if (cancelationToken.IsDisposed) return; + + Queue targetQueue = null; + lock (gate) + { + if (!readyDrainEnumerator) + { + readyDrainEnumerator = true; + runningEnumeratorCount++; + targetQueue = currentQueueReference = pool.Get(); + targetQueue.Enqueue(value); + } + else + { + if (currentQueueReference != null) // null - if doesn't start OnNext and start OnCompleted + { + currentQueueReference.Enqueue(value); + } + return; + } + } + + switch (parent.frameCountType) + { + case FrameCountType.Update: + MainThreadDispatcher.StartUpdateMicroCoroutine(DrainQueue(targetQueue, parent.frameCount)); + break; + case FrameCountType.FixedUpdate: + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(DrainQueue(targetQueue, parent.frameCount)); + break; + case FrameCountType.EndOfFrame: + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(DrainQueue(targetQueue, parent.frameCount)); + break; + default: + throw new ArgumentException("Invalid FrameCountType:" + parent.frameCountType); + } + } + + public override void OnError(Exception error) + { + sourceSubscription.Dispose(); // stop subscription + + if (cancelationToken.IsDisposed) return; + + lock (gate) + { + if (running) + { + hasError = true; + this.error = error; + return; + } + } + + cancelationToken.Dispose(); + try { base.observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + sourceSubscription.Dispose(); // stop subscription + + if (cancelationToken.IsDisposed) return; + + lock (gate) + { + calledCompleted = true; + + if (!readyDrainEnumerator) + { + readyDrainEnumerator = true; + runningEnumeratorCount++; + } + else + { + return; + } + } + + switch (parent.frameCountType) + { + case FrameCountType.Update: + MainThreadDispatcher.StartUpdateMicroCoroutine(DrainQueue(null, parent.frameCount)); + break; + case FrameCountType.FixedUpdate: + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(DrainQueue(null, parent.frameCount)); + break; + case FrameCountType.EndOfFrame: + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(DrainQueue(null, parent.frameCount)); + break; + default: + throw new ArgumentException("Invalid FrameCountType:" + parent.frameCountType); + } + } + } + + class QueuePool + { + readonly object gate = new object(); + readonly Queue> pool = new Queue>(2); + + public Queue Get() + { + lock (gate) + { + if (pool.Count == 0) + { + return new Queue(2); + } + else + { + return pool.Dequeue(); + } + } + } + + public void Return(Queue q) + { + lock (gate) + { + pool.Enqueue(q); + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs.meta new file mode 100644 index 00000000..983d9adb --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 868f75a703f1a944a801ab9c9b4512aa +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs new file mode 100644 index 00000000..9ae1af00 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs @@ -0,0 +1,37 @@ +using System; + +#if UniRxLibrary +using UnityObservable = UniRx.ObservableUnity; +#else +using UnityObservable = UniRx.Observable; +#endif + +namespace UniRx.Operators +{ + internal class DelayFrameSubscriptionObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public DelayFrameSubscriptionObservable(IObservable source, int frameCount, FrameCountType frameCountType) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var d = new MultipleAssignmentDisposable(); + d.Disposable = UnityObservable.TimerFrame(frameCount, frameCountType) + .SubscribeWithState3(observer, d, source, (_, o, disp, s) => + { + disp.Disposable = s.Subscribe(o); + }); + + return d; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs.meta new file mode 100644 index 00000000..06860ea0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/DelayFrameSubscription.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ecfef95eedf36c2448944fb8932f682c +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs new file mode 100644 index 00000000..8e109a49 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs @@ -0,0 +1,52 @@ +using System; + +namespace UniRx.Operators +{ + internal class FrameIntervalObservable : OperatorObservableBase> + { + readonly IObservable source; + + public FrameIntervalObservable(IObservable source) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new FrameInterval(observer, cancel)); + } + + class FrameInterval : OperatorObserverBase> + { + int lastFrame; + + public FrameInterval(IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.lastFrame = UnityEngine.Time.frameCount; + } + + public override void OnNext(T value) + { + var now = UnityEngine.Time.frameCount; + var span = now - lastFrame; + lastFrame = now; + + base.observer.OnNext(new UniRx.FrameInterval(value, span)); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs.meta new file mode 100644 index 00000000..46fd8ddd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameInterval.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a731a1a74be20a04a9d7dedc5ceefab2 +timeCreated: 1467771656 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs new file mode 100644 index 00000000..adaa1497 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs @@ -0,0 +1,60 @@ +using System; + +namespace UniRx.Operators +{ + internal class FrameTimeIntervalObservable : OperatorObservableBase> + { + readonly IObservable source; + readonly bool ignoreTimeScale; + + public FrameTimeIntervalObservable(IObservable source, bool ignoreTimeScale) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.ignoreTimeScale = ignoreTimeScale; + } + + protected override IDisposable SubscribeCore(IObserver> observer, IDisposable cancel) + { + return source.Subscribe(new FrameTimeInterval(this, observer, cancel)); + } + + class FrameTimeInterval : OperatorObserverBase> + { + readonly FrameTimeIntervalObservable parent; + float lastTime; + + public FrameTimeInterval(FrameTimeIntervalObservable parent, IObserver> observer, IDisposable cancel) + : base(observer, cancel) + { + this.parent = parent; + this.lastTime = (parent.ignoreTimeScale) + ? UnityEngine.Time.unscaledTime + : UnityEngine.Time.time; + } + + public override void OnNext(T value) + { + var now = (parent.ignoreTimeScale) + ? UnityEngine.Time.unscaledTime + : UnityEngine.Time.time; + var span = now - lastTime; + lastTime = now; + + base.observer.OnNext(new UniRx.TimeInterval(value, TimeSpan.FromSeconds(span))); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs.meta new file mode 100644 index 00000000..47ba2806 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FrameTimeInterval.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a55cce9ef638364409d1227a25a32421 +timeCreated: 1467771656 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs new file mode 100644 index 00000000..1f71fed3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using System.Threading; + +namespace UniRx.Operators +{ + internal class FromCoroutineObservable : OperatorObservableBase + { + readonly Func, CancellationToken, IEnumerator> coroutine; + + public FromCoroutineObservable(Func, CancellationToken, IEnumerator> coroutine) + : base(false) + { + this.coroutine = coroutine; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var fromCoroutineObserver = new FromCoroutine(observer, cancel); + +#if (NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + var moreCancel = new CancellationDisposable(); + var token = moreCancel.Token; +#else + var moreCancel = new BooleanDisposable(); + var token = new CancellationToken(moreCancel); +#endif + + MainThreadDispatcher.SendStartCoroutine(coroutine(fromCoroutineObserver, token)); + + return moreCancel; + } + + class FromCoroutine : OperatorObserverBase + { + public FromCoroutine(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + + internal class FromMicroCoroutineObservable : OperatorObservableBase + { + readonly Func, CancellationToken, IEnumerator> coroutine; + readonly FrameCountType frameCountType; + + public FromMicroCoroutineObservable(Func, CancellationToken, IEnumerator> coroutine, FrameCountType frameCountType) + : base(false) + { + this.coroutine = coroutine; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var microCoroutineObserver = new FromMicroCoroutine(observer, cancel); + +#if (NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0) + var moreCancel = new CancellationDisposable(); + var token = moreCancel.Token; +#else + var moreCancel = new BooleanDisposable(); + var token = new CancellationToken(moreCancel); +#endif + + switch (frameCountType) + { + case FrameCountType.Update: + MainThreadDispatcher.StartUpdateMicroCoroutine(coroutine(microCoroutineObserver, token)); + break; + case FrameCountType.FixedUpdate: + MainThreadDispatcher.StartFixedUpdateMicroCoroutine(coroutine(microCoroutineObserver, token)); + break; + case FrameCountType.EndOfFrame: + MainThreadDispatcher.StartEndOfFrameMicroCoroutine(coroutine(microCoroutineObserver, token)); + break; + default: + throw new ArgumentException("Invalid FrameCountType:" + frameCountType); + } + + return moreCancel; + } + + class FromMicroCoroutine : OperatorObserverBase + { + public FromMicroCoroutine(IObserver observer, IDisposable cancel) : base(observer, cancel) + { + } + + public override void OnNext(T value) + { + try + { + base.observer.OnNext(value); + } + catch + { + Dispose(); + throw; + } + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs.meta new file mode 100644 index 00000000..84c4dd58 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/FromCoroutine.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e83ddad992535fb4f8a68a1e7ef8be60 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs new file mode 100644 index 00000000..9039e79e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace UniRx.Operators +{ + internal class RepeatUntilObservable : OperatorObservableBase + { + readonly IEnumerable> sources; + readonly IObservable trigger; + readonly GameObject lifeTimeChecker; + + public RepeatUntilObservable(IEnumerable> sources, IObservable trigger, GameObject lifeTimeChecker) + : base(true) + { + this.sources = sources; + this.trigger = trigger; + this.lifeTimeChecker = lifeTimeChecker; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new RepeatUntil(this, observer, cancel).Run(); + } + + class RepeatUntil : OperatorObserverBase + { + readonly RepeatUntilObservable parent; + readonly object gate = new object(); + + IEnumerator> e; + SerialDisposable subscription; + SingleAssignmentDisposable schedule; + Action nextSelf; + bool isStopped; + bool isDisposed; + bool isFirstSubscribe; + IDisposable stopper; + + public RepeatUntil(RepeatUntilObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + isFirstSubscribe = true; + isDisposed = false; + isStopped = false; + e = parent.sources.GetEnumerator(); + subscription = new SerialDisposable(); + schedule = new SingleAssignmentDisposable(); + + stopper = parent.trigger.Subscribe(_ => + { + lock (gate) + { + isStopped = true; + e.Dispose(); + subscription.Dispose(); + schedule.Dispose(); + observer.OnCompleted(); + } + }, observer.OnError); + + schedule.Disposable = Scheduler.CurrentThread.Schedule(RecursiveRun); + + return new CompositeDisposable(schedule, subscription, stopper, Disposable.Create(() => + { + lock (gate) + { + isDisposed = true; + e.Dispose(); + } + })); + } + + void RecursiveRun(Action self) + { + lock (gate) + { + this.nextSelf = self; + if (isDisposed) return; + if (isStopped) return; + + var current = default(IObservable); + var hasNext = false; + var ex = default(Exception); + + try + { + hasNext = e.MoveNext(); + if (hasNext) + { + current = e.Current; + if (current == null) throw new InvalidOperationException("sequence is null."); + } + else + { + e.Dispose(); + } + } + catch (Exception exception) + { + ex = exception; + e.Dispose(); + } + + if (ex != null) + { + stopper.Dispose(); + observer.OnError(ex); + return; + } + + if (!hasNext) + { + stopper.Dispose(); + observer.OnCompleted(); + return; + } + + var source = e.Current; + var d = new SingleAssignmentDisposable(); + subscription.Disposable = d; + + if (isFirstSubscribe) + { + isFirstSubscribe = false; + d.Disposable = source.Subscribe(this); + } + else + { + MainThreadDispatcher.SendStartCoroutine(SubscribeAfterEndOfFrame(d, source, this, parent.lifeTimeChecker)); + } + } + } + + static IEnumerator SubscribeAfterEndOfFrame(SingleAssignmentDisposable d, IObservable source, IObserver observer, GameObject lifeTimeChecker) + { + yield return YieldInstructionCache.WaitForEndOfFrame; + if (!d.IsDisposed && lifeTimeChecker != null) + { + d.Disposable = source.Subscribe(observer); + } + } + + public override void OnNext(T value) + { + base.observer.OnNext(value); + } + + public override void OnError(Exception error) + { + try { observer.OnError(error); } + finally { Dispose(); } + } + + public override void OnCompleted() + { + if (!isDisposed) + { + this.nextSelf(); + } + else + { + e.Dispose(); + if (!isDisposed) + { + try { observer.OnCompleted(); } + finally { Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs.meta new file mode 100644 index 00000000..c292ba2c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/RepeatUntil.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 93507e8a72a71094f870c8dbe1e5bed8 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs new file mode 100644 index 00000000..4f0b4684 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs @@ -0,0 +1,132 @@ +using System; + +#if UniRxLibrary +using UnityObservable = UniRx.ObservableUnity; +#else +using UnityObservable = UniRx.Observable; +#endif + +namespace UniRx.Operators +{ + internal class SampleFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public SampleFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new SampleFrame(this, observer, cancel).Run(); + } + + class SampleFrame : OperatorObserverBase + { + readonly SampleFrameObservable parent; + readonly object gate = new object(); + T latestValue = default(T); + bool isUpdated = false; + bool isCompleted = false; + SingleAssignmentDisposable sourceSubscription; + + public SampleFrame(SampleFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + var scheduling = UnityObservable.IntervalFrame(parent.frameCount, parent.frameCountType) + .Subscribe(new SampleFrameTick(this)); + + return StableCompositeDisposable.Create(sourceSubscription, scheduling); + } + + void OnNextTick(long _) + { + lock (gate) + { + if (isUpdated) + { + var value = latestValue; + isUpdated = false; + observer.OnNext(value); + } + if (isCompleted) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + } + + public override void OnNext(T value) + { + lock (gate) + { + latestValue = value; + isUpdated = true; + } + } + + public override void OnError(Exception error) + { + lock (gate) + { + try { base.observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + lock (gate) + { + isCompleted = true; + sourceSubscription.Dispose(); + } + } + class SampleFrameTick : IObserver + { + readonly SampleFrame parent; + + public SampleFrameTick(SampleFrame parent) + { + this.parent = parent; + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(long _) + { + lock (parent.gate) + { + if (parent.isUpdated) + { + var value = parent.latestValue; + parent.isUpdated = false; + parent.observer.OnNext(value); + } + if (parent.isCompleted) + { + try { parent.observer.OnCompleted(); } finally { parent.Dispose(); } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs.meta new file mode 100644 index 00000000..60fd9ca0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SampleFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e04c7fc1929a3db458bf7ae31bcd9e55 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs new file mode 100644 index 00000000..56c27345 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs @@ -0,0 +1,31 @@ +using System; + +namespace UniRx.Operators +{ + internal class SubscribeOnMainThreadObservable : OperatorObservableBase + { + readonly IObservable source; + readonly IObservable subscribeTrigger; + + public SubscribeOnMainThreadObservable(IObservable source, IObservable subscribeTrigger) + : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.subscribeTrigger = subscribeTrigger; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + var m = new SingleAssignmentDisposable(); + var d = new SerialDisposable(); + d.Disposable = m; + + m.Disposable = subscribeTrigger.SubscribeWithState3(observer, d, source, (_, o, disp, s) => + { + disp.Disposable = s.Subscribe(o); + }); + + return d; + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs.meta new file mode 100644 index 00000000..d31958f4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/SubscribeOnMainThread.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: da3fd97518766ab43827991b7b5d4270 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs new file mode 100644 index 00000000..ef828dff --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs @@ -0,0 +1,123 @@ +using System; + +#if UniRxLibrary +using UnityObservable = UniRx.ObservableUnity; +#else +using UnityObservable = UniRx.Observable; +#endif + +namespace UniRx.Operators +{ + internal class ThrottleFirstFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public ThrottleFirstFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ThrottleFirstFrame(this, observer, cancel).Run(); + } + + class ThrottleFirstFrame : OperatorObserverBase + { + readonly ThrottleFirstFrameObservable parent; + readonly object gate = new object(); + bool open = true; + SerialDisposable cancelable; + + ThrottleFirstFrameTick tick; + + public ThrottleFirstFrame(ThrottleFirstFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + tick = new ThrottleFirstFrameTick(this); + cancelable = new SerialDisposable(); + + var subscription = parent.source.Subscribe(this); + return StableCompositeDisposable.Create(cancelable, subscription); + } + + void OnNext() + { + lock (gate) + { + open = true; + } + } + + public override void OnNext(T value) + { + lock (gate) + { + if (!open) return; + observer.OnNext(value); + open = false; + } + + var d = new SingleAssignmentDisposable(); + cancelable.Disposable = d; + d.Disposable = UnityObservable.TimerFrame(parent.frameCount, parent.frameCountType) + .Subscribe(tick); + } + + public override void OnError(Exception error) + { + cancelable.Dispose(); + + lock (gate) + { + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + cancelable.Dispose(); + + lock (gate) + { + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + // immutable, can share. + class ThrottleFirstFrameTick : IObserver + { + readonly ThrottleFirstFrame parent; + + public ThrottleFirstFrameTick(ThrottleFirstFrame parent) + { + this.parent = parent; + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(long _) + { + lock (parent.gate) + { + parent.open = true; + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs.meta new file mode 100644 index 00000000..7bf9f292 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFirstFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3ec92e777b0b4d949967b0663ce8bee8 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs new file mode 100644 index 00000000..ace4656e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs @@ -0,0 +1,129 @@ +using System; + +#if UniRxLibrary +using UnityObservable = UniRx.ObservableUnity; +#else +using UnityObservable = UniRx.Observable; +#endif + +namespace UniRx.Operators +{ + internal class ThrottleFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public ThrottleFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new ThrottleFrame(this, observer, cancel).Run(); + } + + class ThrottleFrame : OperatorObserverBase + { + readonly ThrottleFrameObservable parent; + readonly object gate = new object(); + T latestValue = default(T); + bool hasValue = false; + SerialDisposable cancelable; + ulong id = 0; + + public ThrottleFrame(ThrottleFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + cancelable = new SerialDisposable(); + var subscription = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(cancelable, subscription); + } + + public override void OnNext(T value) + { + ulong currentid; + lock (gate) + { + hasValue = true; + latestValue = value; + id = unchecked(id + 1); + currentid = id; + } + + var d = new SingleAssignmentDisposable(); + cancelable.Disposable = d; + d.Disposable = UnityObservable.TimerFrame(parent.frameCount, parent.frameCountType) + .Subscribe(new ThrottleFrameTick(this, currentid)); + } + + public override void OnError(Exception error) + { + cancelable.Dispose(); + + lock (gate) + { + hasValue = false; + id = unchecked(id + 1); + try { observer.OnError(error); } finally { Dispose(); } + } + } + + public override void OnCompleted() + { + cancelable.Dispose(); + + lock (gate) + { + if (hasValue) + { + observer.OnNext(latestValue); + } + hasValue = false; + id = unchecked(id + 1); + try { observer.OnCompleted(); } finally { Dispose(); } + } + } + + class ThrottleFrameTick : IObserver + { + readonly ThrottleFrame parent; + readonly ulong currentid; + + public ThrottleFrameTick(ThrottleFrame parent, ulong currentid) + { + this.parent = parent; + this.currentid = currentid; + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(long _) + { + lock (parent.gate) + { + if (parent.hasValue && parent.id == currentid) + { + parent.observer.OnNext(parent.latestValue); + } + parent.hasValue = false; + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs.meta new file mode 100644 index 00000000..5558a497 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/ThrottleFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2c4ef0bfcfe787543999c7a6cda03c07 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs new file mode 100644 index 00000000..1653eedd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs @@ -0,0 +1,142 @@ +using System; + +#if UniRxLibrary +using UnityObservable = UniRx.ObservableUnity; +#else +using UnityObservable = UniRx.Observable; +#endif + +namespace UniRx.Operators +{ + internal class TimeoutFrameObservable : OperatorObservableBase + { + readonly IObservable source; + readonly int frameCount; + readonly FrameCountType frameCountType; + + public TimeoutFrameObservable(IObservable source, int frameCount, FrameCountType frameCountType) : base(source.IsRequiredSubscribeOnCurrentThread()) + { + this.source = source; + this.frameCount = frameCount; + this.frameCountType = frameCountType; + } + + protected override IDisposable SubscribeCore(IObserver observer, IDisposable cancel) + { + return new TimeoutFrame(this, observer, cancel).Run(); + } + + class TimeoutFrame : OperatorObserverBase + { + readonly TimeoutFrameObservable parent; + readonly object gate = new object(); + ulong objectId = 0ul; + bool isTimeout = false; + SingleAssignmentDisposable sourceSubscription; + SerialDisposable timerSubscription; + + public TimeoutFrame(TimeoutFrameObservable parent, IObserver observer, IDisposable cancel) : base(observer, cancel) + { + this.parent = parent; + } + + public IDisposable Run() + { + sourceSubscription = new SingleAssignmentDisposable(); + timerSubscription = new SerialDisposable(); + timerSubscription.Disposable = RunTimer(objectId); + sourceSubscription.Disposable = parent.source.Subscribe(this); + + return StableCompositeDisposable.Create(timerSubscription, sourceSubscription); + } + + IDisposable RunTimer(ulong timerId) + { + return UnityObservable.TimerFrame(parent.frameCount, parent.frameCountType) + .Subscribe(new TimeoutFrameTick(this, timerId)); + } + + public override void OnNext(T value) + { + ulong useObjectId; + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + useObjectId = objectId; + } + if (timeout) return; + + timerSubscription.Disposable = Disposable.Empty; // cancel old timer + observer.OnNext(value); + timerSubscription.Disposable = RunTimer(useObjectId); + } + + public override void OnError(Exception error) + { + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + } + if (timeout) return; + + timerSubscription.Dispose(); + try { observer.OnError(error); } finally { Dispose(); } + } + + public override void OnCompleted() + { + bool timeout; + lock (gate) + { + timeout = isTimeout; + objectId++; + } + if (timeout) return; + + timerSubscription.Dispose(); + try { observer.OnCompleted(); } finally { Dispose(); } + } + + class TimeoutFrameTick : IObserver + { + readonly TimeoutFrame parent; + readonly ulong timerId; + + public TimeoutFrameTick(TimeoutFrame parent, ulong timerId) + { + this.parent = parent; + this.timerId = timerId; + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(long _) + { + + + lock (parent.gate) + { + if (parent.objectId == timerId) + { + parent.isTimeout = true; + } + } + if (parent.isTimeout) + { + try { parent.observer.OnError(new TimeoutException()); } finally { parent.Dispose(); } + } + } + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs.meta new file mode 100644 index 00000000..b6937062 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Operators/TimeoutFrame.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c27be0a585d78a944bccd31b86ee6722 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs new file mode 100644 index 00000000..cfe9a754 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace UniRx +{ + public struct CollectionAddEvent : IEquatable> + { + 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.Default.GetHashCode(Value) << 2; + } + + public bool Equals(CollectionAddEvent other) + { + return Index.Equals(other.Index) && EqualityComparer.Default.Equals(Value, other.Value); + } + } + + public struct CollectionRemoveEvent : IEquatable> + { + 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.Default.GetHashCode(Value) << 2; + } + + public bool Equals(CollectionRemoveEvent other) + { + return Index.Equals(other.Index) && EqualityComparer.Default.Equals(Value, other.Value); + } + } + + public struct CollectionMoveEvent : IEquatable> + { + 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.Default.GetHashCode(Value) >> 2; + } + + public bool Equals(CollectionMoveEvent other) + { + return OldIndex.Equals(other.OldIndex) && NewIndex.Equals(other.NewIndex) && EqualityComparer.Default.Equals(Value, other.Value); + } + } + + public struct CollectionReplaceEvent : IEquatable> + { + 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.Default.GetHashCode(OldValue) << 2 ^ EqualityComparer.Default.GetHashCode(NewValue) >> 2; + } + + public bool Equals(CollectionReplaceEvent other) + { + return Index.Equals(other.Index) + && EqualityComparer.Default.Equals(OldValue, other.OldValue) + && EqualityComparer.Default.Equals(NewValue, other.NewValue); + } + } + + // IReadOnlyList is from .NET 4.5 + public interface IReadOnlyReactiveCollection : IEnumerable + { + int Count { get; } + T this[int index] { get; } + IObservable> ObserveAdd(); + IObservable ObserveCountChanged(bool notifyCurrentCount = false); + IObservable> ObserveMove(); + IObservable> ObserveRemove(); + IObservable> ObserveReplace(); + IObservable ObserveReset(); + } + + public interface IReactiveCollection : IList, IReadOnlyReactiveCollection + { + new int Count { get; } + new T this[int index] { get; set; } + void Move(int oldIndex, int newIndex); + } + + [Serializable] + public class ReactiveCollection : Collection, IReactiveCollection, IDisposable + { + [NonSerialized] + bool isDisposed = false; + + public ReactiveCollection() + { + + } + + public ReactiveCollection(IEnumerable collection) + { + if (collection == null) throw new ArgumentNullException("collection"); + + foreach (var item in collection) + { + Add(item); + } + } + + public ReactiveCollection(List list) + : base(list != null ? new List(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(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(oldIndex, newIndex, item)); + } + + protected override void RemoveItem(int index) + { + T item = this[index]; + base.RemoveItem(index); + + if (collectionRemove != null) collectionRemove.OnNext(new CollectionRemoveEvent(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(index, oldItem, item)); + } + + + [NonSerialized] + Subject countChanged = null; + public IObservable ObserveCountChanged(bool notifyCurrentCount = false) + { + if (isDisposed) return Observable.Empty(); + + var subject = countChanged ?? (countChanged = new Subject()); + if (notifyCurrentCount) + { + return subject.StartWith(() => this.Count); + } + else + { + return subject; + } + } + + [NonSerialized] + Subject collectionReset = null; + public IObservable ObserveReset() + { + if (isDisposed) return Observable.Empty(); + return collectionReset ?? (collectionReset = new Subject()); + } + + [NonSerialized] + Subject> collectionAdd = null; + public IObservable> ObserveAdd() + { + if (isDisposed) return Observable.Empty>(); + return collectionAdd ?? (collectionAdd = new Subject>()); + } + + [NonSerialized] + Subject> collectionMove = null; + public IObservable> ObserveMove() + { + if (isDisposed) return Observable.Empty>(); + return collectionMove ?? (collectionMove = new Subject>()); + } + + [NonSerialized] + Subject> collectionRemove = null; + public IObservable> ObserveRemove() + { + if (isDisposed) return Observable.Empty>(); + return collectionRemove ?? (collectionRemove = new Subject>()); + } + + [NonSerialized] + Subject> collectionReplace = null; + public IObservable> ObserveReplace() + { + if (isDisposed) return Observable.Empty>(); + return collectionReplace ?? (collectionReplace = new Subject>()); + } + + void DisposeSubject(ref Subject 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 ToReactiveCollection(this IEnumerable source) + { + return new ReactiveCollection(source); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs.meta new file mode 100644 index 00000000..deec8ae0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCollection.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2e22185fb1dbcef42bc613efd4769011 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs new file mode 100644 index 00000000..0b65cc85 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs @@ -0,0 +1,487 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +using System.Threading.Tasks; +using UniRx.InternalUtil; +#endif +namespace UniRx +{ + public interface IReactiveCommand : IObservable + { + IReadOnlyReactiveProperty CanExecute { get; } + bool Execute(T parameter); + } + + public interface IAsyncReactiveCommand + { + IReadOnlyReactiveProperty CanExecute { get; } + IDisposable Execute(T parameter); + IDisposable Subscribe(Func> asyncAction); + } + + /// + /// Represents ReactiveCommand<Unit> + /// + public class ReactiveCommand : ReactiveCommand + { + /// + /// CanExecute is always true. + /// + public ReactiveCommand() + : base() + { } + + /// + /// CanExecute is changed from canExecute sequence. + /// + public ReactiveCommand(IObservable canExecuteSource, bool initialValue = true) + : base(canExecuteSource, initialValue) + { + } + + /// Push null to subscribers. + public bool Execute() + { + return Execute(Unit.Default); + } + + /// Force push parameter to subscribers. + public void ForceExecute() + { + ForceExecute(Unit.Default); + } + } + + public class ReactiveCommand : IReactiveCommand, IDisposable + { + readonly Subject trigger = new Subject(); + readonly IDisposable canExecuteSubscription; + + ReactiveProperty canExecute; + public IReadOnlyReactiveProperty CanExecute + { + get + { + return canExecute; + } + } + + public bool IsDisposed { get; private set; } + + /// + /// CanExecute is always true. + /// + public ReactiveCommand() + { + this.canExecute = new ReactiveProperty(true); + this.canExecuteSubscription = Disposable.Empty; + } + + /// + /// CanExecute is changed from canExecute sequence. + /// + public ReactiveCommand(IObservable canExecuteSource, bool initialValue = true) + { + this.canExecute = new ReactiveProperty(initialValue); + this.canExecuteSubscription = canExecuteSource + .DistinctUntilChanged() + .SubscribeWithState(canExecute, (b, c) => c.Value = b); + } + + /// Push parameter to subscribers when CanExecute. + public bool Execute(T parameter) + { + if (canExecute.Value) + { + trigger.OnNext(parameter); + return true; + } + else + { + return false; + } + } + + /// Force push parameter to subscribers. + public void ForceExecute(T parameter) + { + trigger.OnNext(parameter); + } + + /// Subscribe execute. + public IDisposable Subscribe(IObserver observer) + { + return trigger.Subscribe(observer); + } + + /// + /// Stop all subscription and lock CanExecute is false. + /// + public void Dispose() + { + if (IsDisposed) return; + + IsDisposed = true; + canExecute.Dispose(); + trigger.OnCompleted(); + trigger.Dispose(); + canExecuteSubscription.Dispose(); + } + } + + /// + /// Variation of ReactiveCommand, when executing command then CanExecute = false after CanExecute = true. + /// + public class AsyncReactiveCommand : AsyncReactiveCommand + { + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// + public AsyncReactiveCommand() + : base() + { + + } + + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// + public AsyncReactiveCommand(IObservable canExecuteSource) + : base(canExecuteSource) + { + } + + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// The source is shared between other AsyncReactiveCommand. + /// + public AsyncReactiveCommand(IReactiveProperty sharedCanExecute) + : base(sharedCanExecute) + { + } + + public IDisposable Execute() + { + return base.Execute(Unit.Default); + } + } + + /// + /// Variation of ReactiveCommand, canExecute is changed when executing command then CanExecute = false after CanExecute = true. + /// + public class AsyncReactiveCommand : IAsyncReactiveCommand + { + UniRx.InternalUtil.ImmutableList>> asyncActions = UniRx.InternalUtil.ImmutableList>>.Empty; + + readonly object gate = new object(); + readonly IReactiveProperty canExecuteSource; + readonly IReadOnlyReactiveProperty canExecute; + + public IReadOnlyReactiveProperty CanExecute + { + get + { + return canExecute; + } + } + + public bool IsDisposed { get; private set; } + + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// + public AsyncReactiveCommand() + { + this.canExecuteSource = new ReactiveProperty(true); + this.canExecute = canExecuteSource; + } + + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// + public AsyncReactiveCommand(IObservable canExecuteSource) + { + this.canExecuteSource = new ReactiveProperty(true); + this.canExecute = this.canExecuteSource.CombineLatest(canExecuteSource, (x, y) => x && y).ToReactiveProperty(); + } + + /// + /// CanExecute is automatically changed when executing to false and finished to true. + /// The source is shared between other AsyncReactiveCommand. + /// + public AsyncReactiveCommand(IReactiveProperty sharedCanExecute) + { + this.canExecuteSource = sharedCanExecute; + this.canExecute = sharedCanExecute; + } + + /// Push parameter to subscribers when CanExecute. + public IDisposable Execute(T parameter) + { + if (canExecute.Value) + { + canExecuteSource.Value = false; + var a = asyncActions.Data; + if (a.Length == 1) + { + try + { + var asyncState = a[0].Invoke(parameter) ?? Observable.ReturnUnit(); + return asyncState.Finally(() => canExecuteSource.Value = true).Subscribe(); + } + catch + { + canExecuteSource.Value = true; + throw; + } + } + else + { + var xs = new IObservable[a.Length]; + try + { + for (int i = 0; i < a.Length; i++) + { + xs[i] = a[i].Invoke(parameter) ?? Observable.ReturnUnit(); + } + } + catch + { + canExecuteSource.Value = true; + throw; + } + + return Observable.WhenAll(xs).Finally(() => canExecuteSource.Value = true).Subscribe(); + } + } + else + { + return Disposable.Empty; + } + } + + /// Subscribe execute. + public IDisposable Subscribe(Func> asyncAction) + { + lock (gate) + { + asyncActions = asyncActions.Add(asyncAction); + } + + return new Subscription(this, asyncAction); + } + + /// + /// Stop all subscription and lock CanExecute is false. + /// + public void Dispose() + { + if (IsDisposed) return; + + IsDisposed = true; + asyncActions = UniRx.InternalUtil.ImmutableList>>.Empty; + } + class Subscription : IDisposable + { + readonly AsyncReactiveCommand parent; + readonly Func> asyncAction; + + public Subscription(AsyncReactiveCommand parent, Func> asyncAction) + { + this.parent = parent; + this.asyncAction = asyncAction; + } + + public void Dispose() + { + lock (parent.gate) + { + parent.asyncActions = parent.asyncActions.Remove(asyncAction); + } + } + } + } + + public static class ReactiveCommandExtensions + { + /// + /// Create non parameter commands. CanExecute is changed from canExecute sequence. + /// + public static ReactiveCommand ToReactiveCommand(this IObservable canExecuteSource, bool initialValue = true) + { + return new ReactiveCommand(canExecuteSource, initialValue); + } + + /// + /// Create parametered comamnds. CanExecute is changed from canExecute sequence. + /// + public static ReactiveCommand ToReactiveCommand(this IObservable canExecuteSource, bool initialValue = true) + { + return new ReactiveCommand(canExecuteSource, initialValue); + } + +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) + + static readonly Action Callback = CancelCallback; + + static void CancelCallback(object state) + { + var tuple = (Tuple)state; + tuple.Item2.Dispose(); + tuple.Item1.TrySetCanceled(); + } + + public static Task WaitUntilExecuteAsync(this IReactiveCommand source, CancellationToken cancellationToken = default(CancellationToken)) + { + var tcs = new CancellableTaskCompletionSource(); + + var disposable = new SingleAssignmentDisposable(); + disposable.Disposable = source.Subscribe(x => + { + disposable.Dispose(); // finish subscription. + tcs.TrySetResult(x); + }, ex => tcs.TrySetException(ex), () => tcs.TrySetCanceled()); + + cancellationToken.Register(Callback, Tuple.Create(tcs, disposable.Disposable), false); + + return tcs.Task; + } + + public static System.Runtime.CompilerServices.TaskAwaiter GetAwaiter(this IReactiveCommand command) + { + return command.WaitUntilExecuteAsync(CancellationToken.None).GetAwaiter(); + } + +#endif + +#if !UniRxLibrary + + // for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + + /// + /// Bind ReactiveCommand to button's interactable and onClick. + /// + public static IDisposable BindTo(this IReactiveCommand command, UnityEngine.UI.Button button) + { + var d1 = command.CanExecute.SubscribeToInteractable(button); + var d2 = button.OnClickAsObservable().SubscribeWithState(command, (x, c) => c.Execute(x)); + return StableCompositeDisposable.Create(d1, d2); + } + + /// + /// Bind ReactiveCommand to button's interactable and onClick and register onClick action to command. + /// + public static IDisposable BindToOnClick(this IReactiveCommand command, UnityEngine.UI.Button button, Action onClick) + { + var d1 = command.CanExecute.SubscribeToInteractable(button); + var d2 = button.OnClickAsObservable().SubscribeWithState(command, (x, c) => c.Execute(x)); + var d3 = command.Subscribe(onClick); + + return StableCompositeDisposable.Create(d1, d2, d3); + } + + /// + /// Bind canExecuteSource to button's interactable and onClick and register onClick action to command. + /// + public static IDisposable BindToButtonOnClick(this IObservable canExecuteSource, UnityEngine.UI.Button button, Action onClick, bool initialValue = true) + { + return ToReactiveCommand(canExecuteSource, initialValue).BindToOnClick(button, onClick); + } + +#endif + +#endif + } + + public static class AsyncReactiveCommandExtensions + { + public static AsyncReactiveCommand ToAsyncReactiveCommand(this IReactiveProperty sharedCanExecuteSource) + { + return new AsyncReactiveCommand(sharedCanExecuteSource); + } + + public static AsyncReactiveCommand ToAsyncReactiveCommand(this IReactiveProperty sharedCanExecuteSource) + { + return new AsyncReactiveCommand(sharedCanExecuteSource); + } + +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) + + static readonly Action Callback = CancelCallback; + + static void CancelCallback(object state) + { + var tuple = (Tuple)state; + tuple.Item2.Dispose(); + tuple.Item1.TrySetCanceled(); + } + + public static Task WaitUntilExecuteAsync(this IAsyncReactiveCommand source, CancellationToken cancellationToken = default(CancellationToken)) + { + var tcs = new CancellableTaskCompletionSource(); + + var subscription = source.Subscribe(x => { tcs.TrySetResult(x); return Observable.ReturnUnit(); }); + cancellationToken.Register(Callback, Tuple.Create(tcs, subscription), false); + + return tcs.Task; + } + + public static System.Runtime.CompilerServices.TaskAwaiter GetAwaiter(this IAsyncReactiveCommand command) + { + return command.WaitUntilExecuteAsync(CancellationToken.None).GetAwaiter(); + } + +#endif + + +#if !UniRxLibrary + + // for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + + /// + /// Bind AsyncRaectiveCommand to button's interactable and onClick. + /// + public static IDisposable BindTo(this IAsyncReactiveCommand command, UnityEngine.UI.Button button) + { + var d1 = command.CanExecute.SubscribeToInteractable(button); + var d2 = button.OnClickAsObservable().SubscribeWithState(command, (x, c) => c.Execute(x)); + + return StableCompositeDisposable.Create(d1, d2); + } + + /// + /// Bind AsyncRaectiveCommand to button's interactable and onClick and register async action to command. + /// + public static IDisposable BindToOnClick(this IAsyncReactiveCommand command, UnityEngine.UI.Button button, Func> asyncOnClick) + { + var d1 = command.CanExecute.SubscribeToInteractable(button); + var d2 = button.OnClickAsObservable().SubscribeWithState(command, (x, c) => c.Execute(x)); + var d3 = command.Subscribe(asyncOnClick); + + return StableCompositeDisposable.Create(d1, d2, d3); + } + + /// + /// Create AsyncReactiveCommand and bind to button's interactable and onClick and register async action to command. + /// + public static IDisposable BindToOnClick(this UnityEngine.UI.Button button, Func> asyncOnClick) + { + return new AsyncReactiveCommand().BindToOnClick(button, asyncOnClick); + } + + /// + /// Create AsyncReactiveCommand and bind sharedCanExecuteSource source to button's interactable and onClick and register async action to command. + /// + public static IDisposable BindToOnClick(this UnityEngine.UI.Button button, IReactiveProperty sharedCanExecuteSource, Func> asyncOnClick) + { + return sharedCanExecuteSource.ToAsyncReactiveCommand().BindToOnClick(button, asyncOnClick); + } +#endif + +#endif + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs.meta new file mode 100644 index 00000000..a375094f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveCommand.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 939b249fde5252f45a4404e7648931ed +timeCreated: 1462927720 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs new file mode 100644 index 00000000..dd855974 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs @@ -0,0 +1,520 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace UniRx +{ + public struct DictionaryAddEvent : IEquatable> + { + public TKey Key { get; private set; } + public TValue Value { get; private set; } + + public DictionaryAddEvent(TKey key, TValue value) + : this() + { + Key = key; + Value = value; + } + + public override string ToString() + { + return string.Format("Key:{0} Value:{1}", Key, Value); + } + + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(Key) ^ EqualityComparer.Default.GetHashCode(Value) << 2; + } + + public bool Equals(DictionaryAddEvent other) + { + return EqualityComparer.Default.Equals(Key, other.Key) && EqualityComparer.Default.Equals(Value, other.Value); + } + } + + public struct DictionaryRemoveEvent : IEquatable> + { + public TKey Key { get; private set; } + public TValue Value { get; private set; } + + public DictionaryRemoveEvent(TKey key, TValue value) + : this() + { + Key = key; + Value = value; + } + + public override string ToString() + { + return string.Format("Key:{0} Value:{1}", Key, Value); + } + + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(Key) ^ EqualityComparer.Default.GetHashCode(Value) << 2; + } + + public bool Equals(DictionaryRemoveEvent other) + { + return EqualityComparer.Default.Equals(Key, other.Key) && EqualityComparer.Default.Equals(Value, other.Value); + } + } + + public struct DictionaryReplaceEvent : IEquatable> + { + public TKey Key { get; private set; } + public TValue OldValue { get; private set; } + public TValue NewValue { get; private set; } + + public DictionaryReplaceEvent(TKey key, TValue oldValue, TValue newValue) + : this() + { + Key = key; + OldValue = oldValue; + NewValue = newValue; + } + + public override string ToString() + { + return string.Format("Key:{0} OldValue:{1} NewValue:{2}", Key, OldValue, NewValue); + } + + public override int GetHashCode() + { + return EqualityComparer.Default.GetHashCode(Key) ^ EqualityComparer.Default.GetHashCode(OldValue) << 2 ^ EqualityComparer.Default.GetHashCode(NewValue) >> 2; + } + + public bool Equals(DictionaryReplaceEvent other) + { + return EqualityComparer.Default.Equals(Key, other.Key) && EqualityComparer.Default.Equals(OldValue, other.OldValue) && EqualityComparer.Default.Equals(NewValue, other.NewValue); + } + } + + // IReadOnlyDictionary is from .NET 4.5 + public interface IReadOnlyReactiveDictionary : IEnumerable> + { + int Count { get; } + TValue this[TKey index] { get; } + bool ContainsKey(TKey key); + bool TryGetValue(TKey key, out TValue value); + + IObservable> ObserveAdd(); + IObservable ObserveCountChanged(bool notifyCurrentCount = false); + IObservable> ObserveRemove(); + IObservable> ObserveReplace(); + IObservable ObserveReset(); + } + + public interface IReactiveDictionary : IReadOnlyReactiveDictionary, IDictionary + { + } + + [Serializable] + public class ReactiveDictionary : IReactiveDictionary, IDictionary, IEnumerable, ICollection>, IEnumerable>, IDictionary, IDisposable +#if !UNITY_METRO + , ISerializable, IDeserializationCallback +#endif + { + [NonSerialized] + bool isDisposed = false; + +#if !UniRxLibrary + [UnityEngine.SerializeField] +#endif + readonly Dictionary inner; + + public ReactiveDictionary() + { + inner = new Dictionary(); + } + + public ReactiveDictionary(IEqualityComparer comparer) + { + inner = new Dictionary(comparer); + } + + public ReactiveDictionary(Dictionary innerDictionary) + { + inner = innerDictionary; + } + + public TValue this[TKey key] + { + get + { + return inner[key]; + } + + set + { + TValue oldValue; + if (TryGetValue(key, out oldValue)) + { + inner[key] = value; + if (dictionaryReplace != null) dictionaryReplace.OnNext(new DictionaryReplaceEvent(key, oldValue, value)); + } + else + { + inner[key] = value; + if (dictionaryAdd != null) dictionaryAdd.OnNext(new DictionaryAddEvent(key, value)); + if (countChanged != null) countChanged.OnNext(Count); + } + } + } + + public int Count + { + get + { + return inner.Count; + } + } + + public Dictionary.KeyCollection Keys + { + get + { + return inner.Keys; + } + } + + public Dictionary.ValueCollection Values + { + get + { + return inner.Values; + } + } + + public void Add(TKey key, TValue value) + { + inner.Add(key, value); + + if (dictionaryAdd != null) dictionaryAdd.OnNext(new DictionaryAddEvent(key, value)); + if (countChanged != null) countChanged.OnNext(Count); + } + + public void Clear() + { + var beforeCount = Count; + inner.Clear(); + + if (collectionReset != null) collectionReset.OnNext(Unit.Default); + if (beforeCount > 0) + { + if (countChanged != null) countChanged.OnNext(Count); + } + } + + public bool Remove(TKey key) + { + TValue oldValue; + if (inner.TryGetValue(key, out oldValue)) + { + var isSuccessRemove = inner.Remove(key); + if (isSuccessRemove) + { + if (dictionaryRemove != null) dictionaryRemove.OnNext(new DictionaryRemoveEvent(key, oldValue)); + if (countChanged != null) countChanged.OnNext(Count); + } + return isSuccessRemove; + } + else + { + return false; + } + } + + public bool ContainsKey(TKey key) + { + return inner.ContainsKey(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return inner.TryGetValue(key, out value); + } + + public Dictionary.Enumerator GetEnumerator() + { + return inner.GetEnumerator(); + } + + void DisposeSubject(ref Subject 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 countChanged); + DisposeSubject(ref collectionReset); + DisposeSubject(ref dictionaryAdd); + DisposeSubject(ref dictionaryRemove); + DisposeSubject(ref dictionaryReplace); + } + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + + + #region Observe + + [NonSerialized] + Subject countChanged = null; + public IObservable ObserveCountChanged(bool notifyCurrentCount = false) + { + if (isDisposed) return Observable.Empty(); + + var subject = countChanged ?? (countChanged = new Subject()); + if (notifyCurrentCount) + { + return subject.StartWith(() => this.Count); + } + else + { + return subject; + } + } + + [NonSerialized] + Subject collectionReset = null; + public IObservable ObserveReset() + { + if (isDisposed) return Observable.Empty(); + return collectionReset ?? (collectionReset = new Subject()); + } + + [NonSerialized] + Subject> dictionaryAdd = null; + public IObservable> ObserveAdd() + { + if (isDisposed) return Observable.Empty>(); + return dictionaryAdd ?? (dictionaryAdd = new Subject>()); + } + + [NonSerialized] + Subject> dictionaryRemove = null; + public IObservable> ObserveRemove() + { + if (isDisposed) return Observable.Empty>(); + return dictionaryRemove ?? (dictionaryRemove = new Subject>()); + } + + [NonSerialized] + Subject> dictionaryReplace = null; + public IObservable> ObserveReplace() + { + if (isDisposed) return Observable.Empty>(); + return dictionaryReplace ?? (dictionaryReplace = new Subject>()); + } + + #endregion + + #region implement explicit + + object IDictionary.this[object key] + { + get + { + return this[(TKey)key]; + } + + set + { + this[(TKey)key] = (TValue)value; + } + } + + + bool IDictionary.IsFixedSize + { + get + { + return ((IDictionary)inner).IsFixedSize; + } + } + + bool IDictionary.IsReadOnly + { + get + { + return ((IDictionary)inner).IsReadOnly; + } + } + + bool ICollection.IsSynchronized + { + get + { + return ((IDictionary)inner).IsSynchronized; + } + } + + ICollection IDictionary.Keys + { + get + { + return ((IDictionary)inner).Keys; + } + } + + object ICollection.SyncRoot + { + get + { + return ((IDictionary)inner).SyncRoot; + } + } + + ICollection IDictionary.Values + { + get + { + return ((IDictionary)inner).Values; + } + } + + + bool ICollection>.IsReadOnly + { + get + { + return ((ICollection>)inner).IsReadOnly; + } + } + + ICollection IDictionary.Keys + { + get + { + return inner.Keys; + } + } + + ICollection IDictionary.Values + { + get + { + return inner.Values; + } + } + + void IDictionary.Add(object key, object value) + { + Add((TKey)key, (TValue)value); + } + + bool IDictionary.Contains(object key) + { + return ((IDictionary)inner).Contains(key); + } + + void ICollection.CopyTo(Array array, int index) + { + ((IDictionary)inner).CopyTo(array, index); + } + +#if !UNITY_METRO + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + ((ISerializable)inner).GetObjectData(info, context); + } + + public void OnDeserialization(object sender) + { + ((IDeserializationCallback)inner).OnDeserialization(sender); + } + +#endif + + void IDictionary.Remove(object key) + { + Remove((TKey)key); + } + + void ICollection>.Add(KeyValuePair item) + { + Add((TKey)item.Key, (TValue)item.Value); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return ((ICollection>)inner).Contains(item); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((ICollection>)inner).CopyTo(array, arrayIndex); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return ((ICollection>)inner).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return inner.GetEnumerator(); + } + + bool ICollection>.Remove(KeyValuePair item) + { + TValue v; + if (TryGetValue(item.Key, out v)) + { + if (EqualityComparer.Default.Equals(v, item.Value)) + { + Remove(item.Key); + return true; + } + } + + return false; + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return ((IDictionary)inner).GetEnumerator(); + } + + #endregion + } + + public static partial class ReactiveDictionaryExtensions + { + public static ReactiveDictionary ToReactiveDictionary(this Dictionary dictionary) + { + return new ReactiveDictionary(dictionary); + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs.meta new file mode 100644 index 00000000..0d3e42bc --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveDictionary.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 12cd1079b0fe33f429f9f174c1f849af +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs new file mode 100644 index 00000000..f5c33905 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs @@ -0,0 +1,610 @@ +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#endif + +using System; +using System.Collections.Generic; +using System.Threading; +using UniRx.InternalUtil; +#if !UniRxLibrary +using UnityEngine; +#endif +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +using System.Threading.Tasks; +#endif + +namespace UniRx +{ + public interface IReadOnlyReactiveProperty : IObservable + { + T Value { get; } + bool HasValue { get; } + } + + public interface IReactiveProperty : IReadOnlyReactiveProperty + { + new T Value { get; set; } + } + + internal interface IObserverLinkedList + { + void UnsubscribeNode(ObserverNode node); + } + + internal sealed class ObserverNode : IObserver, IDisposable + { + readonly IObserver observer; + IObserverLinkedList list; + + public ObserverNode Previous { get; internal set; } + public ObserverNode Next { get; internal set; } + + public ObserverNode(IObserverLinkedList list, IObserver observer) + { + this.list = list; + this.observer = observer; + } + + public void OnNext(T value) + { + observer.OnNext(value); + } + + public void OnError(Exception error) + { + observer.OnError(error); + } + + public void OnCompleted() + { + observer.OnCompleted(); + } + + public void Dispose() + { + var sourceList = Interlocked.Exchange(ref list, null); + if (sourceList != null) + { + sourceList.UnsubscribeNode(this); + sourceList = null; + } + } + } + + /// + /// Lightweight property broker. + /// + [Serializable] + public class ReactiveProperty : IReactiveProperty, IDisposable, IOptimizedObservable, IObserverLinkedList + { +#if !UniRxLibrary + static readonly IEqualityComparer defaultEqualityComparer = UnityEqualityComparer.GetDefault(); +#else + static readonly IEqualityComparer defaultEqualityComparer = EqualityComparer.Default; +#endif + +#if !UniRxLibrary + [SerializeField] +#endif + T value = default(T); + + [NonSerialized] + ObserverNode root; + + [NonSerialized] + ObserverNode last; + + [NonSerialized] + bool isDisposed = false; + + protected virtual IEqualityComparer EqualityComparer + { + get + { + return defaultEqualityComparer; + } + } + + public T Value + { + get + { + return value; + } + set + { + if (!EqualityComparer.Equals(this.value, value)) + { + SetValue(value); + if (isDisposed) + return; + + RaiseOnNext(ref value); + } + } + } + + // always true, allows empty constructor 'can' publish value on subscribe. + // because sometimes value is deserialized from UnityEngine. + public bool HasValue + { + get + { + return true; + } + } + + public ReactiveProperty() + : this(default(T)) + { + } + + public ReactiveProperty(T initialValue) + { + SetValue(initialValue); + } + + void RaiseOnNext(ref T value) + { + var node = root; + while (node != null) + { + node.OnNext(value); + node = node.Next; + } + } + + protected virtual void SetValue(T value) + { + this.value = value; + } + + public void SetValueAndForceNotify(T value) + { + SetValue(value); + if (isDisposed) + return; + + RaiseOnNext(ref value); + } + + public IDisposable Subscribe(IObserver observer) + { + if (isDisposed) + { + observer.OnCompleted(); + return Disposable.Empty; + } + + // raise latest value on subscribe + observer.OnNext(value); + + // subscribe node, node as subscription. + var next = new ObserverNode(this, observer); + if (root == null) + { + root = last = next; + } + else + { + last.Next = next; + next.Previous = last; + last = next; + } + return next; + } + + void IObserverLinkedList.UnsubscribeNode(ObserverNode node) + { + if (node == root) + { + root = node.Next; + } + if (node == last) + { + last = node.Previous; + } + + if (node.Previous != null) + { + node.Previous.Next = node.Next; + } + if (node.Next != null) + { + node.Next.Previous = node.Previous; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (isDisposed) return; + + var node = root; + root = last = null; + isDisposed = true; + + while (node != null) + { + node.OnCompleted(); + node = node.Next; + } + } + + public override string ToString() + { + return (value == null) ? "(null)" : value.ToString(); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + } + + /// + /// Lightweight property broker. + /// + public class ReadOnlyReactiveProperty : IReadOnlyReactiveProperty, IDisposable, IOptimizedObservable, IObserverLinkedList, IObserver + { +#if !UniRxLibrary + static readonly IEqualityComparer defaultEqualityComparer = UnityEqualityComparer.GetDefault(); +#else + static readonly IEqualityComparer defaultEqualityComparer = EqualityComparer.Default; +#endif + + readonly bool distinctUntilChanged = true; + bool canPublishValueOnSubscribe = false; + bool isDisposed = false; + bool isSourceCompleted = false; + + T latestValue = default(T); + Exception lastException = null; + IDisposable sourceConnection = null; + + ObserverNode root; + ObserverNode last; + + public T Value + { + get + { + return latestValue; + } + } + + public bool HasValue + { + get + { + return canPublishValueOnSubscribe; + } + } + + protected virtual IEqualityComparer EqualityComparer + { + get + { + return defaultEqualityComparer; + } + } + + public ReadOnlyReactiveProperty(IObservable source) + { + this.sourceConnection = source.Subscribe(this); + } + + public ReadOnlyReactiveProperty(IObservable source, bool distinctUntilChanged) + { + this.distinctUntilChanged = distinctUntilChanged; + this.sourceConnection = source.Subscribe(this); + } + + public ReadOnlyReactiveProperty(IObservable source, T initialValue) + { + this.latestValue = initialValue; + this.canPublishValueOnSubscribe = true; + this.sourceConnection = source.Subscribe(this); + } + + public ReadOnlyReactiveProperty(IObservable source, T initialValue, bool distinctUntilChanged) + { + this.distinctUntilChanged = distinctUntilChanged; + this.latestValue = initialValue; + this.canPublishValueOnSubscribe = true; + this.sourceConnection = source.Subscribe(this); + } + + public IDisposable Subscribe(IObserver observer) + { + if (lastException != null) + { + observer.OnError(lastException); + return Disposable.Empty; + } + + if (isSourceCompleted) + { + if (canPublishValueOnSubscribe) + { + observer.OnNext(latestValue); + observer.OnCompleted(); + return Disposable.Empty; + } + else + { + observer.OnCompleted(); + return Disposable.Empty; + } + } + + if (isDisposed) + { + observer.OnCompleted(); + return Disposable.Empty; + } + + if (canPublishValueOnSubscribe) + { + observer.OnNext(latestValue); + } + + // subscribe node, node as subscription. + var next = new ObserverNode(this, observer); + if (root == null) + { + root = last = next; + } + else + { + last.Next = next; + next.Previous = last; + last = next; + } + + return next; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (isDisposed) return; + sourceConnection.Dispose(); + + var node = root; + root = last = null; + isDisposed = true; + + while (node != null) + { + node.OnCompleted(); + node = node.Next; + } + } + + void IObserverLinkedList.UnsubscribeNode(ObserverNode node) + { + if (node == root) + { + root = node.Next; + } + if (node == last) + { + last = node.Previous; + } + + if (node.Previous != null) + { + node.Previous.Next = node.Next; + } + if (node.Next != null) + { + node.Next.Previous = node.Previous; + } + } + + void IObserver.OnNext(T value) + { + if (isDisposed) return; + + if (canPublishValueOnSubscribe) + { + if (distinctUntilChanged && EqualityComparer.Equals(this.latestValue, value)) + { + return; + } + } + + canPublishValueOnSubscribe = true; + + // SetValue + this.latestValue = value; + + // call source.OnNext + var node = root; + while (node != null) + { + node.OnNext(value); + node = node.Next; + } + } + + void IObserver.OnError(Exception error) + { + lastException = error; + + // call source.OnError + var node = root; + while (node != null) + { + node.OnError(error); + node = node.Next; + } + + root = last = null; + } + + void IObserver.OnCompleted() + { + isSourceCompleted = true; + root = last = null; + } + + public override string ToString() + { + return (latestValue == null) ? "(null)" : latestValue.ToString(); + } + + public bool IsRequiredSubscribeOnCurrentThread() + { + return false; + } + } + + /// + /// Extension methods of ReactiveProperty<T> + /// + public static class ReactivePropertyExtensions + { + public static IReadOnlyReactiveProperty ToReactiveProperty(this IObservable source) + { + return new ReadOnlyReactiveProperty(source); + } + + public static IReadOnlyReactiveProperty ToReactiveProperty(this IObservable source, T initialValue) + { + return new ReadOnlyReactiveProperty(source, initialValue); + } + + public static ReadOnlyReactiveProperty ToReadOnlyReactiveProperty(this IObservable source) + { + return new ReadOnlyReactiveProperty(source); + } + +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) + + static readonly Action Callback = CancelCallback; + + static void CancelCallback(object state) + { + var tuple = (Tuple)state; + tuple.Item2.Dispose(); + tuple.Item1.TrySetCanceled(); + } + + public static Task WaitUntilValueChangedAsync(this IReadOnlyReactiveProperty source, CancellationToken cancellationToken = default(CancellationToken)) + { + var tcs = new CancellableTaskCompletionSource(); + + var disposable = new SingleAssignmentDisposable(); + if (source.HasValue) + { + // Skip first value + var isFirstValue = true; + disposable.Disposable = source.Subscribe(x => + { + if (isFirstValue) + { + isFirstValue = false; + return; + } + else + { + disposable.Dispose(); // finish subscription. + tcs.TrySetResult(x); + } + }, ex => tcs.TrySetException(ex), () => tcs.TrySetCanceled()); + } + else + { + disposable.Disposable = source.Subscribe(x => + { + disposable.Dispose(); // finish subscription. + tcs.TrySetResult(x); + }, ex => tcs.TrySetException(ex), () => tcs.TrySetCanceled()); + } + + cancellationToken.Register(Callback, Tuple.Create(tcs, disposable.Disposable), false); + + return tcs.Task; + } + + public static System.Runtime.CompilerServices.TaskAwaiter GetAwaiter(this IReadOnlyReactiveProperty source) + { + return source.WaitUntilValueChangedAsync(CancellationToken.None).GetAwaiter(); + } + +#endif + + /// + /// Create ReadOnlyReactiveProperty with distinctUntilChanged: false. + /// + public static ReadOnlyReactiveProperty ToSequentialReadOnlyReactiveProperty(this IObservable source) + { + return new ReadOnlyReactiveProperty(source, distinctUntilChanged: false); + } + + public static ReadOnlyReactiveProperty ToReadOnlyReactiveProperty(this IObservable source, T initialValue) + { + return new ReadOnlyReactiveProperty(source, initialValue); + } + + /// + /// Create ReadOnlyReactiveProperty with distinctUntilChanged: false. + /// + public static ReadOnlyReactiveProperty ToSequentialReadOnlyReactiveProperty(this IObservable source, T initialValue) + { + return new ReadOnlyReactiveProperty(source, initialValue, distinctUntilChanged: false); + } + + public static IObservable SkipLatestValueOnSubscribe(this IReadOnlyReactiveProperty source) + { + return source.HasValue ? source.Skip(1) : source; + } + + // for multiple toggle or etc.. + + /// + /// Lastest values of each sequence are all true. + /// + public static IObservable CombineLatestValuesAreAllTrue(this IEnumerable> sources) + { + return sources.CombineLatest().Select(xs => + { + foreach (var item in xs) + { + if (item == false) + return false; + } + return true; + }); + } + + + /// + /// Lastest values of each sequence are all false. + /// + public static IObservable CombineLatestValuesAreAllFalse(this IEnumerable> sources) + { + return sources.CombineLatest().Select(xs => + { + foreach (var item in xs) + { + if (item == true) + return false; + } + return true; + }); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs.meta new file mode 100644 index 00000000..9e4eda81 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ReactiveProperty.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 88e12aa895fef434fbe3ea0cc8f57301 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs new file mode 100644 index 00000000..04fda48f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs @@ -0,0 +1,84 @@ +#if UNITY_EDITOR + +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; + +namespace UniRx +{ + [InitializeOnLoad] + public class ScenePlaybackDetector + { + private static bool _isPlaying = false; + + private static bool AboutToStartScene + { + get + { + return EditorPrefs.GetBool("AboutToStartScene"); + } + set + { + EditorPrefs.SetBool("AboutToStartScene", value); + } + } + + public static bool IsPlaying + { + get + { + return _isPlaying; + } + set + { + if (_isPlaying != value) + { + _isPlaying = value; + } + } + } + + // This callback is notified after scripts have been reloaded. + [DidReloadScripts] + public static void OnDidReloadScripts() + { + // Filter DidReloadScripts callbacks to the moment where playmodeState transitions into isPlaying. + if (AboutToStartScene) + { + IsPlaying = true; + } + } + + // InitializeOnLoad ensures that this constructor is called when the Unity Editor is started. + static ScenePlaybackDetector() + { +#if UNITY_2017_2_OR_NEWER + EditorApplication.playModeStateChanged += e => +#else + EditorApplication.playmodeStateChanged += () => +#endif + { + // Before scene start: isPlayingOrWillChangePlaymode = false; isPlaying = false + // Pressed Playback button: isPlayingOrWillChangePlaymode = true; isPlaying = false + // Playing: isPlayingOrWillChangePlaymode = false; isPlaying = true + // Pressed stop button: isPlayingOrWillChangePlaymode = true; isPlaying = true + if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying) + { + AboutToStartScene = true; + } + else + { + AboutToStartScene = false; + } + + // Detect when playback is stopped. + if (!EditorApplication.isPlaying) + { + IsPlaying = false; + } + }; + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs.meta new file mode 100644 index 00000000..d55cd182 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/ScenePlaybackDetector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8d380d86e2ef6674c83ca983a1604273 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit.meta new file mode 100644 index 00000000..d80c1fc5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 726595c7d6d85824887a77691e3ca50a +folderAsset: yes +timeCreated: 1468655394 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs new file mode 100644 index 00000000..45b97395 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs @@ -0,0 +1,474 @@ +#if UNITY_5_3_OR_NEWER + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace UniRx.Toolkit +{ + /// + /// Bass class of ObjectPool. + /// + public abstract class ObjectPool : IDisposable + where T : UnityEngine.Component + { + bool isDisposed = false; + Queue q; + + /// + /// Limit of instace count. + /// + protected int MaxPoolCount + { + get + { + return int.MaxValue; + } + } + + /// + /// Create instance when needed. + /// + protected abstract T CreateInstance(); + + /// + /// Called before return to pool, useful for set active object(it is default behavior). + /// + protected virtual void OnBeforeRent(T instance) + { + instance.gameObject.SetActive(true); + } + + /// + /// Called before return to pool, useful for set inactive object(it is default behavior). + /// + protected virtual void OnBeforeReturn(T instance) + { + instance.gameObject.SetActive(false); + } + + /// + /// Called when clear or disposed, useful for destroy instance or other finalize method. + /// + protected virtual void OnClear(T instance) + { + if (instance == null) return; + + var go = instance.gameObject; + if (go == null) return; + UnityEngine.Object.Destroy(go); + } + + /// + /// Current pooled object count. + /// + public int Count + { + get + { + if (q == null) return 0; + return q.Count; + } + } + + /// + /// Get instance from pool. + /// + public T Rent() + { + if (isDisposed) throw new ObjectDisposedException("ObjectPool was already disposed."); + if (q == null) q = new Queue(); + + var instance = (q.Count > 0) + ? q.Dequeue() + : CreateInstance(); + + OnBeforeRent(instance); + return instance; + } + + /// + /// Return instance to pool. + /// + public void Return(T instance) + { + if (isDisposed) throw new ObjectDisposedException("ObjectPool was already disposed."); + if (instance == null) throw new ArgumentNullException("instance"); + + if (q == null) q = new Queue(); + + if ((q.Count + 1) == MaxPoolCount) + { + throw new InvalidOperationException("Reached Max PoolSize"); + } + + OnBeforeReturn(instance); + q.Enqueue(instance); + } + + /// + /// Clear pool. + /// + public void Clear(bool callOnBeforeRent = false) + { + if (q == null) return; + while (q.Count != 0) + { + var instance = q.Dequeue(); + if (callOnBeforeRent) + { + OnBeforeRent(instance); + } + OnClear(instance); + } + } + + /// + /// Trim pool instances. + /// + /// 0.0f = clear all ~ 1.0f = live all. + /// Min pool count. + /// If true, call OnBeforeRent before OnClear. + public void Shrink(float instanceCountRatio, int minSize, bool callOnBeforeRent = false) + { + if (q == null) return; + + if (instanceCountRatio <= 0) instanceCountRatio = 0; + if (instanceCountRatio >= 1.0f) instanceCountRatio = 1.0f; + + var size = (int)(q.Count * instanceCountRatio); + size = Math.Max(minSize, size); + + while (q.Count > size) + { + var instance = q.Dequeue(); + if (callOnBeforeRent) + { + OnBeforeRent(instance); + } + OnClear(instance); + } + } + + /// + /// If needs shrink pool frequently, start check timer. + /// + /// Interval of call Shrink. + /// 0.0f = clearAll ~ 1.0f = live all. + /// Min pool count. + /// If true, call OnBeforeRent before OnClear. + public IDisposable StartShrinkTimer(TimeSpan checkInterval, float instanceCountRatio, int minSize, bool callOnBeforeRent = false) + { + return Observable.Interval(checkInterval) + .TakeWhile(_ => !isDisposed) + .Subscribe(_ => + { + Shrink(instanceCountRatio, minSize, callOnBeforeRent); + }); + } + + /// + /// Fill pool before rent operation. + /// + /// Pool instance count. + /// Create count per frame. + public IObservable PreloadAsync(int preloadCount, int threshold) + { + if (q == null) q = new Queue(preloadCount); + + return Observable.FromMicroCoroutine((observer, cancel) => PreloadCore(preloadCount, threshold, observer, cancel)); + } + + IEnumerator PreloadCore(int preloadCount, int threshold, IObserver observer, CancellationToken cancellationToken) + { + while (Count < preloadCount && !cancellationToken.IsCancellationRequested) + { + var requireCount = preloadCount - Count; + if (requireCount <= 0) break; + + var createCount = Math.Min(requireCount, threshold); + + for (int i = 0; i < createCount; i++) + { + try + { + var instance = CreateInstance(); + Return(instance); + } + catch (Exception ex) + { + observer.OnError(ex); + yield break; + } + } + yield return null; // next frame. + } + + observer.OnNext(Unit.Default); + observer.OnCompleted(); + } + + #region IDisposable Support + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + if (disposing) + { + Clear(false); + } + + isDisposed = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } + + /// + /// Bass class of ObjectPool. If needs asynchronous initialization, use this instead of standard ObjectPool. + /// + public abstract class AsyncObjectPool : IDisposable + where T : UnityEngine.Component + { + bool isDisposed = false; + Queue q; + + /// + /// Limit of instace count. + /// + protected int MaxPoolCount + { + get + { + return int.MaxValue; + } + } + + /// + /// Create instance when needed. + /// + protected abstract IObservable CreateInstanceAsync(); + + /// + /// Called before return to pool, useful for set active object(it is default behavior). + /// + protected virtual void OnBeforeRent(T instance) + { + instance.gameObject.SetActive(true); + } + + /// + /// Called before return to pool, useful for set inactive object(it is default behavior). + /// + protected virtual void OnBeforeReturn(T instance) + { + instance.gameObject.SetActive(false); + } + + /// + /// Called when clear or disposed, useful for destroy instance or other finalize method. + /// + protected virtual void OnClear(T instance) + { + if (instance == null) return; + + var go = instance.gameObject; + if (go == null) return; + UnityEngine.Object.Destroy(go); + } + + /// + /// Current pooled object count. + /// + public int Count + { + get + { + if (q == null) return 0; + return q.Count; + } + } + + /// + /// Get instance from pool. + /// + public IObservable RentAsync() + { + if (isDisposed) throw new ObjectDisposedException("ObjectPool was already disposed."); + if (q == null) q = new Queue(); + + if (q.Count > 0) + { + var instance = q.Dequeue(); + OnBeforeRent(instance); + return Observable.Return(instance); + } + else + { + var instance = CreateInstanceAsync(); + return instance.Do(x => OnBeforeRent(x)); + } + } + + /// + /// Return instance to pool. + /// + public void Return(T instance) + { + if (isDisposed) throw new ObjectDisposedException("ObjectPool was already disposed."); + if (instance == null) throw new ArgumentNullException("instance"); + + if (q == null) q = new Queue(); + + if ((q.Count + 1) == MaxPoolCount) + { + throw new InvalidOperationException("Reached Max PoolSize"); + } + + OnBeforeReturn(instance); + q.Enqueue(instance); + } + + /// + /// Trim pool instances. + /// + /// 0.0f = clear all ~ 1.0f = live all. + /// Min pool count. + /// If true, call OnBeforeRent before OnClear. + public void Shrink(float instanceCountRatio, int minSize, bool callOnBeforeRent = false) + { + if (q == null) return; + + if (instanceCountRatio <= 0) instanceCountRatio = 0; + if (instanceCountRatio >= 1.0f) instanceCountRatio = 1.0f; + + var size = (int)(q.Count * instanceCountRatio); + size = Math.Max(minSize, size); + + while (q.Count > size) + { + var instance = q.Dequeue(); + if (callOnBeforeRent) + { + OnBeforeRent(instance); + } + OnClear(instance); + } + } + + /// + /// If needs shrink pool frequently, start check timer. + /// + /// Interval of call Shrink. + /// 0.0f = clearAll ~ 1.0f = live all. + /// Min pool count. + /// If true, call OnBeforeRent before OnClear. + public IDisposable StartShrinkTimer(TimeSpan checkInterval, float instanceCountRatio, int minSize, bool callOnBeforeRent = false) + { + return Observable.Interval(checkInterval) + .TakeWhile(_ => !isDisposed) + .Subscribe(_ => + { + Shrink(instanceCountRatio, minSize, callOnBeforeRent); + }); + } + + /// + /// Clear pool. + /// + public void Clear(bool callOnBeforeRent = false) + { + if (q == null) return; + while (q.Count != 0) + { + var instance = q.Dequeue(); + if (callOnBeforeRent) + { + OnBeforeRent(instance); + } + OnClear(instance); + } + } + + /// + /// Fill pool before rent operation. + /// + /// Pool instance count. + /// Create count per frame. + public IObservable PreloadAsync(int preloadCount, int threshold) + { + if (q == null) q = new Queue(preloadCount); + + return Observable.FromMicroCoroutine((observer, cancel) => PreloadCore(preloadCount, threshold, observer, cancel)); + } + + IEnumerator PreloadCore(int preloadCount, int threshold, IObserver observer, CancellationToken cancellationToken) + { + while (Count < preloadCount && !cancellationToken.IsCancellationRequested) + { + var requireCount = preloadCount - Count; + if (requireCount <= 0) break; + + var createCount = Math.Min(requireCount, threshold); + + var loaders = new IObservable[createCount]; + for (int i = 0; i < createCount; i++) + { + var instanceFuture = CreateInstanceAsync(); + loaders[i] = instanceFuture.ForEachAsync(x => Return(x)); + } + + var awaiter = Observable.WhenAll(loaders).ToYieldInstruction(false, cancellationToken); + while (!(awaiter.HasResult || awaiter.IsCanceled || awaiter.HasError)) + { + yield return null; + } + + if (awaiter.HasError) + { + observer.OnError(awaiter.Error); + yield break; + } + else if (awaiter.IsCanceled) + { + yield break; // end. + } + } + + observer.OnNext(Unit.Default); + observer.OnCompleted(); + } + + #region IDisposable Support + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + if (disposing) + { + Clear(false); + } + + isDisposed = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs.meta new file mode 100644 index 00000000..08b34ce2 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Toolkit/ObjectPool.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4980e1e001c7e94fab3250ba284dc91 +timeCreated: 1468655394 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers.meta new file mode 100644 index 00000000..9d639d87 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5380144628ecdc74ab6778f80d103d51 +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs new file mode 100644 index 00000000..cc9c136a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs @@ -0,0 +1,49 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableAnimatorTrigger : ObservableTriggerBase + { + Subject onAnimatorIK; + + /// Callback for setting up animation IK (inverse kinematics). + void OnAnimatorIK(int layerIndex) + { + if (onAnimatorIK != null) onAnimatorIK.OnNext(layerIndex); + } + + /// Callback for setting up animation IK (inverse kinematics). + public IObservable OnAnimatorIKAsObservable() + { + return onAnimatorIK ?? (onAnimatorIK = new Subject()); + } + + Subject onAnimatorMove; + + /// Callback for processing animation movements for modifying root motion. + void OnAnimatorMove() + { + if (onAnimatorMove != null) onAnimatorMove.OnNext(Unit.Default); + } + + /// Callback for processing animation movements for modifying root motion. + public IObservable OnAnimatorMoveAsObservable() + { + return onAnimatorMove ?? (onAnimatorMove = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onAnimatorIK != null) + { + onAnimatorIK.OnCompleted(); + } + if (onAnimatorMove != null) + { + onAnimatorMove.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs.meta new file mode 100644 index 00000000..628dabd8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableAnimatorTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e03f9257cc6667f4082439aa77d6f01e +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs new file mode 100644 index 00000000..8b368020 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableBeginDragTrigger : ObservableTriggerBase, IEventSystemHandler, IBeginDragHandler + { + Subject onBeginDrag; + + void IBeginDragHandler.OnBeginDrag(PointerEventData eventData) + { + if (onBeginDrag != null) onBeginDrag.OnNext(eventData); + } + + public IObservable OnBeginDragAsObservable() + { + return onBeginDrag ?? (onBeginDrag = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onBeginDrag != null) + { + onBeginDrag.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs.meta new file mode 100644 index 00000000..8a2438d9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableBeginDragTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3a81a9b6bec6b4f4fba7e0047cd989f6 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs new file mode 100644 index 00000000..1ae59cf8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableCancelTrigger : ObservableTriggerBase, IEventSystemHandler, ICancelHandler + { + Subject onCancel; + + void ICancelHandler.OnCancel(BaseEventData eventData) + { + if (onCancel != null) onCancel.OnNext(eventData); + } + + public IObservable OnCancelAsObservable() + { + return onCancel ?? (onCancel = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onCancel != null) + { + onCancel.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs.meta new file mode 100644 index 00000000..49e5dd4f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCancelTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4c0a9070b7cc23746b2c0e2db3ec16cd +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs new file mode 100644 index 00000000..31278871 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs @@ -0,0 +1,36 @@ +// after uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableCanvasGroupChangedTrigger : ObservableTriggerBase + { + Subject onCanvasGroupChanged; + + // Callback that is sent if the canvas group is changed + void OnCanvasGroupChanged() + { + if (onCanvasGroupChanged != null) onCanvasGroupChanged.OnNext(Unit.Default); + } + + /// Callback that is sent if the canvas group is changed. + public IObservable OnCanvasGroupChangedAsObservable() + { + return onCanvasGroupChanged ?? (onCanvasGroupChanged = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onCanvasGroupChanged != null) + { + onCanvasGroupChanged.OnCompleted(); + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs.meta new file mode 100644 index 00000000..ca96b7a5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCanvasGroupChangedTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 54095d3e740f7714085d0568207cbfe0 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs new file mode 100644 index 00000000..50a5b040 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs @@ -0,0 +1,67 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableCollision2DTrigger : ObservableTriggerBase + { + Subject onCollisionEnter2D; + + /// Sent when an incoming collider makes contact with this object's collider (2D physics only). + void OnCollisionEnter2D(Collision2D coll) + { + if (onCollisionEnter2D != null) onCollisionEnter2D.OnNext(coll); + } + + /// Sent when an incoming collider makes contact with this object's collider (2D physics only). + public IObservable OnCollisionEnter2DAsObservable() + { + return onCollisionEnter2D ?? (onCollisionEnter2D = new Subject()); + } + + Subject onCollisionExit2D; + + /// Sent when a collider on another object stops touching this object's collider (2D physics only). + void OnCollisionExit2D(Collision2D coll) + { + if (onCollisionExit2D != null) onCollisionExit2D.OnNext(coll); + } + + /// Sent when a collider on another object stops touching this object's collider (2D physics only). + public IObservable OnCollisionExit2DAsObservable() + { + return onCollisionExit2D ?? (onCollisionExit2D = new Subject()); + } + + Subject onCollisionStay2D; + + /// Sent each frame where a collider on another object is touching this object's collider (2D physics only). + void OnCollisionStay2D(Collision2D coll) + { + if (onCollisionStay2D != null) onCollisionStay2D.OnNext(coll); + } + + /// Sent each frame where a collider on another object is touching this object's collider (2D physics only). + public IObservable OnCollisionStay2DAsObservable() + { + return onCollisionStay2D ?? (onCollisionStay2D = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onCollisionEnter2D != null) + { + onCollisionEnter2D.OnCompleted(); + } + if (onCollisionExit2D != null) + { + onCollisionExit2D.OnCompleted(); + } + if (onCollisionStay2D != null) + { + onCollisionStay2D.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs.meta new file mode 100644 index 00000000..1b4749c9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollision2DTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1be7847b61f30f24daa5762db87a5b19 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs new file mode 100644 index 00000000..06490c1a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs @@ -0,0 +1,67 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableCollisionTrigger : ObservableTriggerBase + { + Subject onCollisionEnter; + + /// OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. + void OnCollisionEnter(Collision collision) + { + if (onCollisionEnter != null) onCollisionEnter.OnNext(collision); + } + + /// OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. + public IObservable OnCollisionEnterAsObservable() + { + return onCollisionEnter ?? (onCollisionEnter = new Subject()); + } + + Subject onCollisionExit; + + /// OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider. + void OnCollisionExit(Collision collisionInfo) + { + if (onCollisionExit != null) onCollisionExit.OnNext(collisionInfo); + } + + /// OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider. + public IObservable OnCollisionExitAsObservable() + { + return onCollisionExit ?? (onCollisionExit = new Subject()); + } + + Subject onCollisionStay; + + /// OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. + void OnCollisionStay(Collision collisionInfo) + { + if (onCollisionStay != null) onCollisionStay.OnNext(collisionInfo); + } + + /// OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. + public IObservable OnCollisionStayAsObservable() + { + return onCollisionStay ?? (onCollisionStay = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onCollisionEnter != null) + { + onCollisionEnter.OnCompleted(); + } + if (onCollisionExit != null) + { + onCollisionExit.OnCompleted(); + } + if (onCollisionStay != null) + { + onCollisionStay.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs.meta new file mode 100644 index 00000000..4369acca --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableCollisionTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 10b917196cbfcf74898ce1686e205d04 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs new file mode 100644 index 00000000..08bd8355 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableDeselectTrigger : ObservableTriggerBase, IEventSystemHandler, IDeselectHandler + { + Subject onDeselect; + + void IDeselectHandler.OnDeselect(BaseEventData eventData) + { + if (onDeselect != null) onDeselect.OnNext(eventData); + } + + public IObservable OnDeselectAsObservable() + { + return onDeselect ?? (onDeselect = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onDeselect != null) + { + onDeselect.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs.meta new file mode 100644 index 00000000..ff124d08 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDeselectTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9fe6f69c4d869c04e8a1924aab1d3694 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs new file mode 100644 index 00000000..2c25e02c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs @@ -0,0 +1,67 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableDestroyTrigger : MonoBehaviour + { + bool calledDestroy = false; + Subject onDestroy; + CompositeDisposable disposablesOnDestroy; + + [Obsolete("Internal Use.")] + internal bool IsMonitoredActivate { get; set; } + + public bool IsActivated { get; private set; } + + /// + /// Check called OnDestroy. + /// This property does not guarantees GameObject was destroyed, + /// when gameObject is deactive, does not raise OnDestroy. + /// + public bool IsCalledOnDestroy { get { return calledDestroy; } } + + void Awake() + { + IsActivated = true; + } + + /// This function is called when the MonoBehaviour will be destroyed. + void OnDestroy() + { + if (!calledDestroy) + { + calledDestroy = true; + if (disposablesOnDestroy != null) disposablesOnDestroy.Dispose(); + if (onDestroy != null) { onDestroy.OnNext(Unit.Default); onDestroy.OnCompleted(); } + } + } + + /// This function is called when the MonoBehaviour will be destroyed. + public IObservable OnDestroyAsObservable() + { + if (this == null) return Observable.Return(Unit.Default); + if (calledDestroy) return Observable.Return(Unit.Default); + return onDestroy ?? (onDestroy = new Subject()); + } + + /// Invoke OnDestroy, this method is used on internal. + public void ForceRaiseOnDestroy() + { + OnDestroy(); + } + + public void AddDisposableOnDestroy(IDisposable disposable) + { + if (calledDestroy) + { + disposable.Dispose(); + return; + } + + if (disposablesOnDestroy == null) disposablesOnDestroy = new CompositeDisposable(); + disposablesOnDestroy.Add(disposable); + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs.meta new file mode 100644 index 00000000..46786cb9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDestroyTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cb219b23cdf4b314f94a27bca3cc8012 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs new file mode 100644 index 00000000..652aa697 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableDragTrigger : ObservableTriggerBase, IEventSystemHandler, IDragHandler + { + Subject onDrag; + + void IDragHandler.OnDrag(PointerEventData eventData) + { + if (onDrag != null) onDrag.OnNext(eventData); + } + + public IObservable OnDragAsObservable() + { + return onDrag ?? (onDrag = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onDrag != null) + { + onDrag.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs.meta new file mode 100644 index 00000000..ad9945ba --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDragTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 79db090dc9e4db245821e8b89b0e208e +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs new file mode 100644 index 00000000..7499b0be --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableDropTrigger : ObservableTriggerBase, IEventSystemHandler, IDropHandler + { + Subject onDrop; + + void IDropHandler.OnDrop(PointerEventData eventData) + { + if (onDrop != null) onDrop.OnNext(eventData); + } + + public IObservable OnDropAsObservable() + { + return onDrop ?? (onDrop = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onDrop != null) + { + onDrop.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs.meta new file mode 100644 index 00000000..5628d682 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableDropTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f2ffa8b5af3474446a310bb6aa0b180a +timeCreated: 1455373902 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs new file mode 100644 index 00000000..4ca90030 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs @@ -0,0 +1,49 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableEnableTrigger : ObservableTriggerBase + { + Subject onEnable; + + /// This function is called when the object becomes enabled and active. + void OnEnable() + { + if (onEnable != null) onEnable.OnNext(Unit.Default); + } + + /// This function is called when the object becomes enabled and active. + public IObservable OnEnableAsObservable() + { + return onEnable ?? (onEnable = new Subject()); + } + + Subject onDisable; + + /// This function is called when the behaviour becomes disabled () or inactive. + void OnDisable() + { + if (onDisable != null) onDisable.OnNext(Unit.Default); + } + + /// This function is called when the behaviour becomes disabled () or inactive. + public IObservable OnDisableAsObservable() + { + return onDisable ?? (onDisable = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onEnable != null) + { + onEnable.OnCompleted(); + } + if (onDisable != null) + { + onDisable.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs.meta new file mode 100644 index 00000000..6e24311c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEnableTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0d9c7eb607af1fd4aa0e15f52cc0543b +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs new file mode 100644 index 00000000..f63e1326 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableEndDragTrigger : ObservableTriggerBase, IEventSystemHandler, IEndDragHandler + { + Subject onEndDrag; + + void IEndDragHandler.OnEndDrag(PointerEventData eventData) + { + if (onEndDrag != null) onEndDrag.OnNext(eventData); + } + + public IObservable OnEndDragAsObservable() + { + return onEndDrag ?? (onEndDrag = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onEndDrag != null) + { + onEndDrag.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs.meta new file mode 100644 index 00000000..a7edd6a4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEndDragTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b8ce8424f238d6842bd8b09c0cca1ac4 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs new file mode 100644 index 00000000..b19cdf48 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs @@ -0,0 +1,359 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableEventTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler, IBeginDragHandler, IInitializePotentialDragHandler, IDragHandler, IEndDragHandler, IDropHandler, IScrollHandler, IUpdateSelectedHandler, ISelectHandler, IDeselectHandler, IMoveHandler, ISubmitHandler, ICancelHandler + { + #region IDeselectHandler + + Subject onDeselect; + + void IDeselectHandler.OnDeselect(BaseEventData eventData) + { + if (onDeselect != null) onDeselect.OnNext(eventData); + } + + public IObservable OnDeselectAsObservable() + { + return onDeselect ?? (onDeselect = new Subject()); + } + + #endregion + + #region IMoveHandler + + Subject onMove; + + void IMoveHandler.OnMove(AxisEventData eventData) + { + if (onMove != null) onMove.OnNext(eventData); + } + + public IObservable OnMoveAsObservable() + { + return onMove ?? (onMove = new Subject()); + } + + #endregion + + #region IPointerDownHandler + + Subject onPointerDown; + + void IPointerDownHandler.OnPointerDown(PointerEventData eventData) + { + if (onPointerDown != null) onPointerDown.OnNext(eventData); + } + + public IObservable OnPointerDownAsObservable() + { + return onPointerDown ?? (onPointerDown = new Subject()); + } + + #endregion + + #region IPointerEnterHandler + + Subject onPointerEnter; + + void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData) + { + if (onPointerEnter != null) onPointerEnter.OnNext(eventData); + } + + public IObservable OnPointerEnterAsObservable() + { + return onPointerEnter ?? (onPointerEnter = new Subject()); + } + + #endregion + + #region IPointerExitHandler + + Subject onPointerExit; + + void IPointerExitHandler.OnPointerExit(PointerEventData eventData) + { + if (onPointerExit != null) onPointerExit.OnNext(eventData); + } + + public IObservable OnPointerExitAsObservable() + { + return onPointerExit ?? (onPointerExit = new Subject()); + } + + #endregion + + #region IPointerUpHandler + + Subject onPointerUp; + + void IPointerUpHandler.OnPointerUp(PointerEventData eventData) + { + if (onPointerUp != null) onPointerUp.OnNext(eventData); + } + + public IObservable OnPointerUpAsObservable() + { + return onPointerUp ?? (onPointerUp = new Subject()); + } + + #endregion + + #region ISelectHandler + + Subject onSelect; + + void ISelectHandler.OnSelect(BaseEventData eventData) + { + if (onSelect != null) onSelect.OnNext(eventData); + } + + public IObservable OnSelectAsObservable() + { + return onSelect ?? (onSelect = new Subject()); + } + + #endregion + + #region IPointerClickHandler + + Subject onPointerClick; + + void IPointerClickHandler.OnPointerClick(PointerEventData eventData) + { + if (onPointerClick != null) onPointerClick.OnNext(eventData); + } + + public IObservable OnPointerClickAsObservable() + { + return onPointerClick ?? (onPointerClick = new Subject()); + } + + #endregion + + #region ISubmitHandler + + Subject onSubmit; + + void ISubmitHandler.OnSubmit(BaseEventData eventData) + { + if (onSubmit != null) onSubmit.OnNext(eventData); + } + + public IObservable OnSubmitAsObservable() + { + return onSubmit ?? (onSubmit = new Subject()); + } + + #endregion + + #region IDragHandler + + Subject onDrag; + + void IDragHandler.OnDrag(PointerEventData eventData) + { + if (onDrag != null) onDrag.OnNext(eventData); + } + + public IObservable OnDragAsObservable() + { + return onDrag ?? (onDrag = new Subject()); + } + + #endregion + + #region IBeginDragHandler + + Subject onBeginDrag; + + void IBeginDragHandler.OnBeginDrag(PointerEventData eventData) + { + if (onBeginDrag != null) onBeginDrag.OnNext(eventData); + } + + public IObservable OnBeginDragAsObservable() + { + return onBeginDrag ?? (onBeginDrag = new Subject()); + } + + #endregion + + #region IEndDragHandler + + Subject onEndDrag; + + void IEndDragHandler.OnEndDrag(PointerEventData eventData) + { + if (onEndDrag != null) onEndDrag.OnNext(eventData); + } + + public IObservable OnEndDragAsObservable() + { + return onEndDrag ?? (onEndDrag = new Subject()); + } + + #endregion + + #region IDropHandler + + Subject onDrop; + + void IDropHandler.OnDrop(PointerEventData eventData) + { + if (onDrop != null) onDrop.OnNext(eventData); + } + + public IObservable OnDropAsObservable() + { + return onDrop ?? (onDrop = new Subject()); + } + + #endregion + + #region IUpdateSelectedHandler + + Subject onUpdateSelected; + + void IUpdateSelectedHandler.OnUpdateSelected(BaseEventData eventData) + { + if (onUpdateSelected != null) onUpdateSelected.OnNext(eventData); + } + + public IObservable OnUpdateSelectedAsObservable() + { + return onUpdateSelected ?? (onUpdateSelected = new Subject()); + } + + #endregion + + #region IInitializePotentialDragHandler + + Subject onInitializePotentialDrag; + + void IInitializePotentialDragHandler.OnInitializePotentialDrag(PointerEventData eventData) + { + if (onInitializePotentialDrag != null) onInitializePotentialDrag.OnNext(eventData); + } + + public IObservable OnInitializePotentialDragAsObservable() + { + return onInitializePotentialDrag ?? (onInitializePotentialDrag = new Subject()); + } + + #endregion + + #region ICancelHandler + + Subject onCancel; + + void ICancelHandler.OnCancel(BaseEventData eventData) + { + if (onCancel != null) onCancel.OnNext(eventData); + } + + public IObservable OnCancelAsObservable() + { + return onCancel ?? (onCancel = new Subject()); + } + + #endregion + + #region IScrollHandler + + Subject onScroll; + + void IScrollHandler.OnScroll(PointerEventData eventData) + { + if (onScroll != null) onScroll.OnNext(eventData); + } + + public IObservable OnScrollAsObservable() + { + return onScroll ?? (onScroll = new Subject()); + } + + #endregion + + protected override void RaiseOnCompletedOnDestroy() + { + if (onDeselect != null) + { + onDeselect.OnCompleted(); + } + if (onMove != null) + { + onMove.OnCompleted(); + } + if (onPointerDown != null) + { + onPointerDown.OnCompleted(); + } + if (onPointerEnter != null) + { + onPointerEnter.OnCompleted(); + } + if (onPointerExit != null) + { + onPointerExit.OnCompleted(); + } + if (onPointerUp != null) + { + onPointerUp.OnCompleted(); + } + if (onSelect != null) + { + onSelect.OnCompleted(); + } + if (onPointerClick != null) + { + onPointerClick.OnCompleted(); + } + if (onSubmit != null) + { + onSubmit.OnCompleted(); + } + if (onDrag != null) + { + onDrag.OnCompleted(); + } + if (onBeginDrag != null) + { + onBeginDrag.OnCompleted(); + } + if (onEndDrag != null) + { + onEndDrag.OnCompleted(); + } + if (onDrop != null) + { + onDrop.OnCompleted(); + } + if (onUpdateSelected != null) + { + onUpdateSelected.OnCompleted(); + } + if (onInitializePotentialDrag != null) + { + onInitializePotentialDrag.OnCompleted(); + } + if (onCancel != null) + { + onCancel.OnCompleted(); + } + if (onScroll != null) + { + onScroll.OnCompleted(); + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs.meta new file mode 100644 index 00000000..423e5661 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableEventTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 48e93426b16d5454c89e8d47ccded1c5 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs new file mode 100644 index 00000000..9e3fe294 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs @@ -0,0 +1,31 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableFixedUpdateTrigger : ObservableTriggerBase + { + Subject fixedUpdate; + + /// This function is called every fixed framerate frame, if the MonoBehaviour is enabled. + void FixedUpdate() + { + if (fixedUpdate != null) fixedUpdate.OnNext(Unit.Default); + } + + /// This function is called every fixed framerate frame, if the MonoBehaviour is enabled. + public IObservable FixedUpdateAsObservable() + { + return fixedUpdate ?? (fixedUpdate = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (fixedUpdate != null) + { + fixedUpdate.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs.meta new file mode 100644 index 00000000..14700de4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableFixedUpdateTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d525c42c11d945f4398061ed8f84e5f4 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs new file mode 100644 index 00000000..dfd2daa3 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableInitializePotentialDragTrigger : ObservableTriggerBase, IEventSystemHandler, IInitializePotentialDragHandler + { + Subject onInitializePotentialDrag; + + void IInitializePotentialDragHandler.OnInitializePotentialDrag(PointerEventData eventData) + { + if (onInitializePotentialDrag != null) onInitializePotentialDrag.OnNext(eventData); + } + + public IObservable OnInitializePotentialDragAsObservable() + { + return onInitializePotentialDrag ?? (onInitializePotentialDrag = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onInitializePotentialDrag != null) + { + onInitializePotentialDrag.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs.meta new file mode 100644 index 00000000..a11aff19 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableInitializePotentialDragTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3f3148a9e1b8b21409f54d2b0c2c81de +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs new file mode 100644 index 00000000..b7521f26 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs @@ -0,0 +1,47 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableJointTrigger : ObservableTriggerBase + { + Subject onJointBreak; + + void OnJointBreak(float breakForce) + { + if (onJointBreak != null) onJointBreak.OnNext(breakForce); + } + + public IObservable OnJointBreakAsObservable() + { + return onJointBreak ?? (onJointBreak = new Subject()); + } + + + Subject onJointBreak2D; + + void OnJointBreak2D(Joint2D brokenJoint) + { + if (onJointBreak2D != null) onJointBreak2D.OnNext(brokenJoint); + } + + public IObservable OnJointBreak2DAsObservable() + { + return onJointBreak2D ?? (onJointBreak2D = new Subject()); + } + + + protected override void RaiseOnCompletedOnDestroy() + { + if (onJointBreak != null) + { + onJointBreak.OnCompleted(); + } + if (onJointBreak2D != null) + { + onJointBreak2D.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs.meta new file mode 100644 index 00000000..765bbcb5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableJointTrigger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79b758631951cbc42b40ea87072e1ab3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs new file mode 100644 index 00000000..74eda99b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs @@ -0,0 +1,31 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableLateUpdateTrigger : ObservableTriggerBase + { + Subject lateUpdate; + + /// LateUpdate is called every frame, if the Behaviour is enabled. + void LateUpdate() + { + if (lateUpdate != null) lateUpdate.OnNext(Unit.Default); + } + + /// LateUpdate is called every frame, if the Behaviour is enabled. + public IObservable LateUpdateAsObservable() + { + return lateUpdate ?? (lateUpdate = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (lateUpdate != null) + { + lateUpdate.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs.meta new file mode 100644 index 00000000..bbdbf704 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableLateUpdateTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 176ace24965d0c744bc61c8aad8b3fc7 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs new file mode 100644 index 00000000..17ad9089 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs @@ -0,0 +1,143 @@ +#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO) + +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableMouseTrigger : ObservableTriggerBase + { + Subject onMouseDown; + + /// OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. + void OnMouseDown() + { + if (onMouseDown != null) onMouseDown.OnNext(Unit.Default); + } + + /// OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. + public IObservable OnMouseDownAsObservable() + { + return onMouseDown ?? (onMouseDown = new Subject()); + } + + Subject onMouseDrag; + + /// OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. + void OnMouseDrag() + { + if (onMouseDrag != null) onMouseDrag.OnNext(Unit.Default); + } + + /// OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. + public IObservable OnMouseDragAsObservable() + { + return onMouseDrag ?? (onMouseDrag = new Subject()); + } + + Subject onMouseEnter; + + /// OnMouseEnter is called when the mouse entered the GUIElement or Collider. + void OnMouseEnter() + { + if (onMouseEnter != null) onMouseEnter.OnNext(Unit.Default); + } + + /// OnMouseEnter is called when the mouse entered the GUIElement or Collider. + public IObservable OnMouseEnterAsObservable() + { + return onMouseEnter ?? (onMouseEnter = new Subject()); + } + + Subject onMouseExit; + + /// OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider. + void OnMouseExit() + { + if (onMouseExit != null) onMouseExit.OnNext(Unit.Default); + } + + /// OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider. + public IObservable OnMouseExitAsObservable() + { + return onMouseExit ?? (onMouseExit = new Subject()); + } + + Subject onMouseOver; + + /// OnMouseOver is called every frame while the mouse is over the GUIElement or Collider. + void OnMouseOver() + { + if (onMouseOver != null) onMouseOver.OnNext(Unit.Default); + } + + /// OnMouseOver is called every frame while the mouse is over the GUIElement or Collider. + public IObservable OnMouseOverAsObservable() + { + return onMouseOver ?? (onMouseOver = new Subject()); + } + + Subject onMouseUp; + + /// OnMouseUp is called when the user has released the mouse button. + void OnMouseUp() + { + if (onMouseUp != null) onMouseUp.OnNext(Unit.Default); + } + + /// OnMouseUp is called when the user has released the mouse button. + public IObservable OnMouseUpAsObservable() + { + return onMouseUp ?? (onMouseUp = new Subject()); + } + + Subject onMouseUpAsButton; + + /// OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. + void OnMouseUpAsButton() + { + if (onMouseUpAsButton != null) onMouseUpAsButton.OnNext(Unit.Default); + } + + /// OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. + public IObservable OnMouseUpAsButtonAsObservable() + { + return onMouseUpAsButton ?? (onMouseUpAsButton = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onMouseDown != null) + { + onMouseDown.OnCompleted(); + } + if (onMouseDrag != null) + { + onMouseDrag.OnCompleted(); + } + if (onMouseEnter != null) + { + onMouseEnter.OnCompleted(); + } + if (onMouseExit != null) + { + onMouseExit.OnCompleted(); + } + if (onMouseOver != null) + { + onMouseOver.OnCompleted(); + } + if (onMouseUp != null) + { + onMouseUp.OnCompleted(); + } + if (onMouseUpAsButton != null) + { + onMouseUpAsButton.OnCompleted(); + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs.meta new file mode 100644 index 00000000..4cf6b662 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMouseTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c5f30958c5509bc4f9c14ea261a1567c +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs new file mode 100644 index 00000000..583b2c04 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableMoveTrigger : ObservableTriggerBase, IEventSystemHandler, IMoveHandler + { + Subject onMove; + + void IMoveHandler.OnMove(AxisEventData eventData) + { + if (onMove != null) onMove.OnNext(eventData); + } + + public IObservable OnMoveAsObservable() + { + return onMove ?? (onMove = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onMove != null) + { + onMove.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs.meta new file mode 100644 index 00000000..e293de73 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableMoveTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3e1feec0f10dcea4d9c779a81a0ee3dc +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs new file mode 100644 index 00000000..eda1eb7e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs @@ -0,0 +1,56 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableParticleTrigger : ObservableTriggerBase + { + Subject onParticleCollision; +#if UNITY_5_4_OR_NEWER + Subject onParticleTrigger; +#endif + + /// OnParticleCollision is called when a particle hits a collider. + void OnParticleCollision(GameObject other) + { + if (onParticleCollision != null) onParticleCollision.OnNext(other); + } + + /// OnParticleCollision is called when a particle hits a collider. + public IObservable OnParticleCollisionAsObservable() + { + return onParticleCollision ?? (onParticleCollision = new Subject()); + } + +#if UNITY_5_4_OR_NEWER + + /// OnParticleTrigger is called when any particles in a particle system meet the conditions in the trigger module. + void OnParticleTrigger() + { + if (onParticleTrigger != null) onParticleTrigger.OnNext(Unit.Default); + } + + /// OnParticleTrigger is called when any particles in a particle system meet the conditions in the trigger module. + public IObservable OnParticleTriggerAsObservable() + { + return onParticleTrigger ?? (onParticleTrigger = new Subject()); + } + +#endif + + protected override void RaiseOnCompletedOnDestroy() + { + if (onParticleCollision != null) + { + onParticleCollision.OnCompleted(); + } +#if UNITY_5_4_OR_NEWER + if (onParticleTrigger != null) + { + onParticleTrigger.OnCompleted(); + } +#endif + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs.meta new file mode 100644 index 00000000..4e68d795 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableParticleTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9e6a20494274d5045a1b36a770ea76b4 +timeCreated: 1468669952 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs new file mode 100644 index 00000000..339d4f1d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservablePointerClickTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerClickHandler + { + Subject onPointerClick; + + void IPointerClickHandler.OnPointerClick(PointerEventData eventData) + { + if (onPointerClick != null) onPointerClick.OnNext(eventData); + } + + public IObservable OnPointerClickAsObservable() + { + return onPointerClick ?? (onPointerClick = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onPointerClick != null) + { + onPointerClick.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs.meta new file mode 100644 index 00000000..74f89878 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerClickTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: aa69c313aba23f945b760e79c45083ad +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs new file mode 100644 index 00000000..79668610 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservablePointerDownTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerDownHandler + { + Subject onPointerDown; + + void IPointerDownHandler.OnPointerDown(PointerEventData eventData) + { + if (onPointerDown != null) onPointerDown.OnNext(eventData); + } + + public IObservable OnPointerDownAsObservable() + { + return onPointerDown ?? (onPointerDown = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onPointerDown != null) + { + onPointerDown.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs.meta new file mode 100644 index 00000000..682f0474 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerDownTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c7ae5b5965df2344d99ef7792521b937 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs new file mode 100644 index 00000000..7859f249 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservablePointerEnterTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerEnterHandler + { + Subject onPointerEnter; + + void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData) + { + if (onPointerEnter != null) onPointerEnter.OnNext(eventData); + } + + public IObservable OnPointerEnterAsObservable() + { + return onPointerEnter ?? (onPointerEnter = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onPointerEnter != null) + { + onPointerEnter.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs.meta new file mode 100644 index 00000000..323e047d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerEnterTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3468b3db8d419c745b12124f6432696b +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs new file mode 100644 index 00000000..dfa22497 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservablePointerExitTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerExitHandler + { + Subject onPointerExit; + + void IPointerExitHandler.OnPointerExit(PointerEventData eventData) + { + if (onPointerExit != null) onPointerExit.OnNext(eventData); + } + + public IObservable OnPointerExitAsObservable() + { + return onPointerExit ?? (onPointerExit = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onPointerExit != null) + { + onPointerExit.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs.meta new file mode 100644 index 00000000..95b0afb9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerExitTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9643e74593988274bbed9adf40384e48 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs new file mode 100644 index 00000000..2156713e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservablePointerUpTrigger : ObservableTriggerBase, IEventSystemHandler, IPointerUpHandler + { + Subject onPointerUp; + + void IPointerUpHandler.OnPointerUp(PointerEventData eventData) + { + if (onPointerUp != null) onPointerUp.OnNext(eventData); + } + + public IObservable OnPointerUpAsObservable() + { + return onPointerUp ?? (onPointerUp = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onPointerUp != null) + { + onPointerUp.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs.meta new file mode 100644 index 00000000..86d7c182 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservablePointerUpTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 41b0031b2e409894aacafa49d8583617 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs new file mode 100644 index 00000000..cb23d8d4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs @@ -0,0 +1,55 @@ +// after uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableRectTransformTrigger : ObservableTriggerBase + { + Subject onRectTransformDimensionsChange; + + // Callback that is sent if an associated RectTransform has it's dimensions changed + void OnRectTransformDimensionsChange() + { + if (onRectTransformDimensionsChange != null) onRectTransformDimensionsChange.OnNext(Unit.Default); + } + + /// Callback that is sent if an associated RectTransform has it's dimensions changed. + public IObservable OnRectTransformDimensionsChangeAsObservable() + { + return onRectTransformDimensionsChange ?? (onRectTransformDimensionsChange = new Subject()); + } + + Subject onRectTransformRemoved; + + // Callback that is sent if an associated RectTransform is removed + void OnRectTransformRemoved() + { + if (onRectTransformRemoved != null) onRectTransformRemoved.OnNext(Unit.Default); + } + + /// Callback that is sent if an associated RectTransform is removed. + public IObservable OnRectTransformRemovedAsObservable() + { + return onRectTransformRemoved ?? (onRectTransformRemoved = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onRectTransformDimensionsChange != null) + { + onRectTransformDimensionsChange.OnCompleted(); + } + if (onRectTransformRemoved != null) + { + onRectTransformRemoved.OnCompleted(); + } + } + + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs.meta new file mode 100644 index 00000000..21d70420 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableRectTransformTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 20b97bcdd98f27346851c3a690ec7faf +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs new file mode 100644 index 00000000..33573e5e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableScrollTrigger : ObservableTriggerBase, IEventSystemHandler, IScrollHandler + { + Subject onScroll; + + void IScrollHandler.OnScroll(PointerEventData eventData) + { + if (onScroll != null) onScroll.OnNext(eventData); + } + + public IObservable OnScrollAsObservable() + { + return onScroll ?? (onScroll = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onScroll != null) + { + onScroll.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs.meta new file mode 100644 index 00000000..e014f677 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableScrollTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2231ec04e488f7443ae7acf609ac5f00 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs new file mode 100644 index 00000000..9f4a3492 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableSelectTrigger : ObservableTriggerBase, IEventSystemHandler, ISelectHandler + { + Subject onSelect; + + void ISelectHandler.OnSelect(BaseEventData eventData) + { + if (onSelect != null) onSelect.OnNext(eventData); + } + + public IObservable OnSelectAsObservable() + { + return onSelect ?? (onSelect = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onSelect != null) + { + onSelect.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs.meta new file mode 100644 index 00000000..c3e66fc8 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSelectTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1e4cb287d3ab8274885ed05748f26329 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs new file mode 100644 index 00000000..26e7e1fd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs @@ -0,0 +1,143 @@ +// over Unity5 added StateMachineBehaviour +#if !(UNITY_4_7 || UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 || UNITY_4_2 || UNITY_4_1 || UNITY_4_0_1 || UNITY_4_0 || UNITY_3_5 || UNITY_3_4 || UNITY_3_3 || UNITY_3_2 || UNITY_3_1 || UNITY_3_0_0 || UNITY_3_0 || UNITY_2_6_1 || UNITY_2_6) + +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableStateMachineTrigger : StateMachineBehaviour + { + public class OnStateInfo + { + public Animator Animator { get; private set; } + public AnimatorStateInfo StateInfo { get; private set; } + public int LayerIndex { get; private set; } + + public OnStateInfo(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + Animator = animator; + StateInfo = stateInfo; + LayerIndex = layerIndex; + } + } + + public class OnStateMachineInfo + { + public Animator Animator { get; private set; } + public int StateMachinePathHash { get; private set; } + + public OnStateMachineInfo(Animator animator, int stateMachinePathHash) + { + Animator = animator; + StateMachinePathHash = stateMachinePathHash; + } + } + + // OnStateExit + + Subject onStateExit; + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (onStateExit != null) onStateExit.OnNext(new OnStateInfo(animator, stateInfo, layerIndex)); + } + + public IObservable OnStateExitAsObservable() + { + return onStateExit ?? (onStateExit = new Subject()); + } + + // OnStateEnter + + Subject onStateEnter; + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (onStateEnter != null) onStateEnter.OnNext(new OnStateInfo(animator, stateInfo, layerIndex)); + } + + public IObservable OnStateEnterAsObservable() + { + return onStateEnter ?? (onStateEnter = new Subject()); + } + + // OnStateIK + + Subject onStateIK; + + public override void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if(onStateIK !=null) onStateIK.OnNext(new OnStateInfo(animator, stateInfo, layerIndex)); + } + + public IObservable OnStateIKAsObservable() + { + return onStateIK ?? (onStateIK = new Subject()); + } + + // Does not implments OnStateMove. + // ObservableStateMachine Trigger makes stop animating. + // By defining OnAnimatorMove, you are signifying that you want to intercept the movement of the root object and apply it yourself. + // http://fogbugz.unity3d.com/default.asp?700990_9jqaim4ev33i8e9h + + //// OnStateMove + + //Subject onStateMove; + + //public override void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + //{ + // if (onStateMove != null) onStateMove.OnNext(new OnStateInfo(animator, stateInfo, layerIndex)); + //} + + //public IObservable OnStateMoveAsObservable() + //{ + // return onStateMove ?? (onStateMove = new Subject()); + //} + + // OnStateUpdate + + Subject onStateUpdate; + + public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (onStateUpdate != null) onStateUpdate.OnNext(new OnStateInfo(animator, stateInfo, layerIndex)); + } + + public IObservable OnStateUpdateAsObservable() + { + return onStateUpdate ?? (onStateUpdate = new Subject()); + } + + // OnStateMachineEnter + + Subject onStateMachineEnter; + + public override void OnStateMachineEnter(Animator animator, int stateMachinePathHash) + { + if (onStateMachineEnter != null) onStateMachineEnter.OnNext(new OnStateMachineInfo(animator, stateMachinePathHash)); + } + + public IObservable OnStateMachineEnterAsObservable() + { + return onStateMachineEnter ?? (onStateMachineEnter = new Subject()); + } + + // OnStateMachineExit + + Subject onStateMachineExit; + + public override void OnStateMachineExit(Animator animator, int stateMachinePathHash) + { + if (onStateMachineExit != null) onStateMachineExit.OnNext(new OnStateMachineInfo(animator, stateMachinePathHash)); + } + + public IObservable OnStateMachineExitAsObservable() + { + return onStateMachineExit ?? (onStateMachineExit = new Subject()); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs.meta new file mode 100644 index 00000000..ce2bb361 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableStateMachineTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1e29959e46c7ea7409560769cde085ae +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs new file mode 100644 index 00000000..fe5b8fe6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableSubmitTrigger : ObservableTriggerBase, IEventSystemHandler, ISubmitHandler + { + Subject onSubmit; + + void ISubmitHandler.OnSubmit(BaseEventData eventData) + { + if (onSubmit != null) onSubmit.OnNext(eventData); + } + + public IObservable OnSubmitAsObservable() + { + return onSubmit ?? (onSubmit = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onSubmit != null) + { + onSubmit.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs.meta new file mode 100644 index 00000000..c983c1a7 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableSubmitTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 655296fedabd6004ab699ab9749e369c +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs new file mode 100644 index 00000000..a51e9c3d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs @@ -0,0 +1,72 @@ +// after uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableTransformChangedTrigger : ObservableTriggerBase + { + Subject onBeforeTransformParentChanged; + + // Callback sent to the graphic before a Transform parent change occurs + void OnBeforeTransformParentChanged() + { + if (onBeforeTransformParentChanged != null) onBeforeTransformParentChanged.OnNext(Unit.Default); + } + + /// Callback sent to the graphic before a Transform parent change occurs. + public IObservable OnBeforeTransformParentChangedAsObservable() + { + return onBeforeTransformParentChanged ?? (onBeforeTransformParentChanged = new Subject()); + } + + Subject onTransformParentChanged; + + // This function is called when the parent property of the transform of the GameObject has changed + void OnTransformParentChanged() + { + if (onTransformParentChanged != null) onTransformParentChanged.OnNext(Unit.Default); + } + + /// This function is called when the parent property of the transform of the GameObject has changed. + public IObservable OnTransformParentChangedAsObservable() + { + return onTransformParentChanged ?? (onTransformParentChanged = new Subject()); + } + + Subject onTransformChildrenChanged; + + // This function is called when the list of children of the transform of the GameObject has changed + void OnTransformChildrenChanged() + { + if (onTransformChildrenChanged != null) onTransformChildrenChanged.OnNext(Unit.Default); + } + + /// This function is called when the list of children of the transform of the GameObject has changed. + public IObservable OnTransformChildrenChangedAsObservable() + { + return onTransformChildrenChanged ?? (onTransformChildrenChanged = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onBeforeTransformParentChanged != null) + { + onBeforeTransformParentChanged.OnCompleted(); + } + if (onTransformParentChanged != null) + { + onTransformParentChanged.OnCompleted(); + } + if (onTransformChildrenChanged != null) + { + onTransformChildrenChanged.OnCompleted(); + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs.meta new file mode 100644 index 00000000..0ac861cd --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTransformChangedTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 835e244a602942c4c84a09c9bdedf229 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs new file mode 100644 index 00000000..567421d5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs @@ -0,0 +1,67 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableTrigger2DTrigger : ObservableTriggerBase + { + Subject onTriggerEnter2D; + + /// Sent when another object enters a trigger collider attached to this object (2D physics only). + void OnTriggerEnter2D(Collider2D other) + { + if (onTriggerEnter2D != null) onTriggerEnter2D.OnNext(other); + } + + /// Sent when another object enters a trigger collider attached to this object (2D physics only). + public IObservable OnTriggerEnter2DAsObservable() + { + return onTriggerEnter2D ?? (onTriggerEnter2D = new Subject()); + } + + Subject onTriggerExit2D; + + /// Sent when another object leaves a trigger collider attached to this object (2D physics only). + void OnTriggerExit2D(Collider2D other) + { + if (onTriggerExit2D != null) onTriggerExit2D.OnNext(other); + } + + /// Sent when another object leaves a trigger collider attached to this object (2D physics only). + public IObservable OnTriggerExit2DAsObservable() + { + return onTriggerExit2D ?? (onTriggerExit2D = new Subject()); + } + + Subject onTriggerStay2D; + + /// Sent each frame where another object is within a trigger collider attached to this object (2D physics only). + void OnTriggerStay2D(Collider2D other) + { + if (onTriggerStay2D != null) onTriggerStay2D.OnNext(other); + } + + /// Sent each frame where another object is within a trigger collider attached to this object (2D physics only). + public IObservable OnTriggerStay2DAsObservable() + { + return onTriggerStay2D ?? (onTriggerStay2D = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onTriggerEnter2D != null) + { + onTriggerEnter2D.OnCompleted(); + } + if (onTriggerExit2D != null) + { + onTriggerExit2D.OnCompleted(); + } + if (onTriggerStay2D != null) + { + onTriggerStay2D.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs.meta new file mode 100644 index 00000000..a8855046 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTrigger2DTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1aad3129752ef804999a880a7b2d72ef +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs new file mode 100644 index 00000000..50bf742e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs @@ -0,0 +1,65 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + public abstract class ObservableTriggerBase : MonoBehaviour + { + bool calledAwake = false; + Subject awake; + + /// Awake is called when the script instance is being loaded. + void Awake() + { + calledAwake = true; + if (awake != null) { awake.OnNext(Unit.Default); awake.OnCompleted(); } + } + + /// Awake is called when the script instance is being loaded. + public IObservable AwakeAsObservable() + { + if (calledAwake) return Observable.Return(Unit.Default); + return awake ?? (awake = new Subject()); + } + + bool calledStart = false; + Subject start; + + /// Start is called on the frame when a script is enabled just before any of the Update methods is called the first time. + void Start() + { + calledStart = true; + if (start != null) { start.OnNext(Unit.Default); start.OnCompleted(); } + } + + /// Start is called on the frame when a script is enabled just before any of the Update methods is called the first time. + public IObservable StartAsObservable() + { + if (calledStart) return Observable.Return(Unit.Default); + return start ?? (start = new Subject()); + } + + + bool calledDestroy = false; + Subject onDestroy; + + /// This function is called when the MonoBehaviour will be destroyed. + void OnDestroy() + { + calledDestroy = true; + if (onDestroy != null) { onDestroy.OnNext(Unit.Default); onDestroy.OnCompleted(); } + + RaiseOnCompletedOnDestroy(); + } + + /// This function is called when the MonoBehaviour will be destroyed. + public IObservable OnDestroyAsObservable() + { + if (this == null) return Observable.Return(Unit.Default); + if (calledDestroy) return Observable.Return(Unit.Default); + return onDestroy ?? (onDestroy = new Subject()); + } + + protected abstract void RaiseOnCompletedOnDestroy(); + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs.meta new file mode 100644 index 00000000..9857d04d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 850bc951297608e4fb0722795c21ed16 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs new file mode 100644 index 00000000..bdb7b2c4 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs @@ -0,0 +1,461 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) +using UnityEngine.EventSystems; +#endif + +namespace UniRx.Triggers +{ + // for Component + public static partial class ObservableTriggerExtensions + { + #region ObservableAnimatorTrigger + + /// Callback for setting up animation IK (inverse kinematics). + public static IObservable OnAnimatorIKAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnAnimatorIKAsObservable(); + } + + /// Callback for processing animation movements for modifying root motion. + public static IObservable OnAnimatorMoveAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnAnimatorMoveAsObservable(); + } + + #endregion + + #region ObservableCollision2DTrigger + + /// Sent when an incoming collider makes contact with this object's collider (2D physics only). + public static IObservable OnCollisionEnter2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionEnter2DAsObservable(); + } + + + /// Sent when a collider on another object stops touching this object's collider (2D physics only). + public static IObservable OnCollisionExit2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionExit2DAsObservable(); + } + + /// Sent each frame where a collider on another object is touching this object's collider (2D physics only). + public static IObservable OnCollisionStay2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionStay2DAsObservable(); + } + + #endregion + + #region ObservableCollisionTrigger + + /// OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. + public static IObservable OnCollisionEnterAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionEnterAsObservable(); + } + + + /// OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider. + public static IObservable OnCollisionExitAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionExitAsObservable(); + } + + /// OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. + public static IObservable OnCollisionStayAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCollisionStayAsObservable(); + } + + #endregion + + #region ObservableDestroyTrigger + + /// This function is called when the MonoBehaviour will be destroyed. + public static IObservable OnDestroyAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Return(Unit.Default); // send destroy message + return GetOrAddComponent(component.gameObject).OnDestroyAsObservable(); + } + + #endregion + + + #region ObservableEnableTrigger + + /// This function is called when the object becomes enabled and active. + public static IObservable OnEnableAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnEnableAsObservable(); + } + + /// This function is called when the behaviour becomes disabled () or inactive. + public static IObservable OnDisableAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnDisableAsObservable(); + } + + #endregion + + #region ObservableFixedUpdateTrigger + + /// This function is called every fixed framerate frame, if the MonoBehaviour is enabled. + public static IObservable FixedUpdateAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).FixedUpdateAsObservable(); + } + + #endregion + + #region ObservableLateUpdateTrigger + + /// LateUpdate is called every frame, if the Behaviour is enabled. + public static IObservable LateUpdateAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).LateUpdateAsObservable(); + } + + #endregion + +#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO) + + #region ObservableMouseTrigger + + /// OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. + public static IObservable OnMouseDownAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseDownAsObservable(); + } + + /// OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. + public static IObservable OnMouseDragAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseDragAsObservable(); + } + + /// OnMouseEnter is called when the mouse entered the GUIElement or Collider. + public static IObservable OnMouseEnterAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseEnterAsObservable(); + } + + /// OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider. + public static IObservable OnMouseExitAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseExitAsObservable(); + } + + /// OnMouseOver is called every frame while the mouse is over the GUIElement or Collider. + public static IObservable OnMouseOverAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseOverAsObservable(); + } + + /// OnMouseUp is called when the user has released the mouse button. + public static IObservable OnMouseUpAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseUpAsObservable(); + } + + /// OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. + public static IObservable OnMouseUpAsButtonAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMouseUpAsButtonAsObservable(); + } + + #endregion + +#endif + + #region ObservableTrigger2DTrigger + + /// Sent when another object enters a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerEnter2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerEnter2DAsObservable(); + } + + + /// Sent when another object leaves a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerExit2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerExit2DAsObservable(); + } + + /// Sent each frame where another object is within a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerStay2DAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerStay2DAsObservable(); + } + + #endregion + + #region ObservableTriggerTrigger + + /// OnTriggerEnter is called when the Collider other enters the trigger. + public static IObservable OnTriggerEnterAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerEnterAsObservable(); + } + + + /// OnTriggerExit is called when the Collider other has stopped touching the trigger. + public static IObservable OnTriggerExitAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerExitAsObservable(); + } + + /// OnTriggerStay is called once per frame for every Collider other that is touching the trigger. + public static IObservable OnTriggerStayAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTriggerStayAsObservable(); + } + + #endregion + + #region ObservableUpdateTrigger + + /// Update is called every frame, if the MonoBehaviour is enabled. + public static IObservable UpdateAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).UpdateAsObservable(); + } + + #endregion + + #region ObservableVisibleTrigger + + /// OnBecameInvisible is called when the renderer is no longer visible by any camera. + public static IObservable OnBecameInvisibleAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnBecameInvisibleAsObservable(); + } + + /// OnBecameVisible is called when the renderer became visible by any camera. + public static IObservable OnBecameVisibleAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnBecameVisibleAsObservable(); + } + + #endregion + +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + + #region ObservableTransformChangedTrigger + + /// Callback sent to the graphic before a Transform parent change occurs. + public static IObservable OnBeforeTransformParentChangedAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnBeforeTransformParentChangedAsObservable(); + } + + /// This function is called when the parent property of the transform of the GameObject has changed. + public static IObservable OnTransformParentChangedAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTransformParentChangedAsObservable(); + } + + /// This function is called when the list of children of the transform of the GameObject has changed. + public static IObservable OnTransformChildrenChangedAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnTransformChildrenChangedAsObservable(); + } + + #endregion + + #region ObservableCanvasGroupChangedTrigger + + /// Callback that is sent if the canvas group is changed. + public static IObservable OnCanvasGroupChangedAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCanvasGroupChangedAsObservable(); + } + + #endregion + + #region ObservableRectTransformTrigger + + /// Callback that is sent if an associated RectTransform has it's dimensions changed. + public static IObservable OnRectTransformDimensionsChangeAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnRectTransformDimensionsChangeAsObservable(); + } + + /// Callback that is sent if an associated RectTransform is removed. + public static IObservable OnRectTransformRemovedAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnRectTransformRemovedAsObservable(); + } + + #endregion + + // uGUI + + #region ObservableEventTrigger classes + + public static IObservable OnDeselectAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnDeselectAsObservable(); + } + + public static IObservable OnMoveAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnMoveAsObservable(); + } + + public static IObservable OnPointerDownAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnPointerDownAsObservable(); + } + + public static IObservable OnPointerEnterAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnPointerEnterAsObservable(); + } + + public static IObservable OnPointerExitAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnPointerExitAsObservable(); + } + + public static IObservable OnPointerUpAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnPointerUpAsObservable(); + } + + public static IObservable OnSelectAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnSelectAsObservable(); + } + + public static IObservable OnPointerClickAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnPointerClickAsObservable(); + } + + public static IObservable OnSubmitAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnSubmitAsObservable(); + } + + public static IObservable OnDragAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnDragAsObservable(); + } + + public static IObservable OnBeginDragAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnBeginDragAsObservable(); + } + + public static IObservable OnEndDragAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnEndDragAsObservable(); + } + + public static IObservable OnDropAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnDropAsObservable(); + } + + public static IObservable OnUpdateSelectedAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnUpdateSelectedAsObservable(); + } + + public static IObservable OnInitializePotentialDragAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnInitializePotentialDragAsObservable(); + } + + public static IObservable OnCancelAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnCancelAsObservable(); + } + + public static IObservable OnScrollAsObservable(this UIBehaviour component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnScrollAsObservable(); + } + + #endregion + +#endif + + #region ObservableParticleTrigger + + /// OnParticleCollision is called when a particle hits a collider. + public static IObservable OnParticleCollisionAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnParticleCollisionAsObservable(); + } + +#if UNITY_5_4_OR_NEWER + + /// OnParticleTrigger is called when any particles in a particle system meet the conditions in the trigger module. + public static IObservable OnParticleTriggerAsObservable(this Component component) + { + if (component == null || component.gameObject == null) return Observable.Empty(); + return GetOrAddComponent(component.gameObject).OnParticleTriggerAsObservable(); + } + +#endif + + #endregion + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs.meta new file mode 100644 index 00000000..1dec345e --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.Component.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d10150b3ca6f3924baae5bce4343f6c4 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs new file mode 100644 index 00000000..82ba7185 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs @@ -0,0 +1,361 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + // for GameObject + public static partial class ObservableTriggerExtensions + { + #region ObservableAnimatorTrigger + + /// Callback for setting up animation IK (inverse kinematics). + public static IObservable OnAnimatorIKAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnAnimatorIKAsObservable(); + } + + /// Callback for processing animation movements for modifying root motion. + public static IObservable OnAnimatorMoveAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnAnimatorMoveAsObservable(); + } + + #endregion + + #region ObservableCollision2DTrigger + + /// Sent when an incoming collider makes contact with this object's collider (2D physics only). + public static IObservable OnCollisionEnter2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionEnter2DAsObservable(); + } + + + /// Sent when a collider on another object stops touching this object's collider (2D physics only). + public static IObservable OnCollisionExit2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionExit2DAsObservable(); + } + + /// Sent each frame where a collider on another object is touching this object's collider (2D physics only). + public static IObservable OnCollisionStay2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionStay2DAsObservable(); + } + + #endregion + + #region ObservableCollisionTrigger + + /// OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. + public static IObservable OnCollisionEnterAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionEnterAsObservable(); + } + + + /// OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider. + public static IObservable OnCollisionExitAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionExitAsObservable(); + } + + /// OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. + public static IObservable OnCollisionStayAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCollisionStayAsObservable(); + } + + #endregion + + #region ObservableDestroyTrigger + + /// This function is called when the MonoBehaviour will be destroyed. + public static IObservable OnDestroyAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Return(Unit.Default); // send destroy message + return GetOrAddComponent(gameObject).OnDestroyAsObservable(); + } + + #endregion + + + #region ObservableEnableTrigger + + /// This function is called when the object becomes enabled and active. + public static IObservable OnEnableAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnEnableAsObservable(); + } + + /// This function is called when the behaviour becomes disabled () or inactive. + public static IObservable OnDisableAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnDisableAsObservable(); + } + + #endregion + + #region ObservableFixedUpdateTrigger + + /// This function is called every fixed framerate frame, if the MonoBehaviour is enabled. + public static IObservable FixedUpdateAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).FixedUpdateAsObservable(); + } + + #endregion + + #region ObservableLateUpdateTrigger + + /// LateUpdate is called every frame, if the Behaviour is enabled. + public static IObservable LateUpdateAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).LateUpdateAsObservable(); + } + + #endregion + +#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO) + + #region ObservableMouseTrigger + + /// OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. + public static IObservable OnMouseDownAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseDownAsObservable(); + } + + /// OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. + public static IObservable OnMouseDragAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseDragAsObservable(); + } + + /// OnMouseEnter is called when the mouse entered the GUIElement or Collider. + public static IObservable OnMouseEnterAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseEnterAsObservable(); + } + + /// OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider. + public static IObservable OnMouseExitAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseExitAsObservable(); + } + + /// OnMouseOver is called every frame while the mouse is over the GUIElement or Collider. + public static IObservable OnMouseOverAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseOverAsObservable(); + } + + /// OnMouseUp is called when the user has released the mouse button. + public static IObservable OnMouseUpAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseUpAsObservable(); + } + + /// OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. + public static IObservable OnMouseUpAsButtonAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnMouseUpAsButtonAsObservable(); + } + + #endregion + +#endif + + #region ObservableTrigger2DTrigger + + /// Sent when another object enters a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerEnter2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerEnter2DAsObservable(); + } + + + /// Sent when another object leaves a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerExit2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerExit2DAsObservable(); + } + + /// Sent each frame where another object is within a trigger collider attached to this object (2D physics only). + public static IObservable OnTriggerStay2DAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerStay2DAsObservable(); + } + + #endregion + + #region ObservableTriggerTrigger + + /// OnTriggerEnter is called when the Collider other enters the trigger. + public static IObservable OnTriggerEnterAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerEnterAsObservable(); + } + + + /// OnTriggerExit is called when the Collider other has stopped touching the trigger. + public static IObservable OnTriggerExitAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerExitAsObservable(); + } + + /// OnTriggerStay is called once per frame for every Collider other that is touching the trigger. + public static IObservable OnTriggerStayAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTriggerStayAsObservable(); + } + + #endregion + + #region ObservableUpdateTrigger + + /// Update is called every frame, if the MonoBehaviour is enabled. + public static IObservable UpdateAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).UpdateAsObservable(); + } + + #endregion + + #region ObservableVisibleTrigger + + /// OnBecameInvisible is called when the renderer is no longer visible by any camera. + public static IObservable OnBecameInvisibleAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnBecameInvisibleAsObservable(); + } + + /// OnBecameVisible is called when the renderer became visible by any camera. + public static IObservable OnBecameVisibleAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnBecameVisibleAsObservable(); + } + + #endregion + +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + + #region ObservableTransformChangedTrigger + + /// Callback sent to the graphic before a Transform parent change occurs. + public static IObservable OnBeforeTransformParentChangedAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnBeforeTransformParentChangedAsObservable(); + } + + /// This function is called when the parent property of the transform of the GameObject has changed. + public static IObservable OnTransformParentChangedAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTransformParentChangedAsObservable(); + } + + /// This function is called when the list of children of the transform of the GameObject has changed. + public static IObservable OnTransformChildrenChangedAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnTransformChildrenChangedAsObservable(); + } + + #endregion + + #region ObservableCanvasGroupChangedTrigger + + /// Callback that is sent if the canvas group is changed. + public static IObservable OnCanvasGroupChangedAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnCanvasGroupChangedAsObservable(); + } + + #endregion + + #region ObservableRectTransformTrigger + + /// Callback that is sent if an associated RectTransform has it's dimensions changed. + public static IObservable OnRectTransformDimensionsChangeAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnRectTransformDimensionsChangeAsObservable(); + } + + /// Callback that is sent if an associated RectTransform is removed. + public static IObservable OnRectTransformRemovedAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnRectTransformRemovedAsObservable(); + } + + #endregion +#endif + + #region ObservableParticleTrigger + + /// OnParticleCollision is called when a particle hits a collider. + public static IObservable OnParticleCollisionAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnParticleCollisionAsObservable(); + } + +#if UNITY_5_4_OR_NEWER + + /// OnParticleTrigger is called when any particles in a particle system meet the conditions in the trigger module. + public static IObservable OnParticleTriggerAsObservable(this GameObject gameObject) + { + if (gameObject == null) return Observable.Empty(); + return GetOrAddComponent(gameObject).OnParticleTriggerAsObservable(); + } + +#endif + + #endregion + + + static T GetOrAddComponent(GameObject gameObject) + where T : Component + { + var component = gameObject.GetComponent(); + if (component == null) + { + component = gameObject.AddComponent(); + } + + return component; + } + } +} diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs.meta new file mode 100644 index 00000000..24a681c9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3ee4df960144b9042874516111cf2d6c +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs new file mode 100644 index 00000000..93714171 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs @@ -0,0 +1,67 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableTriggerTrigger : ObservableTriggerBase + { + Subject onTriggerEnter; + + /// OnTriggerEnter is called when the Collider other enters the trigger. + void OnTriggerEnter(Collider other) + { + if (onTriggerEnter != null) onTriggerEnter.OnNext(other); + } + + /// OnTriggerEnter is called when the Collider other enters the trigger. + public IObservable OnTriggerEnterAsObservable() + { + return onTriggerEnter ?? (onTriggerEnter = new Subject()); + } + + Subject onTriggerExit; + + /// OnTriggerExit is called when the Collider other has stopped touching the trigger. + void OnTriggerExit(Collider other) + { + if (onTriggerExit != null) onTriggerExit.OnNext(other); + } + + /// OnTriggerExit is called when the Collider other has stopped touching the trigger. + public IObservable OnTriggerExitAsObservable() + { + return onTriggerExit ?? (onTriggerExit = new Subject()); + } + + Subject onTriggerStay; + + /// OnTriggerStay is called once per frame for every Collider other that is touching the trigger. + void OnTriggerStay(Collider other) + { + if (onTriggerStay != null) onTriggerStay.OnNext(other); + } + + /// OnTriggerStay is called once per frame for every Collider other that is touching the trigger. + public IObservable OnTriggerStayAsObservable() + { + return onTriggerStay ?? (onTriggerStay = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onTriggerEnter != null) + { + onTriggerEnter.OnCompleted(); + } + if (onTriggerExit != null) + { + onTriggerExit.OnCompleted(); + } + if (onTriggerStay != null) + { + onTriggerStay.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs.meta new file mode 100644 index 00000000..663f39ee --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableTriggerTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: cadcfd987fed8a044b75709fc19ad0f7 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs new file mode 100644 index 00000000..b15807f0 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs @@ -0,0 +1,36 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; // require keep for Windows Universal App +using UnityEngine; +using UnityEngine.EventSystems; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableUpdateSelectedTrigger : ObservableTriggerBase, IEventSystemHandler, IUpdateSelectedHandler + { + Subject onUpdateSelected; + + void IUpdateSelectedHandler.OnUpdateSelected(BaseEventData eventData) + { + if (onUpdateSelected != null) onUpdateSelected.OnNext(eventData); + } + + public IObservable OnUpdateSelectedAsObservable() + { + return onUpdateSelected ?? (onUpdateSelected = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onUpdateSelected != null) + { + onUpdateSelected.OnCompleted(); + } + } + } +} + + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs.meta new file mode 100644 index 00000000..52c3caef --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateSelectedTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4d207a04db328fd4d970c1457530deb3 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs new file mode 100644 index 00000000..86a40a3d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs @@ -0,0 +1,31 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableUpdateTrigger : ObservableTriggerBase + { + Subject update; + + /// Update is called every frame, if the MonoBehaviour is enabled. + void Update() + { + if (update != null) update.OnNext(Unit.Default); + } + + /// Update is called every frame, if the MonoBehaviour is enabled. + public IObservable UpdateAsObservable() + { + return update ?? (update = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (update != null) + { + update.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs.meta new file mode 100644 index 00000000..4ee9bc3d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableUpdateTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ceb5e5014f40d6948815a7be8b174ff2 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs new file mode 100644 index 00000000..4c6a5034 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs @@ -0,0 +1,49 @@ +using System; // require keep for Windows Universal App +using UnityEngine; + +namespace UniRx.Triggers +{ + [DisallowMultipleComponent] + public class ObservableVisibleTrigger : ObservableTriggerBase + { + Subject onBecameInvisible; + + /// OnBecameInvisible is called when the renderer is no longer visible by any camera. + void OnBecameInvisible() + { + if (onBecameInvisible != null) onBecameInvisible.OnNext(Unit.Default); + } + + /// OnBecameInvisible is called when the renderer is no longer visible by any camera. + public IObservable OnBecameInvisibleAsObservable() + { + return onBecameInvisible ?? (onBecameInvisible = new Subject()); + } + + Subject onBecameVisible; + + /// OnBecameVisible is called when the renderer became visible by any camera. + void OnBecameVisible() + { + if (onBecameVisible != null) onBecameVisible.OnNext(Unit.Default); + } + + /// OnBecameVisible is called when the renderer became visible by any camera. + public IObservable OnBecameVisibleAsObservable() + { + return onBecameVisible ?? (onBecameVisible = new Subject()); + } + + protected override void RaiseOnCompletedOnDestroy() + { + if (onBecameInvisible != null) + { + onBecameInvisible.OnCompleted(); + } + if (onBecameVisible != null) + { + onBecameVisible.OnCompleted(); + } + } + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs.meta new file mode 100644 index 00000000..9a4b336b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/Triggers/ObservableVisibleTrigger.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 03515121745b2d74c8782ce92eb2a1a0 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs new file mode 100644 index 00000000..56e0d0ba --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs @@ -0,0 +1,58 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine.Events; + +namespace UniRx +{ + public static partial class UnityEventExtensions + { + public static IObservable AsObservable(this UnityEngine.Events.UnityEvent unityEvent) + { + return Observable.FromEvent(h => new UnityAction(h), h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h)); + } + + public static IObservable AsObservable(this UnityEngine.Events.UnityEvent unityEvent) + { + return Observable.FromEvent, T>(h => new UnityAction(h), h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h)); + } + + public static IObservable> AsObservable(this UnityEngine.Events.UnityEvent unityEvent) + { + return Observable.FromEvent, Tuple>(h => + { + return new UnityAction((t0, t1) => + { + h(Tuple.Create(t0, t1)); + }); + }, h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h)); + } + + public static IObservable> AsObservable(this UnityEngine.Events.UnityEvent unityEvent) + { + return Observable.FromEvent, Tuple>(h => + { + return new UnityAction((t0, t1, t2) => + { + h(Tuple.Create(t0, t1, t2)); + }); + }, h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h)); + } + + public static IObservable> AsObservable(this UnityEngine.Events.UnityEvent unityEvent) + { + return Observable.FromEvent, Tuple>(h => + { + return new UnityAction((t0, t1, t2, t3) => + { + h(Tuple.Create(t0, t1, t2, t3)); + }); + }, h => unityEvent.AddListener(h), h => unityEvent.RemoveListener(h)); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs.meta new file mode 100644 index 00000000..766e4a9c --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityEventExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e3c4861cc04ac524484d0730a3a5bd4a +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs new file mode 100644 index 00000000..d8416f8f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs @@ -0,0 +1,44 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using UnityEngine.Events; +using UnityEngine.UI; + +namespace UniRx +{ + public static partial class UnityGraphicExtensions + { + public static IObservable DirtyLayoutCallbackAsObservable(this Graphic graphic) + { + return Observable.Create(observer => + { + UnityAction registerHandler = () => observer.OnNext(Unit.Default); + graphic.RegisterDirtyLayoutCallback(registerHandler); + return Disposable.Create(() => graphic.UnregisterDirtyLayoutCallback(registerHandler)); + }); + } + + public static IObservable DirtyMaterialCallbackAsObservable(this Graphic graphic) + { + return Observable.Create(observer => + { + UnityAction registerHandler = () => observer.OnNext(Unit.Default); + graphic.RegisterDirtyMaterialCallback(registerHandler); + return Disposable.Create(() => graphic.UnregisterDirtyMaterialCallback(registerHandler)); + }); + } + + public static IObservable DirtyVerticesCallbackAsObservable(this Graphic graphic) + { + return Observable.Create(observer => + { + UnityAction registerHandler = () => observer.OnNext(Unit.Default); + graphic.RegisterDirtyVerticesCallback(registerHandler); + return Disposable.Create(() => graphic.UnregisterDirtyVerticesCallback(registerHandler)); + }); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs.meta new file mode 100644 index 00000000..deacff22 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityGraphicExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 99be646df339108498ebb70efa1b7bd4 +timeCreated: 1455373900 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs new file mode 100644 index 00000000..cbbbe7f6 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs @@ -0,0 +1,123 @@ +// for uGUI(from 4.6) +#if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5) + +using System; +using UnityEngine; +using UnityEngine.UI; + +namespace UniRx +{ + public static partial class UnityUIComponentExtensions + { + public static IDisposable SubscribeToText(this IObservable source, Text text) + { + return source.SubscribeWithState(text, (x, t) => t.text = x); + } + + public static IDisposable SubscribeToText(this IObservable source, Text text) + { + return source.SubscribeWithState(text, (x, t) => t.text = x.ToString()); + } + + public static IDisposable SubscribeToText(this IObservable source, Text text, Func selector) + { + return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x)); + } + + public static IDisposable SubscribeToInteractable(this IObservable source, Selectable selectable) + { + return source.SubscribeWithState(selectable, (x, s) => s.interactable = x); + } + + /// Observe onClick event. + public static IObservable OnClickAsObservable(this Button button) + { + return button.onClick.AsObservable(); + } + + /// Observe onValueChanged with current `isOn` value on subscribe. + public static IObservable OnValueChangedAsObservable(this Toggle toggle) + { + // Optimized Defer + StartWith + return Observable.CreateWithState(toggle, (t, observer) => + { + observer.OnNext(t.isOn); + return t.onValueChanged.AsObservable().Subscribe(observer); + }); + } + + /// Observe onValueChanged with current `value` on subscribe. + public static IObservable OnValueChangedAsObservable(this Scrollbar scrollbar) + { + return Observable.CreateWithState(scrollbar, (s, observer) => + { + observer.OnNext(s.value); + return s.onValueChanged.AsObservable().Subscribe(observer); + }); + } + + /// Observe onValueChanged with current `normalizedPosition` value on subscribe. + public static IObservable OnValueChangedAsObservable(this ScrollRect scrollRect) + { + return Observable.CreateWithState(scrollRect, (s, observer) => + { + observer.OnNext(s.normalizedPosition); + return s.onValueChanged.AsObservable().Subscribe(observer); + }); + } + + /// Observe onValueChanged with current `value` on subscribe. + public static IObservable OnValueChangedAsObservable(this Slider slider) + { + return Observable.CreateWithState(slider, (s, observer) => + { + observer.OnNext(s.value); + return s.onValueChanged.AsObservable().Subscribe(observer); + }); + } + + /// Observe onEndEdit(Submit) event. + public static IObservable OnEndEditAsObservable(this InputField inputField) + { + return inputField.onEndEdit.AsObservable(); + } + +#if (UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2) + /// Observe onValueChange with current `text` value on subscribe. + public static IObservable OnValueChangeAsObservable(this InputField inputField) + { + return Observable.CreateWithState(inputField, (i, observer) => + { + observer.OnNext(i.text); + return i.onValueChange.AsObservable().Subscribe(observer); + }); + } +#else + /// Observe onValueChanged with current `text` value on subscribe. + public static IObservable OnValueChangedAsObservable(this InputField inputField) + { + return Observable.CreateWithState(inputField, (i, observer) => + { + observer.OnNext(i.text); + return i.onValueChanged.AsObservable().Subscribe(observer); + }); + } +#endif + +#if UNITY_5_3_OR_NEWER + + /// Observe onValueChanged with current `value` on subscribe. + public static IObservable OnValueChangedAsObservable(this Dropdown dropdown) + { + return Observable.CreateWithState(dropdown, (d, observer) => + { + observer.OnNext(d.value); + return d.onValueChanged.AsObservable().Subscribe(observer); + }); + } + +#endif + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs.meta new file mode 100644 index 00000000..7e93d62b --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7645084659bc779448e384456805d251 +timeCreated: 1455373899 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs new file mode 100644 index 00000000..c1c8510d --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +namespace UniRx +{ + internal static class YieldInstructionCache + { + public static readonly WaitForEndOfFrame WaitForEndOfFrame = new WaitForEndOfFrame(); + public static readonly WaitForFixedUpdate WaitForFixedUpdate = new WaitForFixedUpdate(); + } +} \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs.meta new file mode 100644 index 00000000..cb0dc8f5 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityEngineBridge/YieldInstructionCache.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2493deaccf35b0542800b0851771e665 +timeCreated: 1455373897 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge.meta new file mode 100644 index 00000000..3472483a --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2c03c70869bcd0240b96959097acc29d +folderAsset: yes +timeCreated: 1455373896 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs new file mode 100644 index 00000000..0a733ed9 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs @@ -0,0 +1,26 @@ +#if UNITY_METRO + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace UniRx +{ + public static class Thread + { + public static void Sleep(TimeSpan wait) + { + new System.Threading.ManualResetEvent(false).WaitOne(wait); + } + + public static void Sleep(int ms) + { + new System.Threading.ManualResetEvent(false).WaitOne(ms); + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs.meta new file mode 100644 index 00000000..847d4215 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/Thread.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: bf1175d5dd9b5904d898eb4c9dd7e0c5 +timeCreated: 1455373901 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs new file mode 100644 index 00000000..74c9598f --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs @@ -0,0 +1,100 @@ +#if UNITY_METRO + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +#if NETFX_CORE +using System.Threading.Tasks; +#endif + +namespace UniRx +{ + public static partial class Scheduler + { + public static readonly IScheduler ThreadPool = new ThreadPoolScheduler(); + + class ThreadPoolScheduler : IScheduler + { + public DateTimeOffset Now + { + get { return Scheduler.Now; } + } + + public IDisposable Schedule(Action action) + { + var d = new BooleanDisposable(); +#if NETFX_CORE + + Task.Run(()=> + { + if (!d.IsDisposed) + { + action(); + } + }); + +#else + Action act = () => + { + if (!d.IsDisposed) + { + action(); + } + }; + + act.BeginInvoke(ar => act.EndInvoke(ar), null); + +#endif + + return d; + } + + public IDisposable Schedule(TimeSpan dueTime, Action action) + { + var wait = Scheduler.Normalize(dueTime); + + var d = new BooleanDisposable(); + +#if NETFX_CORE + + Task.Run(()=> + { + if (!d.IsDisposed) + { + if (wait.Ticks > 0) + { + Thread.Sleep(wait); + } + action(); + } + }); + +#else + + Action act = () => + { + if (!d.IsDisposed) + { + if (wait.Ticks > 0) + { + Thread.Sleep(wait); + } + action(); + } + }; + + act.BeginInvoke(ar => act.EndInvoke(ar), null); + +#endif + + return d; + } + } + } +} + +#endif \ No newline at end of file diff --git a/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs.meta b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs.meta new file mode 100644 index 00000000..24053881 --- /dev/null +++ b/popcorn/Assets/Plugins/UniRx/Scripts/UnityWinRTBridge/ThreadPoolScheduler_UnityWinRT.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2c36c9256c17bbb40854ef9b9e4d51c7 +timeCreated: 1455373898 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: