unirx 추가 및 패키지 폴더 정리
This commit is contained in:
parent
bdbaaa2499
commit
006952cf2a
|
|
@ -1,2 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67a75261c5338ce43956280a2563bc58
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f0f9ae9ec9ccd044888049fc2f7a991f
|
||||
DefaultImporter:
|
||||
userData:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e4a0f5f2551636f4b890cabfbc89bd08
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a1bdebfe2d938c45b7a5a3cff10e668
|
||||
DefaultImporter:
|
||||
userData:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd3ccd040e82bcb44b2d059120263d15
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e56ed53a87c41c5469f603de48a0e7fc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f5d2f1b7bdeef4847ae22f2fac658374
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3cdc2d5ee3b40ca41890e290539d7a67
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9077e099c9d455340848a426fc17a0b4
|
||||
timeCreated: 1643183840
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e435e044f0ae52499033f057cfee292
|
||||
timeCreated: 1643183890
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f597f19f656ba56eae4f6a3a7cc528f4
|
||||
timeCreated: 1488828285
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 48e08dc33330d11e9d4a1b246c52e4f6
|
||||
timeCreated: 1488828285
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ed09910c0094cb27be8f3ca264680da3
|
||||
timeCreated: 1488828285
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc355dd4cf1e6173beaeb22c2858cbe1
|
||||
timeCreated: 1488828285
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d44247be8eeb4b44a82f90cb26f290b4
|
||||
guid: e2760ae7ae7094557894fed288d95b2b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 967c51da60b108e46b03160cc93a5277
|
||||
timeCreated: 1496899716
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 978ae90fe3a2bba4f8dd7ab0f7c029dc
|
||||
folderAsset: yes
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#if !(UNITY_METRO || UNITY_WP8)
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning disable CS0618
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
// sample script, attach your object.
|
||||
public class Sample01_ObservableWWW : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
// Basic: Download from google.
|
||||
{
|
||||
ObservableWWW.Get("http://google.co.jp/")
|
||||
.Subscribe(
|
||||
x => Debug.Log(x.Substring(0, 100)), // onSuccess
|
||||
ex => Debug.LogException(ex)); // onError
|
||||
}
|
||||
|
||||
// Linear Pattern with LINQ Query Expressions
|
||||
// download after google, start bing download
|
||||
{
|
||||
var query = from google in ObservableWWW.Get("http://google.com/")
|
||||
from bing in ObservableWWW.Get("http://bing.com/")
|
||||
select new { google, bing };
|
||||
|
||||
var cancel = query.Subscribe(x => Debug.Log(x.google.Substring(0, 100) + ":" + x.bing.Substring(0, 100)));
|
||||
|
||||
// Call Dispose is cancel downloading.
|
||||
cancel.Dispose();
|
||||
}
|
||||
|
||||
// Observable.WhenAll is for parallel asynchronous operation
|
||||
// (It's like Observable.Zip but specialized for single async operations like Task.WhenAll of .NET 4)
|
||||
{
|
||||
var parallel = Observable.WhenAll(
|
||||
ObservableWWW.Get("http://google.com/"),
|
||||
ObservableWWW.Get("http://bing.com/"),
|
||||
ObservableWWW.Get("http://unity3d.com/"));
|
||||
|
||||
parallel.Subscribe(xs =>
|
||||
{
|
||||
Debug.Log(xs[0].Substring(0, 100)); // google
|
||||
Debug.Log(xs[1].Substring(0, 100)); // bing
|
||||
Debug.Log(xs[2].Substring(0, 100)); // unity
|
||||
});
|
||||
}
|
||||
|
||||
// with Progress
|
||||
{
|
||||
// notifier for progress
|
||||
var progressNotifier = new ScheduledNotifier<float>();
|
||||
progressNotifier.Subscribe(x => Debug.Log(x)); // write www.progress
|
||||
|
||||
// pass notifier to WWW.Get/Post
|
||||
ObservableWWW.Get("http://google.com/", progress: progressNotifier).Subscribe();
|
||||
}
|
||||
|
||||
// with Error
|
||||
{
|
||||
// If WWW has .error, ObservableWWW throws WWWErrorException to onError pipeline.
|
||||
// WWWErrorException has RawErrorMessage, HasResponse, StatusCode, ResponseHeaders
|
||||
ObservableWWW.Get("http://www.google.com/404")
|
||||
.CatchIgnore((WWWErrorException ex) =>
|
||||
{
|
||||
Debug.Log(ex.RawErrorMessage);
|
||||
if (ex.HasResponse)
|
||||
{
|
||||
Debug.Log(ex.StatusCode);
|
||||
}
|
||||
foreach (var item in ex.ResponseHeaders)
|
||||
{
|
||||
Debug.Log(item.Key + ":" + item.Value);
|
||||
}
|
||||
})
|
||||
.Subscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning restore CS0618
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bf3770fc51ac89f45987dbde37ae81bd
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using UnityEngine;
|
||||
using UniRx.Triggers; // Triggers Namepsace
|
||||
using System;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample02_ObservableTriggers : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
// Get the plain object
|
||||
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
|
||||
// Add ObservableXxxTrigger for handle MonoBehaviour's event as Observable
|
||||
cube.AddComponent<ObservableUpdateTrigger>()
|
||||
.UpdateAsObservable()
|
||||
.SampleFrame(30)
|
||||
.Subscribe(x => Debug.Log("cube"), () => Debug.Log("destroy"));
|
||||
|
||||
// destroy after 3 second:)
|
||||
GameObject.Destroy(cube, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cb5e978d683e94f4d9c2c81be80f93a7
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_METRO)
|
||||
|
||||
using UnityEngine;
|
||||
using UniRx.Triggers; // for enable gameObject.EventAsObservbale()
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample03_GameObjectAsObservable : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
// All events can subscribe by ***AsObservable if enables UniRx.Triggers
|
||||
this.OnMouseDownAsObservable()
|
||||
.SelectMany(_ => this.gameObject.UpdateAsObservable())
|
||||
.TakeUntil(this.gameObject.OnMouseUpAsObservable())
|
||||
.Select(_ => Input.mousePosition)
|
||||
.RepeatUntilDestroy(this)
|
||||
.Subscribe(x => Debug.Log(x), ()=> Debug.Log("!!!" + "complete"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 005e349e5ccdd2b47bddc813b81afe40
|
||||
timeCreated: 1455373897
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample04_ConvertFromUnityCallback : MonoBehaviour
|
||||
{
|
||||
// This is about log but more reliable log sample => Sample11_Logger
|
||||
|
||||
private class LogCallback
|
||||
{
|
||||
public string Condition;
|
||||
public string StackTrace;
|
||||
public UnityEngine.LogType LogType;
|
||||
}
|
||||
|
||||
static class LogHelper
|
||||
{
|
||||
// If static register callback, use Subject for event branching.
|
||||
|
||||
#if (UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
|
||||
static Subject<LogCallback> subject;
|
||||
|
||||
public static IObservable<LogCallback> LogCallbackAsObservable()
|
||||
{
|
||||
if (subject == null)
|
||||
{
|
||||
subject = new Subject<LogCallback>();
|
||||
|
||||
// Publish to Subject in callback
|
||||
|
||||
|
||||
UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) =>
|
||||
{
|
||||
subject.OnNext(new LogCallback { Condition = condition, StackTrace = stackTrace, LogType = type });
|
||||
});
|
||||
}
|
||||
|
||||
return subject.AsObservable();
|
||||
}
|
||||
|
||||
#else
|
||||
// If standard evetns, you can use Observable.FromEvent.
|
||||
|
||||
public static IObservable<LogCallback> LogCallbackAsObservable()
|
||||
{
|
||||
return Observable.FromEvent<Application.LogCallback, LogCallback>(
|
||||
h => (condition, stackTrace, type) => h(new LogCallback { Condition = condition, StackTrace = stackTrace, LogType = type }),
|
||||
h => Application.logMessageReceived += h, h => Application.logMessageReceived -= h);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// method is separatable and composable
|
||||
LogHelper.LogCallbackAsObservable()
|
||||
.Where(x => x.LogType == LogType.Warning)
|
||||
.Subscribe(x => Debug.Log(x));
|
||||
|
||||
LogHelper.LogCallbackAsObservable()
|
||||
.Where(x => x.LogType == LogType.Error)
|
||||
.Subscribe(x => Debug.Log(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73e69fd4bbb724045a4e06050fbc5af3
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning disable CS0618
|
||||
#endif
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample05_ConvertFromCoroutine
|
||||
{
|
||||
// public method
|
||||
public static IObservable<string> GetWWW(string url)
|
||||
{
|
||||
// convert coroutine to IObservable
|
||||
return Observable.FromCoroutine<string>((observer, cancellationToken) => GetWWWCore(url, observer, cancellationToken));
|
||||
}
|
||||
|
||||
// IEnumerator with callback
|
||||
static IEnumerator GetWWWCore(string url, IObserver<string> observer, CancellationToken cancellationToken)
|
||||
{
|
||||
var www = new UnityEngine.WWW(url);
|
||||
while (!www.isDone && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested) yield break;
|
||||
|
||||
if (www.error != null)
|
||||
{
|
||||
observer.OnError(new Exception(www.error));
|
||||
}
|
||||
else
|
||||
{
|
||||
observer.OnNext(www.text);
|
||||
observer.OnCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning restore CS0618
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 41f3df73f7da66b4980f6d9a86927796
|
||||
timeCreated: 1455373898
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample06_ConvertToCoroutine : MonoBehaviour
|
||||
{
|
||||
// convert IObservable to Coroutine
|
||||
void Start()
|
||||
{
|
||||
StartCoroutine(ComplexCoroutineTest());
|
||||
}
|
||||
|
||||
IEnumerator ComplexCoroutineTest()
|
||||
{
|
||||
yield return new WaitForSeconds(1);
|
||||
|
||||
var v = default(int);
|
||||
yield return Observable.Range(1, 10).StartAsCoroutine(x => v = x);
|
||||
|
||||
Debug.Log(v); // 10(callback is last value)
|
||||
yield return new WaitForSeconds(3);
|
||||
|
||||
yield return Observable.Return(100).StartAsCoroutine(x => v = x);
|
||||
|
||||
Debug.Log(v); // 100
|
||||
}
|
||||
|
||||
// Note:ToAwaitableEnumerator/StartAsCoroutine/LazyTask are obsolete way on Unity 5.3
|
||||
// You can use ToYieldInstruction.
|
||||
|
||||
#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)
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning disable CS0618
|
||||
#endif
|
||||
|
||||
IEnumerator TestNewCustomYieldInstruction()
|
||||
{
|
||||
// wait Rx Observable.
|
||||
yield return Observable.Timer(TimeSpan.FromSeconds(1)).ToYieldInstruction();
|
||||
|
||||
// you can change the scheduler(this is ignore Time.scale)
|
||||
yield return Observable.Timer(TimeSpan.FromSeconds(1), Scheduler.MainThreadIgnoreTimeScale).ToYieldInstruction();
|
||||
|
||||
// get return value from ObservableYieldInstruction
|
||||
var o = ObservableWWW.Get("http://unity3d.com/").ToYieldInstruction(throwOnError: false);
|
||||
yield return o;
|
||||
|
||||
if (o.HasError) { Debug.Log(o.Error.ToString()); }
|
||||
if (o.HasResult) { Debug.Log(o.Result); }
|
||||
|
||||
// other sample(wait until transform.position.y >= 100)
|
||||
yield return this.ObserveEveryValueChanged(x => x.transform).FirstOrDefault(x => x.position.y >= 100).ToYieldInstruction();
|
||||
}
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
#pragma warning restore CS0618
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5da8247fbc4a4c84e96a727b44903214
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
#pragma warning disable 0168
|
||||
#pragma warning disable 0219
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample07_OrchestratIEnumerator : MonoBehaviour
|
||||
{
|
||||
// two coroutines
|
||||
IEnumerator AsyncA()
|
||||
{
|
||||
Debug.Log("a start");
|
||||
yield return new WaitForSeconds(3);
|
||||
Debug.Log("a end");
|
||||
}
|
||||
|
||||
IEnumerator AsyncB()
|
||||
{
|
||||
Debug.Log("b start");
|
||||
yield return new WaitForEndOfFrame();
|
||||
Debug.Log("b end");
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
// after completed AsyncA, run AsyncB as continuous routine.
|
||||
// UniRx expands SelectMany(IEnumerator) as SelectMany(IEnumerator.ToObservable())
|
||||
var cancel = Observable.FromCoroutine(AsyncA)
|
||||
.SelectMany(AsyncB)
|
||||
.Subscribe();
|
||||
|
||||
// If you want to stop Coroutine(as cancel), call subscription.Dispose()
|
||||
// cancel.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0219
|
||||
#pragma warning restore 0168
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d437607dfffa8ff428bda3366354078d
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample08_DetectDoubleClick : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
// Global event handling is very useful.
|
||||
// UniRx can handle there events.
|
||||
// Observable.EveryUpdate/EveryFixedUpdate/EveryEndOfFrame
|
||||
// Observable.EveryApplicationFocus/EveryApplicationPause
|
||||
// Observable.OnceApplicationQuit
|
||||
|
||||
// This DoubleCLick Sample is from
|
||||
// The introduction to Reactive Programming you've been missing
|
||||
// https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
|
||||
|
||||
var clickStream = Observable.EveryUpdate()
|
||||
.Where(_ => Input.GetMouseButtonDown(0));
|
||||
|
||||
clickStream.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)))
|
||||
.Where(xs => xs.Count >= 2)
|
||||
.Subscribe(xs => Debug.Log("DoubleClick Detected! Count:" + xs.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eb801bbfb1ffcd64389e90c8f2435b79
|
||||
timeCreated: 1455373902
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#pragma warning disable 0067
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample09_EventHandling : MonoBehaviour
|
||||
{
|
||||
public class MyEventArgs : EventArgs
|
||||
{
|
||||
public int MyProperty { get; set; }
|
||||
}
|
||||
|
||||
public event EventHandler<MyEventArgs> FooBar;
|
||||
public event Action<int> FooFoo;
|
||||
|
||||
CompositeDisposable disposables = new CompositeDisposable();
|
||||
|
||||
// Subject is Rx's native event expression and recommend way for use Rx as event.
|
||||
// Subject.OnNext as fire event,
|
||||
// expose IObserver is subscibable for external source, it's no need convert.
|
||||
Subject<int> onBarBar = new Subject<int>();
|
||||
public IObservable<int> OnBarBar { get { return onBarBar; } }
|
||||
|
||||
void Start()
|
||||
{
|
||||
// convert to IO<EventPattern> as (sender, eventArgs)
|
||||
Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(
|
||||
h => h.Invoke, h => FooBar += h, h => FooBar -= h)
|
||||
.Subscribe()
|
||||
.AddTo(disposables); // IDisposable can add to collection easily by AddTo
|
||||
|
||||
// convert to IO<EventArgs>, many situation this is useful than FromEventPattern
|
||||
Observable.FromEvent<EventHandler<MyEventArgs>, MyEventArgs>(
|
||||
h => (sender, e) => h(e), h => FooBar += h, h => FooBar -= h)
|
||||
.Subscribe()
|
||||
.AddTo(disposables);
|
||||
|
||||
// You can convert Action like event.
|
||||
Observable.FromEvent<int>(
|
||||
h => FooFoo += h, h => FooFoo -= h)
|
||||
.Subscribe()
|
||||
.AddTo(disposables);
|
||||
|
||||
// AOT Safe EventHandling, use dummy capture, see:https://github.com/neuecc/UniRx/wiki/AOT-Exception-Patterns-and-Hacks
|
||||
var capture = 0;
|
||||
Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(h =>
|
||||
{
|
||||
capture.GetHashCode(); // dummy for AOT
|
||||
return new EventHandler<MyEventArgs>(h);
|
||||
}, h => FooBar += h, h => FooBar -= h)
|
||||
.Subscribe()
|
||||
.AddTo(disposables);
|
||||
|
||||
// Subject as like event.
|
||||
OnBarBar.Subscribe().AddTo(disposables);
|
||||
onBarBar.OnNext(1); // fire event
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// manage subscription lifecycle
|
||||
disposables.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0067
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 95140e49213aa6f49a470a81873b87c0
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample10_MainThreadDispatcher
|
||||
{
|
||||
public void Run()
|
||||
{
|
||||
// MainThreadDispatcher is heart of Rx and Unity integration
|
||||
|
||||
// StartCoroutine can start coroutine besides MonoBehaviour.
|
||||
MainThreadDispatcher.StartCoroutine(TestAsync());
|
||||
|
||||
// We have two way of run coroutine, FromCoroutine or StartCoroutine.
|
||||
// StartCoroutine is Unity primitive way and it's awaitable by yield return.
|
||||
// FromCoroutine is Rx, it's composable and cancellable by subscription's IDisposable.
|
||||
// FromCoroutine's overload can have return value, see:Sample05_ConvertFromCoroutine
|
||||
Observable.FromCoroutine(TestAsync).Subscribe();
|
||||
|
||||
// Add Action to MainThreadDispatcher. Action is saved queue, run on next update.
|
||||
MainThreadDispatcher.Post(_ => Debug.Log("test"), null);
|
||||
|
||||
// Timebased operations is run on MainThread(as default)
|
||||
// All timebased operation(Interval, Timer, Delay, Buffer, etc...)is single thread, thread safe!
|
||||
Observable.Interval(TimeSpan.FromSeconds(1))
|
||||
.Subscribe(x => Debug.Log(x));
|
||||
|
||||
// Observable.Start use ThreadPool Scheduler as default.
|
||||
// ObserveOnMainThread return to mainthread
|
||||
Observable.Start(() => Unit.Default) // asynchronous work
|
||||
.ObserveOnMainThread()
|
||||
.Subscribe(x => Debug.Log(x));
|
||||
}
|
||||
|
||||
IEnumerator TestAsync()
|
||||
{
|
||||
Debug.Log("a");
|
||||
yield return new WaitForSeconds(1);
|
||||
Debug.Log("b");
|
||||
yield return new WaitForSeconds(1);
|
||||
Debug.Log("c");
|
||||
yield return new WaitForSeconds(1);
|
||||
Debug.Log("d");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a0b959735346af48b772254afc8afdd
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using UniRx.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample11_Logger
|
||||
{
|
||||
// UniRx.Diagnostics.Logger
|
||||
// logger is threadsafe, define per class with name.
|
||||
static readonly UniRx.Diagnostics.Logger logger = new UniRx.Diagnostics.Logger("Sample11");
|
||||
|
||||
// call once at applicationinit
|
||||
public void ApplicationInitialize()
|
||||
{
|
||||
// Log as Stream, UniRx.Diagnostics.ObservableLogger.Listener is IObservable<LogEntry>
|
||||
// You can subscribe and output to any place.
|
||||
ObservableLogger.Listener.LogToUnityDebug();
|
||||
|
||||
// for example, filter only Exception and upload to web.
|
||||
// (make custom sink(IObserver<EventEntry>) is better to use)
|
||||
ObservableLogger.Listener
|
||||
.Where(x => x.LogType == LogType.Exception)
|
||||
.Subscribe(x =>
|
||||
{
|
||||
// ObservableWWW.Post("", null).Subscribe();
|
||||
});
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
// Debug is write only DebugBuild.
|
||||
logger.Debug("Debug Message");
|
||||
|
||||
// or other logging methods
|
||||
logger.Log("Message");
|
||||
logger.Exception(new Exception("test exception"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f5aa72c61e2548a4bac4d65f93c63bf1
|
||||
timeCreated: 1455373902
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa1d80321df46bd47a4a60137cea10de
|
||||
timeCreated: 1634768071
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 4a4aea8df1ad11c47a1db84432dd30f8
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// 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.Examples
|
||||
{
|
||||
public class Sample12_ReactiveProperty : MonoBehaviour
|
||||
{
|
||||
// Open Sample12Scene. Set from canvas
|
||||
public Button MyButton;
|
||||
public Toggle MyToggle;
|
||||
public InputField MyInput;
|
||||
public Text MyText;
|
||||
public Slider MySlider;
|
||||
|
||||
// You can monitor/modifie in inspector by SpecializedReactiveProperty
|
||||
public IntReactiveProperty IntRxProp = new IntReactiveProperty();
|
||||
|
||||
Enemy enemy = new Enemy(1000);
|
||||
|
||||
void Start()
|
||||
{
|
||||
// UnityEvent as Observable
|
||||
// (shortcut, MyButton.OnClickAsObservable())
|
||||
MyButton.onClick.AsObservable().Subscribe(_ => enemy.CurrentHp.Value -= 99);
|
||||
|
||||
// Toggle, Input etc as Observable(OnValueChangedAsObservable is helper for provide isOn value on subscribe)
|
||||
// SubscribeToInteractable is UniRx.UI Extension Method, same as .interactable = x)
|
||||
MyToggle.OnValueChangedAsObservable().SubscribeToInteractable(MyButton);
|
||||
|
||||
// input shows delay after 1 second
|
||||
#if !(UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
|
||||
MyInput.OnValueChangedAsObservable()
|
||||
#else
|
||||
MyInput.OnValueChangeAsObservable()
|
||||
#endif
|
||||
.Where(x => x != null)
|
||||
.Delay(TimeSpan.FromSeconds(1))
|
||||
.SubscribeToText(MyText); // SubscribeToText is UniRx.UI Extension Method
|
||||
|
||||
// converting for human visibility
|
||||
MySlider.OnValueChangedAsObservable()
|
||||
.SubscribeToText(MyText, x => Math.Round(x, 2).ToString());
|
||||
|
||||
// from RxProp, CurrentHp changing(Button Click) is observable
|
||||
enemy.CurrentHp.SubscribeToText(MyText);
|
||||
enemy.IsDead.Where(isDead => isDead == true)
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
MyToggle.interactable = MyButton.interactable = false;
|
||||
});
|
||||
|
||||
// initial text:)
|
||||
IntRxProp.SubscribeToText(MyText);
|
||||
}
|
||||
}
|
||||
|
||||
// Reactive Notification Model
|
||||
public class Enemy
|
||||
{
|
||||
public IReactiveProperty<long> CurrentHp { get; private set; }
|
||||
|
||||
public IReadOnlyReactiveProperty<bool> IsDead { get; private set; }
|
||||
|
||||
public Enemy(int initialHp)
|
||||
{
|
||||
// Declarative Property
|
||||
CurrentHp = new ReactiveProperty<long>(initialHp);
|
||||
IsDead = CurrentHp.Select(x => x <= 0).ToReactiveProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 18e34490a83a27e44adf93dd4ffd1f22
|
||||
timeCreated: 1455373897
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,8 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e44ccdfffd6394f459ff14d0c592baf1
|
||||
timeCreated: 1643183720
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: b879645f640b02b43a8e78e210c1da1f
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 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.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace UniRx.Examples
|
||||
{
|
||||
public class Sample13_ToDoApp : MonoBehaviour
|
||||
{
|
||||
// Open Sample13Scene. Set from canvas
|
||||
public Text Title;
|
||||
public InputField ToDoInput;
|
||||
public Button AddButton;
|
||||
public Button ClearButton;
|
||||
public GameObject TodoList;
|
||||
|
||||
// prefab:)
|
||||
public GameObject SampleItemPrefab;
|
||||
|
||||
ReactiveCollection<GameObject> toDos = new ReactiveCollection<GameObject>();
|
||||
|
||||
void Start()
|
||||
{
|
||||
// merge Button click and push enter key on input field.
|
||||
var submit = Observable.Merge(
|
||||
AddButton.OnClickAsObservable().Select(_ => ToDoInput.text),
|
||||
ToDoInput.OnEndEditAsObservable().Where(_ => Input.GetKeyDown(KeyCode.Return)));
|
||||
|
||||
// add to reactive collection
|
||||
submit.Where(x => x != "")
|
||||
.Subscribe(x =>
|
||||
{
|
||||
ToDoInput.text = ""; // clear input field
|
||||
var item = Instantiate(SampleItemPrefab) as GameObject;
|
||||
(item.GetComponentInChildren(typeof(Text)) as Text).text = x;
|
||||
toDos.Add(item);
|
||||
});
|
||||
|
||||
// Collection Change Handling
|
||||
toDos.ObserveCountChanged().Subscribe(x => Title.text = "TODO App, ItemCount:" + x);
|
||||
toDos.ObserveAdd().Subscribe(x =>
|
||||
{
|
||||
x.Value.transform.SetParent(TodoList.transform, false);
|
||||
});
|
||||
toDos.ObserveRemove().Subscribe(x =>
|
||||
{
|
||||
GameObject.Destroy(x.Value);
|
||||
});
|
||||
|
||||
// Clear
|
||||
ClearButton.OnClickAsObservable()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
var removeTargets = toDos.Where(x => x.GetComponent<Toggle>().isOn).ToArray();
|
||||
foreach (var item in removeTargets)
|
||||
{
|
||||
toDos.Remove(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 022ecfa555367154c8cf87d61465f7e2
|
||||
timeCreated: 1455373897
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &152834
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 22461494}
|
||||
- 222: {fileID: 22298102}
|
||||
- 114: {fileID: 11434412}
|
||||
m_Layer: 5
|
||||
m_Name: Background
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!1 &172388
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 22491898}
|
||||
- 222: {fileID: 22251748}
|
||||
- 114: {fileID: 11438756}
|
||||
m_Layer: 5
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!1 &174974
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 22463654}
|
||||
- 222: {fileID: 22278786}
|
||||
- 114: {fileID: 11497312}
|
||||
m_Layer: 5
|
||||
m_Name: Checkmark
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!1 &182208
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 22478562}
|
||||
- 114: {fileID: 11479148}
|
||||
m_Layer: 5
|
||||
m_Name: Sample13_ToDoItem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &11434412
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 152834}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
--- !u!114 &11438756
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 172388}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: .196078435, g: .196078435, b: .196078435, a: 1}
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 30
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: 'TODOITEM
|
||||
|
||||
'
|
||||
--- !u!114 &11479148
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182208}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 2109663825, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: .960784316, g: .960784316, b: .960784316, a: 1}
|
||||
m_PressedColor: {r: .784313738, g: .784313738, b: .784313738, a: 1}
|
||||
m_DisabledColor: {r: .784313738, g: .784313738, b: .784313738, a: .501960814}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: .100000001
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 11434412}
|
||||
toggleTransition: 1
|
||||
graphic: {fileID: 11497312}
|
||||
m_Group: {fileID: 0}
|
||||
onValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.Toggle+ToggleEvent, UnityEngine.UI, Version=1.0.0.0,
|
||||
Culture=neutral, PublicKeyToken=null
|
||||
m_IsOn: 1
|
||||
--- !u!114 &11497312
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 174974}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
--- !u!222 &22251748
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 172388}
|
||||
--- !u!222 &22278786
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 174974}
|
||||
--- !u!222 &22298102
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 152834}
|
||||
--- !u!224 &22461494
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 152834}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 22463654}
|
||||
m_Father: {fileID: 22478562}
|
||||
m_RootOrder: 0
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 10, y: -10}
|
||||
m_SizeDelta: {x: 20, y: 30}
|
||||
m_Pivot: {x: .5, y: .5}
|
||||
--- !u!224 &22463654
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 174974}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 22461494}
|
||||
m_RootOrder: 0
|
||||
m_AnchorMin: {x: .5, y: .5}
|
||||
m_AnchorMax: {x: .5, y: .5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 20, y: 30}
|
||||
m_Pivot: {x: .5, y: .5}
|
||||
--- !u!224 &22478562
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182208}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 22461494}
|
||||
- {fileID: 22491898}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: .5, y: .5}
|
||||
--- !u!224 &22491898
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 172388}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 22478562}
|
||||
m_RootOrder: 1
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 9, y: -.5}
|
||||
m_SizeDelta: {x: -28, y: -3}
|
||||
m_Pivot: {x: .5, y: .5}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 182208}
|
||||
m_IsPrefabParent: 1
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 173222196f3e1f0448b383f260df7d44
|
||||
timeCreated: 1455373909
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "UniRx.Examples",
|
||||
"references": [
|
||||
"UniRx"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ef1ab177f3fe27429d3f283efd75860
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: 71799519d12379b49b6b53aea974bea5
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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).
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 52d665ea30c2a3a49a6fa4b3b5a0349a
|
||||
timeCreated: 1455373909
|
||||
licenseType: Store
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd9da43799024a84ba7709f4d54259d6
|
||||
timeCreated: 1643183778
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
fileFormatVersion: 2
|
||||
guid: eaf9ac9937118834c86197511fd5317f
|
||||
folderAsset: yes
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c490b3110ff2a524ea963382652a378f
|
||||
folderAsset: yes
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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<TResult> AbortableDeferredAsyncRequest<TResult>(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, TResult> end, WebRequest request)
|
||||
{
|
||||
var result = Observable.Create<TResult>(observer =>
|
||||
{
|
||||
var isCompleted = -1;
|
||||
var subscription = Observable.FromAsyncPattern<TResult>(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<WebResponse> GetResponseAsObservable(this WebRequest request)
|
||||
{
|
||||
return AbortableDeferredAsyncRequest<WebResponse>(request.BeginGetResponse, request.EndGetResponse, request);
|
||||
}
|
||||
|
||||
public static IObservable<HttpWebResponse> GetResponseAsObservable(this HttpWebRequest request)
|
||||
{
|
||||
return AbortableDeferredAsyncRequest<HttpWebResponse>(request.BeginGetResponse, ar => (HttpWebResponse)request.EndGetResponse(ar), request);
|
||||
}
|
||||
|
||||
public static IObservable<Stream> GetRequestStreamAsObservable(this WebRequest request)
|
||||
{
|
||||
return AbortableDeferredAsyncRequest<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 457f0007b2c70e34e9929ec8f0e2c4e6
|
||||
timeCreated: 1455373898
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d061218ef48281148bb1a996d971bdbe
|
||||
folderAsset: yes
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ff95c6eb380ca248984d8c27c1244d0
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// original code from GitHub Reactive-Extensions/Rx.NET
|
||||
// some modified.
|
||||
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#if (NETFX_CORE || NET_4_6 || NET_STANDARD_2_0 || UNITY_WSA_10_0)
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a disposable resource that has an associated <seealso cref="T:System.Threading.CancellationToken"/> that will be set to the cancellation requested state upon disposal.
|
||||
/// </summary>
|
||||
public sealed class CancellationDisposable : ICancelable
|
||||
{
|
||||
private readonly CancellationTokenSource _cts;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CancellationDisposable"/> class that uses an existing <seealso cref="T:System.Threading.CancellationTokenSource"/>.
|
||||
/// </summary>
|
||||
/// <param name="cts"><seealso cref="T:System.Threading.CancellationTokenSource"/> used for cancellation.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="cts"/> is null.</exception>
|
||||
public CancellationDisposable(CancellationTokenSource cts)
|
||||
{
|
||||
if (cts == null)
|
||||
throw new ArgumentNullException("cts");
|
||||
|
||||
_cts = cts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CancellationDisposable"/> class that uses a new <seealso cref="T:System.Threading.CancellationTokenSource"/>.
|
||||
/// </summary>
|
||||
public CancellationDisposable()
|
||||
: this(new CancellationTokenSource())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="T:System.Threading.CancellationToken"/> used by this CancellationDisposable.
|
||||
/// </summary>
|
||||
public CancellationToken Token
|
||||
{
|
||||
get { return _cts.Token; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the underlying <seealso cref="T:System.Threading.CancellationTokenSource"/>.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the object is disposed.
|
||||
/// </summary>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get { return _cts.IsCancellationRequested; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c675907554bfa24d8bd411f386e410d
|
||||
timeCreated: 1475137543
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,283 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
// using System.Linq; do not use LINQ
|
||||
using System.Text;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
// copy, modified from Rx Official
|
||||
|
||||
public sealed class CompositeDisposable : ICollection<IDisposable>, IDisposable, ICancelable
|
||||
{
|
||||
private readonly object _gate = new object();
|
||||
|
||||
private bool _disposed;
|
||||
private List<IDisposable> _disposables;
|
||||
private int _count;
|
||||
private const int SHRINK_THRESHOLD = 64;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class with no disposables contained by it initially.
|
||||
/// </summary>
|
||||
public CompositeDisposable()
|
||||
{
|
||||
_disposables = new List<IDisposable>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class with the specified number of disposables.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The number of disposables that the new CompositeDisposable can initially store.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than zero.</exception>
|
||||
public CompositeDisposable(int capacity)
|
||||
{
|
||||
if (capacity < 0)
|
||||
throw new ArgumentOutOfRangeException("capacity");
|
||||
|
||||
_disposables = new List<IDisposable>(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class from a group of disposables.
|
||||
/// </summary>
|
||||
/// <param name="disposables">Disposables that will be disposed together.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="disposables"/> is null.</exception>
|
||||
public CompositeDisposable(params IDisposable[] disposables)
|
||||
{
|
||||
if (disposables == null)
|
||||
throw new ArgumentNullException("disposables");
|
||||
|
||||
_disposables = new List<IDisposable>(disposables);
|
||||
_count = _disposables.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.CompositeDisposable"/> class from a group of disposables.
|
||||
/// </summary>
|
||||
/// <param name="disposables">Disposables that will be disposed together.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="disposables"/> is null.</exception>
|
||||
public CompositeDisposable(IEnumerable<IDisposable> disposables)
|
||||
{
|
||||
if (disposables == null)
|
||||
throw new ArgumentNullException("disposables");
|
||||
|
||||
_disposables = new List<IDisposable>(disposables);
|
||||
_count = _disposables.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of disposables contained in the CompositeDisposable.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed.
|
||||
/// </summary>
|
||||
/// <param name="item">Disposable to add.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
|
||||
public void Add(IDisposable item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
var shouldDispose = false;
|
||||
lock (_gate)
|
||||
{
|
||||
shouldDispose = _disposed;
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposables.Add(item);
|
||||
_count++;
|
||||
}
|
||||
}
|
||||
if (shouldDispose)
|
||||
item.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes and disposes the first occurrence of a disposable from the CompositeDisposable.
|
||||
/// </summary>
|
||||
/// <param name="item">Disposable to remove.</param>
|
||||
/// <returns>true if found; false otherwise.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
|
||||
public bool Remove(IDisposable item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
var shouldDispose = false;
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
//
|
||||
// List<T> doesn't shrink the size of the underlying array but does collapse the array
|
||||
// by copying the tail one position to the left of the removal index. We don't need
|
||||
// index-based lookup but only ordering for sequential disposal. So, instead of spending
|
||||
// cycles on the Array.Copy imposed by Remove, we use a null sentinel value. We also
|
||||
// do manual Swiss cheese detection to shrink the list if there's a lot of holes in it.
|
||||
//
|
||||
var i = _disposables.IndexOf(item);
|
||||
if (i >= 0)
|
||||
{
|
||||
shouldDispose = true;
|
||||
_disposables[i] = null;
|
||||
_count--;
|
||||
|
||||
if (_disposables.Capacity > SHRINK_THRESHOLD && _count < _disposables.Capacity / 2)
|
||||
{
|
||||
var old = _disposables;
|
||||
_disposables = new List<IDisposable>(_disposables.Capacity / 2);
|
||||
|
||||
foreach (var d in old)
|
||||
if (d != null)
|
||||
_disposables.Add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldDispose)
|
||||
item.Dispose();
|
||||
|
||||
return shouldDispose;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all disposables in the group and removes them from the group.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
var currentDisposables = default(IDisposable[]);
|
||||
lock (_gate)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
currentDisposables = _disposables.ToArray();
|
||||
_disposables.Clear();
|
||||
_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentDisposables != null)
|
||||
{
|
||||
foreach (var d in currentDisposables)
|
||||
if (d != null)
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes and disposes all disposables from the CompositeDisposable, but does not dispose the CompositeDisposable.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
var currentDisposables = default(IDisposable[]);
|
||||
lock (_gate)
|
||||
{
|
||||
currentDisposables = _disposables.ToArray();
|
||||
_disposables.Clear();
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
foreach (var d in currentDisposables)
|
||||
if (d != null)
|
||||
d.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the CompositeDisposable contains a specific disposable.
|
||||
/// </summary>
|
||||
/// <param name="item">Disposable to search for.</param>
|
||||
/// <returns>true if the disposable was found; otherwise, false.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="item"/> is null.</exception>
|
||||
public bool Contains(IDisposable item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
return _disposables.Contains(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the disposables contained in the CompositeDisposable to an array, starting at a particular array index.
|
||||
/// </summary>
|
||||
/// <param name="array">Array to copy the contained disposables to.</param>
|
||||
/// <param name="arrayIndex">Target index at which to copy the first disposable of the group.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="array"/> is null.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than zero. -or - <paramref name="arrayIndex"/> is larger than or equal to the array length.</exception>
|
||||
public void CopyTo(IDisposable[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
if (arrayIndex < 0 || arrayIndex >= array.Length)
|
||||
throw new ArgumentOutOfRangeException("arrayIndex");
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
var disArray = new List<IDisposable>();
|
||||
foreach (var item in _disposables)
|
||||
{
|
||||
if (item != null) disArray.Add(item);
|
||||
}
|
||||
|
||||
Array.Copy(disArray.ToArray(), 0, array, arrayIndex, array.Length - arrayIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always returns false.
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the CompositeDisposable.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator to iterate over the disposables.</returns>
|
||||
public IEnumerator<IDisposable> GetEnumerator()
|
||||
{
|
||||
var res = new List<IDisposable>();
|
||||
|
||||
lock (_gate)
|
||||
{
|
||||
foreach (var d in _disposables)
|
||||
{
|
||||
if (d != null) res.Add(d);
|
||||
}
|
||||
}
|
||||
|
||||
return res.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the CompositeDisposable.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator to iterate over the disposables.</returns>
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the object is disposed.
|
||||
/// </summary>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get { return _disposed; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a0f9d923bd5f4cd47b39bdd83125de27
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
public sealed class DictionaryDisposable<TKey, TValue> : IDisposable, IDictionary<TKey, TValue>
|
||||
where TValue : IDisposable
|
||||
{
|
||||
bool isDisposed = false;
|
||||
readonly Dictionary<TKey, TValue> inner;
|
||||
|
||||
public DictionaryDisposable()
|
||||
{
|
||||
inner = new Dictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
public DictionaryDisposable(IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
inner = new Dictionary<TKey, TValue>(comparer);
|
||||
}
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return inner[key];
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
if (isDisposed) value.Dispose();
|
||||
|
||||
TValue oldValue;
|
||||
if (TryGetValue(key, out oldValue))
|
||||
{
|
||||
oldValue.Dispose();
|
||||
inner[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
inner[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return inner.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue>.KeyCollection Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException("please use .Select(x => x.Key).ToArray()");
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue>.ValueCollection Values
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException("please use .Select(x => x.Value).ToArray()");
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
if (isDisposed)
|
||||
{
|
||||
value.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
inner.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
foreach (var item in inner)
|
||||
{
|
||||
item.Value.Dispose();
|
||||
}
|
||||
inner.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
TValue oldValue;
|
||||
if (inner.TryGetValue(key, out oldValue))
|
||||
{
|
||||
var isSuccessRemove = inner.Remove(key);
|
||||
if (isSuccessRemove)
|
||||
{
|
||||
oldValue.Dispose();
|
||||
}
|
||||
return isSuccessRemove;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return inner.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return inner.TryGetValue(key, out value);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(inner).GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)inner).IsReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
ICollection<TKey> IDictionary<TKey, TValue>.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return new List<TKey>(inner.Keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ICollection<TValue> IDictionary<TKey, TValue>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return new List<TValue>(inner.Values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !UNITY_METRO
|
||||
|
||||
public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
((System.Runtime.Serialization.ISerializable)inner).GetObjectData(info, context);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDeserialization(object sender)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
((System.Runtime.Serialization.IDeserializationCallback)inner).OnDeserialization(sender);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Add((TKey)item.Key, (TValue)item.Value);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)inner).Contains(item);
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)inner).CopyTo(array, arrayIndex);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
return new List<KeyValuePair<TKey, TValue>>((ICollection<KeyValuePair<TKey, TValue>>)inner).GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (inner)
|
||||
{
|
||||
if (isDisposed) return;
|
||||
isDisposed = true;
|
||||
|
||||
foreach (var item in inner)
|
||||
{
|
||||
item.Value.Dispose();
|
||||
}
|
||||
inner.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 702939929fc84d544b12076b76aa73b5
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
public static class Disposable
|
||||
{
|
||||
public static readonly IDisposable Empty = EmptyDisposable.Singleton;
|
||||
|
||||
public static IDisposable Create(Action disposeAction)
|
||||
{
|
||||
return new AnonymousDisposable(disposeAction);
|
||||
}
|
||||
|
||||
public static IDisposable CreateWithState<TState>(TState state, Action<TState> disposeAction)
|
||||
{
|
||||
return new AnonymousDisposable<TState>(state, disposeAction);
|
||||
}
|
||||
|
||||
class EmptyDisposable : IDisposable
|
||||
{
|
||||
public static EmptyDisposable Singleton = new EmptyDisposable();
|
||||
|
||||
private EmptyDisposable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class AnonymousDisposable : IDisposable
|
||||
{
|
||||
bool isDisposed = false;
|
||||
readonly Action dispose;
|
||||
|
||||
public AnonymousDisposable(Action dispose)
|
||||
{
|
||||
this.dispose = dispose;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnonymousDisposable<T> : IDisposable
|
||||
{
|
||||
bool isDisposed = false;
|
||||
readonly T state;
|
||||
readonly Action<T> dispose;
|
||||
|
||||
public AnonymousDisposable(T state, Action<T> dispose)
|
||||
{
|
||||
this.state = state;
|
||||
this.dispose = dispose;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
dispose(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 958f291bb8f434740a6d2c08ad5182a0
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
public static partial class DisposableExtensions
|
||||
{
|
||||
/// <summary>Add disposable(self) to CompositeDisposable(or other ICollection). Return value is self disposable.</summary>
|
||||
public static T AddTo<T>(this T disposable, ICollection<IDisposable> container)
|
||||
where T : IDisposable
|
||||
{
|
||||
if (disposable == null) throw new ArgumentNullException("disposable");
|
||||
if (container == null) throw new ArgumentNullException("container");
|
||||
|
||||
container.Add(disposable);
|
||||
|
||||
return disposable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9c4757265ae105441bae71007cbd0184
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
public interface ICancelable : IDisposable
|
||||
{
|
||||
bool IsDisposed { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5cd5b0b304c78345a49757b1f6f8ba8
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb959083576ace749afd55c1e54b02d9
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
// This code is borrwed from Rx Official and some modified.
|
||||
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a disposable resource that only disposes its underlying disposable resource when all <see cref="GetDisposable">dependent disposable objects</see> have been disposed.
|
||||
/// </summary>
|
||||
public sealed class RefCountDisposable : ICancelable
|
||||
{
|
||||
private readonly object _gate = new object();
|
||||
private IDisposable _disposable;
|
||||
private bool _isPrimaryDisposed;
|
||||
private int _count;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.RefCountDisposable"/> class with the specified disposable.
|
||||
/// </summary>
|
||||
/// <param name="disposable">Underlying disposable.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="disposable"/> is null.</exception>
|
||||
public RefCountDisposable(IDisposable disposable)
|
||||
{
|
||||
if (disposable == null)
|
||||
throw new ArgumentNullException("disposable");
|
||||
|
||||
_disposable = disposable;
|
||||
_isPrimaryDisposed = false;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the object is disposed.
|
||||
/// </summary>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get { return _disposable == null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.
|
||||
/// </summary>
|
||||
/// <returns>A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Backward compat + non-trivial work for a property getter.")]
|
||||
public IDisposable GetDisposable()
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
if (_disposable == null)
|
||||
{
|
||||
return Disposable.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_count++;
|
||||
return new InnerDisposable(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the underlying disposable only when all dependent disposables have been disposed.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
var disposable = default(IDisposable);
|
||||
lock (_gate)
|
||||
{
|
||||
if (_disposable != null)
|
||||
{
|
||||
if (!_isPrimaryDisposed)
|
||||
{
|
||||
_isPrimaryDisposed = true;
|
||||
|
||||
if (_count == 0)
|
||||
{
|
||||
disposable = _disposable;
|
||||
_disposable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disposable != null)
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
private void Release()
|
||||
{
|
||||
var disposable = default(IDisposable);
|
||||
lock (_gate)
|
||||
{
|
||||
if (_disposable != null)
|
||||
{
|
||||
_count--;
|
||||
|
||||
if (_isPrimaryDisposed)
|
||||
{
|
||||
if (_count == 0)
|
||||
{
|
||||
disposable = _disposable;
|
||||
_disposable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disposable != null)
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
sealed class InnerDisposable : IDisposable
|
||||
{
|
||||
private RefCountDisposable _parent;
|
||||
object parentLock = new object();
|
||||
|
||||
public InnerDisposable(RefCountDisposable parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RefCountDisposable parent;
|
||||
lock (parentLock)
|
||||
{
|
||||
parent = _parent;
|
||||
_parent = null;
|
||||
}
|
||||
if (parent != null)
|
||||
parent.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Observable
|
||||
{
|
||||
static IObservable<T> AddRef<T>(IObservable<T> xs, RefCountDisposable r)
|
||||
{
|
||||
return Observable.Create<T>((IObserver<T> observer) => new CompositeDisposable(new IDisposable[]
|
||||
{
|
||||
r.GetDisposable(),
|
||||
xs.Subscribe(observer)
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2fb5a2cdb138579498eb20d8b7818ad8
|
||||
timeCreated: 1455373898
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db98ce742e859bd4e81db434c3ca3663
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06fb064ad9e4d354ab15ff89f6343243
|
||||
timeCreated: 1455373897
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ec869f7548c62748ad57a5c86b2f6ba
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace UniRx
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a group of disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
public abstract class StableCompositeDisposable : ICancelable
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new group containing two disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
|
||||
{
|
||||
if (disposable1 == null) throw new ArgumentNullException("disposable1");
|
||||
if (disposable2 == null) throw new ArgumentNullException("disposable2");
|
||||
|
||||
return new Binary(disposable1, disposable2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new group containing three disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable3">The third disposable resoruce to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
|
||||
{
|
||||
if (disposable1 == null) throw new ArgumentNullException("disposable1");
|
||||
if (disposable2 == null) throw new ArgumentNullException("disposable2");
|
||||
if (disposable3 == null) throw new ArgumentNullException("disposable3");
|
||||
|
||||
return new Trinary(disposable1, disposable2, disposable3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new group containing four disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
/// <param name="disposable1">The first disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable2">The second disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable3">The three disposable resoruce to add to the group.</param>
|
||||
/// <param name="disposable4">The four disposable resoruce to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
|
||||
{
|
||||
if (disposable1 == null) throw new ArgumentNullException("disposable1");
|
||||
if (disposable2 == null) throw new ArgumentNullException("disposable2");
|
||||
if (disposable3 == null) throw new ArgumentNullException("disposable3");
|
||||
if (disposable4 == null) throw new ArgumentNullException("disposable4");
|
||||
|
||||
return new Quaternary(disposable1, disposable2, disposable3, disposable4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new group of disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
/// <param name="disposables">Disposable resources to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable Create(params IDisposable[] disposables)
|
||||
{
|
||||
if (disposables == null) throw new ArgumentNullException("disposables");
|
||||
|
||||
return new NAry(disposables);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new group of disposable resources that are disposed together. Array is not copied, it's unsafe but optimized.
|
||||
/// </summary>
|
||||
/// <param name="disposables">Disposable resources to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable CreateUnsafe(IDisposable[] disposables)
|
||||
{
|
||||
return new NAryUnsafe(disposables);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new group of disposable resources that are disposed together.
|
||||
/// </summary>
|
||||
/// <param name="disposables">Disposable resources to add to the group.</param>
|
||||
/// <returns>Group of disposable resources that are disposed together.</returns>
|
||||
public static ICancelable Create(IEnumerable<IDisposable> disposables)
|
||||
{
|
||||
if (disposables == null) throw new ArgumentNullException("disposables");
|
||||
|
||||
return new NAry(disposables);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all disposables in the group.
|
||||
/// </summary>
|
||||
public abstract void Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether the object is disposed.
|
||||
/// </summary>
|
||||
public abstract bool IsDisposed
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
class Binary : StableCompositeDisposable
|
||||
{
|
||||
int disposedCallCount = -1;
|
||||
private volatile IDisposable _disposable1;
|
||||
private volatile IDisposable _disposable2;
|
||||
|
||||
public Binary(IDisposable disposable1, IDisposable disposable2)
|
||||
{
|
||||
_disposable1 = disposable1;
|
||||
_disposable2 = disposable2;
|
||||
}
|
||||
|
||||
public override bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return disposedCallCount != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref disposedCallCount) == 0)
|
||||
{
|
||||
_disposable1.Dispose();
|
||||
_disposable2.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Trinary : StableCompositeDisposable
|
||||
{
|
||||
int disposedCallCount = -1;
|
||||
private volatile IDisposable _disposable1;
|
||||
private volatile IDisposable _disposable2;
|
||||
private volatile IDisposable _disposable3;
|
||||
|
||||
public Trinary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
|
||||
{
|
||||
_disposable1 = disposable1;
|
||||
_disposable2 = disposable2;
|
||||
_disposable3 = disposable3;
|
||||
}
|
||||
|
||||
public override bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return disposedCallCount != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref disposedCallCount) == 0)
|
||||
{
|
||||
_disposable1.Dispose();
|
||||
_disposable2.Dispose();
|
||||
_disposable3.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Quaternary : StableCompositeDisposable
|
||||
{
|
||||
int disposedCallCount = -1;
|
||||
private volatile IDisposable _disposable1;
|
||||
private volatile IDisposable _disposable2;
|
||||
private volatile IDisposable _disposable3;
|
||||
private volatile IDisposable _disposable4;
|
||||
|
||||
public Quaternary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
|
||||
{
|
||||
_disposable1 = disposable1;
|
||||
_disposable2 = disposable2;
|
||||
_disposable3 = disposable3;
|
||||
_disposable4 = disposable4;
|
||||
}
|
||||
|
||||
public override bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return disposedCallCount != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref disposedCallCount) == 0)
|
||||
{
|
||||
_disposable1.Dispose();
|
||||
_disposable2.Dispose();
|
||||
_disposable3.Dispose();
|
||||
_disposable4.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NAry : StableCompositeDisposable
|
||||
{
|
||||
int disposedCallCount = -1;
|
||||
private volatile List<IDisposable> _disposables;
|
||||
|
||||
public NAry(IDisposable[] disposables)
|
||||
: this((IEnumerable<IDisposable>)disposables)
|
||||
{
|
||||
}
|
||||
|
||||
public NAry(IEnumerable<IDisposable> disposables)
|
||||
{
|
||||
_disposables = new List<IDisposable>(disposables);
|
||||
|
||||
//
|
||||
// Doing this on the list to avoid duplicate enumeration of disposables.
|
||||
//
|
||||
if (_disposables.Contains(null)) throw new ArgumentException("Disposables can't contains null", "disposables");
|
||||
}
|
||||
|
||||
public override bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return disposedCallCount != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref disposedCallCount) == 0)
|
||||
{
|
||||
foreach (var d in _disposables)
|
||||
{
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NAryUnsafe : StableCompositeDisposable
|
||||
{
|
||||
int disposedCallCount = -1;
|
||||
private volatile IDisposable[] _disposables;
|
||||
|
||||
public NAryUnsafe(IDisposable[] disposables)
|
||||
{
|
||||
_disposables = disposables;
|
||||
}
|
||||
|
||||
public override bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
return disposedCallCount != -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (Interlocked.Increment(ref disposedCallCount) == 0)
|
||||
{
|
||||
var len = _disposables.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
_disposables[i].Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3a9cd9fa22bc6a5439484581f5049cf8
|
||||
timeCreated: 1455373898
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a .NET event invocation consisting of the strongly typed object that raised the event and the data that was generated by the event.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender">
|
||||
/// 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.
|
||||
/// </typeparam>
|
||||
/// <typeparam name="TEventArgs">
|
||||
/// 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.
|
||||
/// </typeparam>
|
||||
public interface IEventPattern<TSender, TEventArgs>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the sender object that raised the event.
|
||||
/// </summary>
|
||||
TSender Sender { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event data that was generated by the event.
|
||||
/// </summary>
|
||||
TEventArgs EventArgs { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a .NET event invocation consisting of the weakly typed object that raised the event and the data that was generated by the event.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
|
||||
public class EventPattern<TEventArgs> : EventPattern<object, TEventArgs>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new data representation instance of a .NET event invocation with the given sender and event data.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender object that raised the event.</param>
|
||||
/// <param name="e">The event data that was generated by the event.</param>
|
||||
public EventPattern(object sender, TEventArgs e)
|
||||
: base(sender, e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a .NET event invocation consisting of the strongly typed object that raised the event and the data that was generated by the event.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender">The type of the sender that raised the event.</typeparam>
|
||||
/// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
|
||||
public class EventPattern<TSender, TEventArgs> : IEquatable<EventPattern<TSender, TEventArgs>>, IEventPattern<TSender, TEventArgs>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new data representation instance of a .NET event invocation with the given sender and event data.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender object that raised the event.</param>
|
||||
/// <param name="e">The event data that was generated by the event.</param>
|
||||
public EventPattern(TSender sender, TEventArgs e)
|
||||
{
|
||||
Sender = sender;
|
||||
EventArgs = e;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sender object that raised the event.
|
||||
/// </summary>
|
||||
public TSender Sender { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event data that was generated by the event.
|
||||
/// </summary>
|
||||
public TEventArgs EventArgs { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the current EventPattern<TSender, TEventArgs> object represents the same event as a specified EventPattern<TSender, TEventArgs> object.
|
||||
/// </summary>
|
||||
/// <param name="other">An object to compare to the current EventPattern<TSender, TEventArgs> object.</param>
|
||||
/// <returns>true if both EventPattern<TSender, TEventArgs> objects represent the same event; otherwise, false.</returns>
|
||||
public bool Equals(EventPattern<TSender, TEventArgs> other)
|
||||
{
|
||||
if (object.ReferenceEquals(null, other))
|
||||
return false;
|
||||
if (object.ReferenceEquals(this, other))
|
||||
return true;
|
||||
|
||||
return EqualityComparer<TSender>.Default.Equals(Sender, other.Sender) && EqualityComparer<TEventArgs>.Default.Equals(EventArgs, other.EventArgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified System.Object is equal to the current EventPattern<TSender, TEventArgs>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The System.Object to compare with the current EventPattern<TSender, TEventArgs>.</param>
|
||||
/// <returns>true if the specified System.Object is equal to the current EventPattern<TSender, TEventArgs>; otherwise, false.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as EventPattern<TSender, TEventArgs>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for the current EventPattern<TSender, TEventArgs> instance.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the current EventPattern<TSender, TEventArgs> instance.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var x = EqualityComparer<TSender>.Default.GetHashCode(Sender);
|
||||
var y = EqualityComparer<TEventArgs>.Default.GetHashCode(EventArgs);
|
||||
return (x << 5) + (x ^ y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two specified EventPattern<TSender, TEventArgs> objects represent the same event.
|
||||
/// </summary>
|
||||
/// <param name="first">The first EventPattern<TSender, TEventArgs> to compare, or null.</param>
|
||||
/// <param name="second">The second EventPattern<TSender, TEventArgs> to compare, or null.</param>
|
||||
/// <returns>true if both EventPattern<TSender, TEventArgs> objects represent the same event; otherwise, false.</returns>
|
||||
public static bool operator ==(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second)
|
||||
{
|
||||
return object.Equals(first, second);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two specified EventPattern<TSender, TEventArgs> objects represent a different event.
|
||||
/// </summary>
|
||||
/// <param name="first">The first EventPattern<TSender, TEventArgs> to compare, or null.</param>
|
||||
/// <param name="second">The second EventPattern<TSender, TEventArgs> to compare, or null.</param>
|
||||
/// <returns>true if both EventPattern<TSender, TEventArgs> objects don't represent the same event; otherwise, false.</returns>
|
||||
public static bool operator !=(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second)
|
||||
{
|
||||
return !object.Equals(first, second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e4b797bfea1999a499309068b7d7a97e
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7147cf40e45d9b7468957f2d28b1f2f0
|
||||
folderAsset: yes
|
||||
timeCreated: 1455373896
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// this code is borrowed from RxOfficial(rx.codeplex.com) and modified
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UniRx.InternalUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Asynchronous lock.
|
||||
/// </summary>
|
||||
internal sealed class AsyncLock : IDisposable
|
||||
{
|
||||
private readonly Queue<Action> queue = new Queue<Action>();
|
||||
private bool isAcquired = false;
|
||||
private bool hasFaulted = false;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="action">Action to queue for execution.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the work items in the queue and drops further work being queued.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (queue)
|
||||
{
|
||||
queue.Clear();
|
||||
hasFaulted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 23dbd656cfe9c5e47b02c3c263e476aa
|
||||
timeCreated: 1455373897
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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<T> : TaskCompletionSource<T>, ICancellableTaskCompletionSource
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 622c7ba8630c25b4c911cd1612ee0887
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 94d5d10805124b34c8b488ebf3f893eb
|
||||
timeCreated: 1509016318
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
|
||||
namespace UniRx.InternalUtil
|
||||
{
|
||||
// ImmutableList is sometimes useful, use for public.
|
||||
public class ImmutableList<T>
|
||||
{
|
||||
public static readonly ImmutableList<T> Empty = new ImmutableList<T>();
|
||||
|
||||
T[] data;
|
||||
|
||||
public T[] Data
|
||||
{
|
||||
get { return data; }
|
||||
}
|
||||
|
||||
ImmutableList()
|
||||
{
|
||||
data = new T[0];
|
||||
}
|
||||
|
||||
public ImmutableList(T[] data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ImmutableList<T> Add(T value)
|
||||
{
|
||||
var newData = new T[data.Length + 1];
|
||||
Array.Copy(data, newData, data.Length);
|
||||
newData[data.Length] = value;
|
||||
return new ImmutableList<T>(newData);
|
||||
}
|
||||
|
||||
public ImmutableList<T> 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<T>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dbafd8a41f556ec40b4bbd46fca2e85c
|
||||
timeCreated: 1455373901
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace UniRx.InternalUtil
|
||||
{
|
||||
public class ListObserver<T> : IObserver<T>
|
||||
{
|
||||
private readonly ImmutableList<IObserver<T>> _observers;
|
||||
|
||||
public ListObserver(ImmutableList<IObserver<T>> 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<T> Add(IObserver<T> observer)
|
||||
{
|
||||
return new ListObserver<T>(_observers.Add(observer));
|
||||
}
|
||||
|
||||
internal IObserver<T> Remove(IObserver<T> 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<T>(_observers.Remove(observer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EmptyObserver<T> : IObserver<T>
|
||||
{
|
||||
public static readonly EmptyObserver<T> Instance = new EmptyObserver<T>();
|
||||
|
||||
EmptyObserver()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ThrowObserver<T> : IObserver<T>
|
||||
{
|
||||
public static readonly ThrowObserver<T> Instance = new ThrowObserver<T>();
|
||||
|
||||
ThrowObserver()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
error.Throw();
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DisposedObserver<T> : IObserver<T>
|
||||
{
|
||||
public static readonly DisposedObserver<T> Instance = new DisposedObserver<T>();
|
||||
|
||||
DisposedObserver()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
throw new ObjectDisposedException("");
|
||||
}
|
||||
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
throw new ObjectDisposedException("");
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
{
|
||||
throw new ObjectDisposedException("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 889dc2f3c5f44d24a98a2c25510b4346
|
||||
timeCreated: 1455373900
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UniRx.InternalUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple supports(only yield return null) lightweight, threadsafe coroutine dispatcher.
|
||||
/// </summary>
|
||||
public class MicroCoroutine
|
||||
{
|
||||
const int InitialSize = 16;
|
||||
|
||||
readonly object runningAndQueueLock = new object();
|
||||
readonly object arrayLock = new object();
|
||||
readonly Action<Exception> unhandledExceptionCallback;
|
||||
|
||||
int tail = 0;
|
||||
bool running = false;
|
||||
IEnumerator[] coroutines = new IEnumerator[InitialSize];
|
||||
Queue<IEnumerator> waitQueue = new Queue<IEnumerator>();
|
||||
|
||||
public MicroCoroutine(Action<Exception> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 108be6d634275c94a95eeb2a39de0792
|
||||
timeCreated: 1462599042
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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<T> where T : IComparable<T>
|
||||
{
|
||||
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<T>.Default.Equals(_items[i].Value, item))
|
||||
{
|
||||
RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct IndexedItem : IComparable<IndexedItem>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7956b408e24dc5a4884fe4f5a3d7c858
|
||||
timeCreated: 1455373899
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue