Skip to content

Commit

Permalink
experiment with "external" observables once again
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniil Korostelev committed Jun 21, 2024
1 parent 4e53998 commit 06e6bed
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 21 deletions.
51 changes: 31 additions & 20 deletions playground/Playground.cs
Original file line number Diff line number Diff line change
@@ -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();
}
Expand Down
90 changes: 90 additions & 0 deletions src/TinkState/Runtime/ExternalObservable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace TinkState.Internal
{
class ExternalObservable<T> : Dispatcher, Observable<T>, DispatchingObservable<T>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public T Value => AutoObservable.Track(this);

readonly Func<T> getter;
readonly Action<Action> wakeup;
readonly Action sleep;
readonly IEqualityComparer<T> comparer;

T last;
bool isDirty;
bool isSubscribedTo;

public ExternalObservable(Func<T> getter, Action<Action> wakeup, Action sleep, IEqualityComparer<T> comparer)
{
this.getter = getter;
this.wakeup = wakeup;
this.sleep = sleep;
this.comparer = comparer ?? EqualityComparer<T>.Default;
isDirty = true;
}

public IDisposable Bind(Action<T> callback, IEqualityComparer<T> comparer = null, Scheduler scheduler = null)
{
return Binding<T>.Create(this, callback, comparer, scheduler);
}

public Observable<TOut> Map<TOut>(Func<T, TOut> transform, IEqualityComparer<TOut> comparer = null)
{
return TransformObservable.Create(this, transform, comparer);
}

public IEqualityComparer<T> 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();
}
}
}
}
7 changes: 6 additions & 1 deletion src/TinkState/Runtime/Observable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public static Observable<T> Auto<T>(Func<T> compute, IEqualityComparer<T> compar
return new AutoObservable<T>(new SyncComputation<T>(compute), comparer);
}

public static Observable<T> External<T>(Func<T> getter, Action<Action> wakeup, Action sleep, IEqualityComparer<T> comparer = null)
{
return new ExternalObservable<T>(getter, wakeup, sleep, comparer);
}

/// <summary>
/// <para>
/// Create an observable containing data computed using given <paramref name="compute"/> function.
Expand Down Expand Up @@ -220,4 +225,4 @@ public static ObservableDictionary<TKey, TValue> Dictionary<TKey, TValue>()
/// </remarks>
public static Scheduler Scheduler = Scheduler.Direct;
}
}
}

0 comments on commit 06e6bed

Please sign in to comment.