diff --git a/playground/Playground.cs b/playground/Playground.cs index 497a760..509fd40 100644 --- a/playground/Playground.cs +++ b/playground/Playground.cs @@ -1,34 +1,45 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using System.Timers; using TinkState; class Playground { - static async Task Main() + static void Main() { - var stateA = Observable.State("hello"); - var stateB = Observable.State("world"); + var timer = new Timer(1000); + ElapsedEventHandler timerElapsedHandler = null; - var o = Observable.Auto(async () => - { - Console.WriteLine("computing"); - var a = stateA.Value; - await Task.Delay(1000); - var b = stateB.Value; - return a + " " + b; - }); + var time = Observable.External( + () => DateTime.UtcNow, + invalidate => + { + Console.WriteLine("wakeup"); + timerElapsedHandler = (_, _) => + { + Console.WriteLine("tick"); + invalidate(); + }; + timer.Elapsed += timerElapsedHandler; + timer.Start(); + }, + () => + { + Console.WriteLine("sleep"); + timer.Elapsed -= timerElapsedHandler; + timer.Stop(); + } + ); - o.Bind(result => Console.WriteLine(result.Status switch + var counter = 0; + IDisposable binding = null; + binding = time.Bind(v => { - AsyncComputeStatus.Loading => "Loading...", - AsyncComputeStatus.Done => "Done: " + result.Result, - AsyncComputeStatus.Failed => "Failed: " + result.Exception, - })); - - await Task.Delay(1500); - - stateB.Value = "Dan"; + Console.WriteLine($"Current time is: {v}"); + counter++; + if (counter >= 5) binding.Dispose(); + }); Process.GetCurrentProcess().WaitForExit(); } diff --git a/src/TinkState/Runtime/ExternalObservable.cs b/src/TinkState/Runtime/ExternalObservable.cs new file mode 100644 index 0000000..a6e49d3 --- /dev/null +++ b/src/TinkState/Runtime/ExternalObservable.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace TinkState.Internal +{ + class ExternalObservable : Dispatcher, Observable, DispatchingObservable + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public T Value => AutoObservable.Track(this); + + readonly Func getter; + readonly Action wakeup; + readonly Action sleep; + readonly IEqualityComparer comparer; + + T last; + bool isDirty; + bool isSubscribedTo; + + public ExternalObservable(Func getter, Action wakeup, Action sleep, IEqualityComparer comparer) + { + this.getter = getter; + this.wakeup = wakeup; + this.sleep = sleep; + this.comparer = comparer ?? EqualityComparer.Default; + isDirty = true; + } + + public IDisposable Bind(Action callback, IEqualityComparer comparer = null, Scheduler scheduler = null) + { + return Binding.Create(this, callback, comparer, scheduler); + } + + public Observable Map(Func transform, IEqualityComparer comparer = null) + { + return TransformObservable.Create(this, transform, comparer); + } + + public IEqualityComparer GetComparer() + { + return comparer; + } + + public long GetRevision() + { + return revision; + } + + public T GetCurrentValue() + { + if (isDirty || !isSubscribedTo) RecalculateCurrentValue(); + return last; + } + + void RecalculateCurrentValue() + { + last = getter(); + isDirty = false; + } + + protected override void OnStatusChange(bool active) + { + if (active) WakeUp(); + else Sleep(); + } + + void WakeUp() + { + wakeup(Notify); + isSubscribedTo = true; + RecalculateCurrentValue(); + } + + void Sleep() + { + sleep(); + isSubscribedTo = false; + } + + void Notify() + { + if (!isDirty) + { + isDirty = true; + Fire(); + } + } + } +} diff --git a/src/TinkState/Runtime/Observable.cs b/src/TinkState/Runtime/Observable.cs index 36fb641..7ab2613 100644 --- a/src/TinkState/Runtime/Observable.cs +++ b/src/TinkState/Runtime/Observable.cs @@ -99,6 +99,11 @@ public static Observable Auto(Func compute, IEqualityComparer compar return new AutoObservable(new SyncComputation(compute), comparer); } + public static Observable External(Func getter, Action wakeup, Action sleep, IEqualityComparer comparer = null) + { + return new ExternalObservable(getter, wakeup, sleep, comparer); + } + /// /// /// Create an observable containing data computed using given function. @@ -220,4 +225,4 @@ public static ObservableDictionary Dictionary() /// public static Scheduler Scheduler = Scheduler.Direct; } -} \ No newline at end of file +}