public IDisposable ListenUpdates(Action <T2> reaction) { var group = new CellJoinDisposable <T2>(); group.lastValue = value; Action <T> func = iVal => { if (group.disposed) { return; } var innerCell = map(iVal); if (@group.Second != null) { var innerVal = innerCell.value; if (!EqualityComparer <T2> .Default.Equals(group.lastValue, innerVal)) { reaction(innerVal); group.lastValue = innerVal; } @group.Second.Dispose(); } @group.Second = innerCell.ListenUpdates(val => { reaction(val); group.lastValue = val; }); }; @group.First = cell.Bind(func); return(group); }
public static ICell <T3> Merge <T, T2, T3>(this ICell <T> cell, ICell <T2> cell2, Func <T, T2, T3> func) { Func <T3> curr = () => func(cell.value, cell2.value); return(new AnonymousCell <T3>((Action <T3> reaction, Priority p) => { var disp = new CellJoinDisposable <T3>(); disp.lastValue = func(cell.value, cell2.value); disp.Add(cell.ListenUpdates(val => { T3 newCurr = curr(); if (!object.Equals(newCurr, disp.lastValue)) { disp.lastValue = newCurr; reaction(newCurr); } }, p)); disp.Add(cell2.ListenUpdates(val => { T3 newCurr = curr(); if (!object.Equals(newCurr, disp.lastValue)) { disp.lastValue = newCurr; reaction(newCurr); } }, p)); return disp; }, curr)); }
/* Pass plain formula and recieve fully subscribed reactive cell * * Example: * var relativeHp = Calculate(() = > { * if (monster.value == null) return 0; * return monster.value.hp.value / monster.maxHealth.value; * }); * * Restrictions: * 1 Do not do bind, listen, connections dispose or other operations. Write pure calculation code. * 2 Do not change state. Your formula should not mutate world. Only constant access. * 3 Do not use reactive values in code branches or it will not be subscribed properly. (May be fixed later) */ public static ICell <T> Calculate <T>(Func <T> formula) { calculationMode = true; var probe = formula(); calculationMode = false; var copyTouched = touched; touched = new List <ICell>(); return(new AnonymousCell <T>((Action <T> reaction, Priority p) => { CellJoinDisposable <T> group = new CellJoinDisposable <T>(); group.SetArray(copyTouched.Select(cell => cell.OnChanged(() => { var val = formula(); if (!object.Equals(group.lastValue, val)) { reaction(val); group.lastValue = val; } }, p))); group.lastValue = formula(); return group; }, () => formula())); }
public static ICell <IEnumerable <T> > ToCellOfCollection <T>(this IEnumerable <ICell <T> > cells) { Func <IEnumerable <T> > values = () => cells.Select(cell => cell.value); return(new AnonymousCell <IEnumerable <T> >((Action <IEnumerable <T> > reaction, Priority p) => { CellJoinDisposable <T> group = new CellJoinDisposable <T> { }; foreach (var cell in cells) { group.Add(cell.ListenUpdates(_ => reaction(values()), p)); } return group; }, values)); }
public IDisposable ListenUpdates(Action <T> reaction) { ICell <T> currInnerCell = cell.value; CheckInnerCell(currInnerCell); var group = new CellJoinDisposable <T>(); Action <ICell <T> > func = innerCell => { if (group.disposed) { return; } CheckInnerCell(innerCell); if (group.Second != null) { var innerVal = innerCell.value; if (!EqualityComparer <T> .Default.Equals(group.lastValue, innerVal)) { reaction(innerVal); group.lastValue = innerVal; } group.Second.Dispose(); } group.Second = innerCell.ListenUpdates(val => { reaction(val); group.lastValue = val; }); }; group.lastValue = currInnerCell.value; func(cell.value); group.First = cell.ListenUpdates(func); return(group); }
static public IStream <T> Join <T>(this ICell <IStream <T> > cell) { return(new AnonymousStream <T>((Action <T> reaction, Priority p) => { SingleAssignmentDisposable mainDisposable = new SingleAssignmentDisposable(); SingleAssignmentDisposable inner = new SingleAssignmentDisposable(); CellJoinDisposable <T> group = new CellJoinDisposable <T> { mainDisposable, inner }; Action <IStream <T> > func = (IStream <T> innerStream) => { inner.Dispose(); if (innerStream != null) { inner.Disposable = innerStream.Listen(reaction, p); } }; mainDisposable.Disposable = cell.Bind(func, p); return group; })); }
public static ICell <T> Join <T>(this ICell <ICell <T> > cell) { return(new AnonymousCell <T>((Action <T> reaction, Priority p) => { SingleAssignmentDisposable mainDisposable = new SingleAssignmentDisposable(); SingleAssignmentDisposable inner = new SingleAssignmentDisposable(); CellJoinDisposable <T> group = new CellJoinDisposable <T> { mainDisposable, inner }; group.lastValue = cell.value.value; Action <ICell <T> > func = (ICell <T> innerCell) => { if (!inner.IsDisposed) { T value = innerCell.value; if (!object.Equals(group.lastValue, value)) { reaction(value); group.lastValue = value; } inner.Dispose(); } inner.Disposable = innerCell.ListenUpdates(val => { reaction(val); group.lastValue = val; }, p); }; func(cell.value); mainDisposable.Disposable = cell.ListenUpdates(func, p); return group; }, () => cell.value.value)); }