public async Task SuppressTest() { var stateFactory = Services.StateFactory(); var time = Services.GetRequiredService <ITimeService>(); var count1 = 0; var count2 = 0; #pragma warning disable 1998 var s1 = await stateFactory.NewComputed <int>(async (s, ct) => count1++).Update(); var s2 = await stateFactory.NewComputed <int>(async (s, ct) => count2++).Update(); #pragma warning restore 1998 var s12 = await stateFactory.NewComputed <(int, int)>( async (s, cancellationToken) => { var a = await s1.Use(cancellationToken); using var _ = Computed.SuspendDependencyCapture(); var b = await s2.Use(cancellationToken); return(a, b); }).Update(); var v12a = await s12.Use(); s1.Computed.Invalidate(); // Should increment c1 & impact c12 var v12b = await s12.Use(); v12b.Should().Be((v12a.Item1 + 1, v12a.Item2)); s2.Computed.Invalidate(); // Should increment c2, but shouldn't impact c12 var v12c = await s12.Use(); v12c.Should().Be(v12b); }
public void Increment(string key) { WriteLine($"{nameof(Increment)}({key})"); _counters.AddOrUpdate(key, k => 1, (k, v) => v + 1); using (Computed.Invalidate()) Get(key).Ignore(); }
public static async Task IncrementCounter() { #region Part02_IncrementCounter var counters = CreateServices().GetRequiredService <CounterService>(); Task.Run(async() => { for (var i = 0; i <= 5; i++) { await Task.Delay(1000); counters.Increment("a"); } }).Ignore(); var computed = await Computed.Capture(_ => counters.Get("a")); WriteLine($"{DateTime.Now}: {computed.Value}"); for (var i = 0; i < 5; i++) { await computed.WhenInvalidated(); computed = await computed.Update(); WriteLine($"{DateTime.Now}: {computed.Value}"); } #endregion }
public ComputedCollection(Func <IEnumerable <T> > getMethod) { _getMethod = getMethod; _depCollection = new Computed(OnUpdateCollection); _depCollection.Invalidated += () => UpdateScheduler.ScheduleUpdate(UpdateNow); _depCollection.Touch(); }
public virtual async Task EditUser(EditUserCommand command, CancellationToken cancellationToken = default) { var session = command.Session; var context = CommandContext.GetCurrent(); if (Computed.IsInvalidating()) { var invSessionInfo = context.Operation().Items.Get <SessionInfo>(); TryGetUser(invSessionInfo.UserId, default).Ignore(); return; } var sessionInfo = await GetSessionInfo(session, cancellationToken).ConfigureAwait(false); if (!sessionInfo.IsAuthenticated) { throw Errors.NotAuthenticated(); } await using var dbContext = await CreateCommandDbContext(cancellationToken).ConfigureAwait(false); var longUserId = long.Parse(sessionInfo.UserId); var dbUser = await Users.TryGet(dbContext, longUserId, cancellationToken).ConfigureAwait(false); if (dbUser == null) { throw Internal.Errors.EntityNotFound(Users.UserEntityType); } await Users.Edit(dbContext, dbUser, command, cancellationToken).ConfigureAwait(false); context.Operation().Items.Set(sessionInfo); }
private async Task <IComputed <Screenshot> > GetScreenshotComputedAsync() { var screenshots = Services.GetRequiredService <IScreenshotService>(); var computed = await Computed.CaptureAsync(_ => screenshots.GetScreenshotAsync(1280)); return(computed); }
public async Task BasicTest() { var kvs = Services.GetRequiredService <IKeyValueStore>(); var c1 = await Computed.Capture(_ => kvs.Get("1")); var c2 = await Computed.Capture(_ => kvs.Get("2")); var c3 = await Computed.Capture(_ => kvs.Get("3")); c1.Value.Should().BeNull(); c2.Value.Should().BeNull(); c3.Value.Should().BeNull(); var commander = Services.Commander(); var command = new NestedOperationLoggerTester.SetManyCommand( new[] { "1", "2", "3" }, "v"); await commander.Call(command); c1.IsInvalidated().Should().BeTrue(); c2.IsInvalidated().Should().BeTrue(); c3.IsInvalidated().Should().BeTrue(); c1 = await c1.Update(); c2 = await c2.Update(); c3 = await c3.Update(); c1.Value.Should().Be("v3"); c2.Value.Should().Be("v2"); c3.Value.Should().Be("v1"); }
public async Task Test1() { var epsilon = TimeSpan.FromSeconds(0.5); await using var serving = await WebSocketHost.ServeAsync(); var client = Services.GetRequiredService <IClientTimeService>(); var cTime = await Computed.CaptureAsync(_ => client.GetTimeAsync()); cTime.Options.AutoInvalidateTime.Should().Be(ComputedOptions.Default.AutoInvalidateTime); if (!cTime.IsConsistent()) { cTime = await cTime.UpdateAsync(false); cTime.IsConsistent().Should().BeTrue(); } (DateTime.Now - cTime.Value).Should().BeLessThan(epsilon); await TestEx.WhenMetAsync( () => cTime.IsConsistent().Should().BeFalse(), TimeSpan.FromSeconds(5)); var time = await cTime.UseAsync(); (DateTime.Now - time).Should().BeLessThan(epsilon); }
public async Task InvalidateEverythingTest() { var users = Services.GetRequiredService <IUserService>(); // We need at least 1 user to see count invalidation messages await users.Create(new(new User() { Id = int.MaxValue, Name = "Chuck Norris", })); var u1 = await users.TryGet(int.MaxValue); var c1 = await Computed.Capture(_ => users.Count()); users.Invalidate(); var u2 = await users.TryGet(int.MaxValue); var c2 = await Computed.Capture(_ => users.Count()); u2.Should().NotBeSameAs(u1); u2 !.Id.Should().Be(u1 !.Id); u2.Name.Should().Be(u1.Name); c2.Should().NotBeSameAs(c1); c2 !.Value.Should().Be(c1 !.Value); }
public async Task BasicTest() { var liveClock = Services.GetRequiredService <ILiveClock>(); var cTime = await Computed.Capture(_ => liveClock.GetUtcNow()); cTime.IsConsistent().Should().BeTrue(); (DateTime.UtcNow - cTime.Value).Should().BeLessThan(TimeSpan.FromSeconds(1.1)); await Delay(1.3); cTime.IsConsistent().Should().BeFalse(); cTime = await Computed.Capture(_ => liveClock.GetUtcNow(TimeSpan.FromMilliseconds(200))); cTime.IsConsistent().Should().BeTrue(); await Delay(0.25); cTime.IsConsistent().Should().BeFalse(); var now = DateTime.UtcNow; var ago = await liveClock.GetMomentsAgo(now); ago.Should().Be("just now"); await Delay(1.8); ago = await liveClock.GetMomentsAgo(now); ago.Should().Be("1 second ago"); }
public async Task AutoRecomputeTest() { var stateFactory = Services.StateFactory(); var time = Services.GetRequiredService <ITimeService>(); var c = await Computed.Capture( _ => time.GetTimeWithOffset(TimeSpan.FromSeconds(1))); var count = 0L; using var state = stateFactory.NewComputed <DateTime>( UpdateDelayer.ZeroUpdateDelay, async(_, ct) => await c.Use(ct)); state.Updated += (s, _) => Log.LogInformation($"{++count} -> {s.Value:hh:mm:ss:fff}"); await TestEx.WhenMet( () => count.Should().BeGreaterThan(2), TimeSpan.FromSeconds(5)); var lastCount = count; state.Dispose(); await Task.Delay(1000); count.Should().Be(lastCount); }
public async Task InvalidationAndCachingTest2() { // TODO: Fix the test so that it starts right after the time invalidation, // otherwise it has a tiny chance of failure var time = Services.GetRequiredService <ITimeService>(); var c1 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); c1.Should().NotBeNull(); var c2 = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c2.Should().NotBeNull(); c1.Should().NotBeSameAs(c2); var c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); var c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c1.Should().BeSameAs(c1a); c2.Should().BeSameAs(c2a); // Wait for time invalidation await Task.Delay(500); c1a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(1))); c2a = await Computed.CaptureAsync(_ => time.GetTimeWithOffsetAsync(TimeSpan.FromSeconds(2))); c1.Should().NotBeSameAs(c1a); c2.Should().NotBeSameAs(c2a); }
public Task AddLoggingRecord(LoggingRecord loggingRecord) { database.Add(loggingRecord); using (Computed.Invalidate()) GetLatest().Ignore(); return(Task.CompletedTask); }
public static async Task <IPublication <T>?> TryPublish <T>( this IPublisher publisher, Func <CancellationToken, Task <T> > producer, CancellationToken cancellationToken = default) { var computed = await Computed .Capture(producer, cancellationToken) .ConfigureAwait(false); if (computed == null) { return(null); } var publication = (IPublication <T>)publisher.Publish(computed); // Publication doesn't have to be "in sync" with the computed // we requested it for (i.e. it might still point to its older, // inconsistent version), so we have to update it here. try { await publication.Update(cancellationToken); } catch (OperationCanceledException) { throw; } catch { // Intended, it's fine to publish a computed w/ an error } return(publication); }
public Task Increment(CancellationToken cancellationToken = default) { Interlocked.Increment(ref _count); using (Computed.Invalidate()) Get(cancellationToken); return(Task.CompletedTask); }
public MainViewModel() { // init this.Sum = Computed <int> .Of(this, nameof(Sum)) .Observe(nameof(Num1), nameof(Num2)) .ComputeAs(me => me.Num1 + me.Num2) .Build(); }
public virtual void Invalidate() { if (!IsCaching) { return; } Computed.Invalidate(Everything); }
public virtual Task <TimeSpan> GetUptime(TimeSpan updatePeriod, CancellationToken cancellationToken = default) { var computed = Computed.GetCurrent(); Task.Delay(updatePeriod, default) .ContinueWith(_ => computed !.Invalidate(), CancellationToken.None); return(Task.FromResult(DateTime.UtcNow - _startTime)); }
public ComputedSubscription(Computed computed, Action update) { _computed = computed; _update = update; _computed.Invalidated += Computed_Invalidated; Computed_Invalidated(); }
public Personnage() { Caractéristiques = new Caractéristiques(); _reflexe = Computed.From(() => _classes.Sum(setable => setable.Reflexe) + Caractéristiques.Dexterite.Modificateur); _vigueur = Computed.From(() => _classes.Sum(setable => setable.Vigueur) + Caractéristiques.Constitution.Modificateur); _volonte = Computed.From(() => _classes.Sum(setable => setable.Volonte) + Caractéristiques.Sagesse.Modificateur); _bonusDeBaseAttaque = Computed.From(() => _classes.Sum(classe => classe.BonusDeBaseAttaque)); }
public Classe(Description.Classe classe) { _classe = classe; _reflexe = Computed.From(() => _classe.Sauvegardes.Reflexe(Niveau)); _vigueur = Computed.From(() => _classe.Sauvegardes.Vigueur(Niveau)); _volonte = Computed.From(() => _classe.Sauvegardes.Volonte(Niveau)); _bonusDeBaseAttaque = Computed.From(() => _classe.BonusDeBaseAttaque(Niveau)); }
public virtual Task <double> GetUptime(double updatePeriod, CancellationToken cancellationToken = default) { var computed = Computed.GetCurrent(); Task.Delay(TimeSpan.FromSeconds(updatePeriod), default) .ContinueWith(_ => computed !.Invalidate(), CancellationToken.None); return(Task.FromResult((DateTime.UtcNow - _startTime).TotalSeconds)); }
public Tree() { _depNodes = new Computed(delegate { _root.UpdateNodes(); }); _depNodes.Invalidated += () => UpdateScheduler.ScheduleUpdate(UpdateNow); }
public Projection(Observable <string> prefix, Contact contact) { _prefix = prefix; _contact = contact; _name = new Computed <string>(() => prefix.Value + _contact.FirstName + _contact.LastName); }
protected override async ValueTask <IComputed <T> > ComputeAsync( InterceptedInput input, IComputed <T>?cached, CancellationToken cancellationToken) { var tag = LTagGenerator.Next(); var method = Method; var output = new Computed <InterceptedInput, T>(method.Options, input, tag); try { using var _ = Computed.ChangeCurrent(output); var resultTask = input.InvokeOriginalFunction(cancellationToken); if (method.ReturnsComputed) { if (method.ReturnsValueTask) { var task = (ValueTask <IComputed <T> >)resultTask; await task.ConfigureAwait(false); // output == task.Result here, so no need to call output.TrySetOutput(...) } else { var task = (Task <IComputed <T> >)resultTask; await task.ConfigureAwait(false); // output == task.Result here, so no need to call output.TrySetOutput(...) } } else { if (method.ReturnsValueTask) { var task = (ValueTask <T>)resultTask; var value = await task.ConfigureAwait(false); output.TrySetOutput(value !); } else { var task = (Task <T>)resultTask; var value = await task.ConfigureAwait(false); output.TrySetOutput(value !); } } } catch (OperationCanceledException) { throw; } catch (Exception e) { output.TrySetOutput(Result.Error <T>(e)); // Weird case: if the output is already set, all we can // is to ignore the exception we've just caught; // throwing it further will probably make it just worse, // since the the caller have to take this scenario into acc. } return(output); }
public void Initialize() { _gained = false; _observable = new NotifyingObservable(); _observable.OnGainComputed += () => { _gained = true; }; _observable.OnLoseComputed += () => { _lost = true; }; _computed = new Computed(() => { _observable.OnGet(); }); _secondComputed = new Computed(() => { _observable.OnGet(); }); }
public OrderCalculationEngine(IDataService data) : base() { // inputs _inventory = Setable(data.LoadInventory(), "Inventory"); _order = Setable(data.LoadOrder(), "Order"); // outputs _orderResult = Computed(() => OrderMethods.GetOrderResults(_order, _inventory), "OrderResult"); }
public async Task OnCommandAsync(ICompletion command, CommandContext context, CancellationToken cancellationToken) { var originalCommand = command.UntypedCommand; var requiresInvalidation = InvalidationInfoProvider.RequiresInvalidation(originalCommand) && !Computed.IsInvalidating(); if (!requiresInvalidation) { await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); return; } var oldOperation = context.Items.TryGet <IOperation>(); var operation = command.Operation; context.SetOperation(operation); var invalidateScope = Computed.Invalidate(); try { var logEnabled = LogLevel != LogLevel.None && Log.IsEnabled(LogLevel); var finalHandler = context.ExecutionState.FindFinalHandler(); if (finalHandler != null) { if (logEnabled) { Log.Log(LogLevel, "Invalidating via dedicated command handler for '{CommandType}'", command.GetType()); } await context.InvokeRemainingHandlersAsync(cancellationToken).ConfigureAwait(false); } else { if (logEnabled) { Log.Log(LogLevel, "Invalidating via shared command handler for '{CommandType}'", originalCommand.GetType()); } await context.Commander.CallAsync(originalCommand, cancellationToken).ConfigureAwait(false); } var operationItems = operation.Items; try { var nestedCommands = operationItems.GetOrDefault(ImmutableList <NestedCommandEntry> .Empty); if (!nestedCommands.IsEmpty) { await InvokeNestedCommandsAsync(context, operation, nestedCommands, cancellationToken); } } finally { operation.Items = operationItems; } } finally { context.SetOperation(oldOperation); invalidateScope.Dispose(); } }
public Task IncrementCounterAsync() { lock (_lock) { ++_count; _changeTime = DateTime.Now; } Computed.Invalidate(() => GetCounterAsync()); return(Task.CompletedTask); }
public override string ToString() { if (Computed.Type == ECssValueTypes.INTEGER) { return(Enum.GetName(typeof(Ty), Computed.AsEnum <Ty>())); } return(base.ToString()); }
public MethodCommand(object instance, CommandMeta meta) { Instance = instance; Meta = meta; if (meta.Condition != null) { _computedCan = new Computed<bool>(() => (bool)meta.Condition.GetValue(Instance)); _computedCan.Invalidated += () => UpdateScheduler.ScheduleUpdate(UpdateNow); } }
public Task Increment() { lock (_lock) { ++_count; _changeTime = DateTime.Now; } using (Computed.Invalidate()) Get(); return(Task.CompletedTask); }
public ObjectPropertyCollection(IObjectInstance objectInstance, ClassProperty classProperty) : base(objectInstance, classProperty) { if (ClassProperty.CanRead) { // When the collection is out of date, update it from the wrapped object. _depCollection = new Computed(OnUpdateCollection); // When the property becomes out of date, trigger an update. _depCollection.Invalidated += TriggerUpdate; } }
public MediaCacheService( CommuterApplication application, Func<Queue, MediaDownloader> createMediaDownloader) { var mediaDownloaders = new ComputedList<MediaDownloader>(() => application.Root?.QueuedEpisodes.Select(e => createMediaDownloader(e)) .ToImmutableList() ?? ImmutableList<MediaDownloader>.Empty); var dowloadersToStart = new Computed<ImmutableList<MediaDownloader>>(() => mediaDownloaders.Where(d => d.ShouldStart).ToImmutableList()); _subscribeToStart = dowloadersToStart.Subscribe(StartDownloaders); }
public ObjectPropertyCollection(IObjectInstance objectInstance, ClassProperty classProperty, bool hasChildObjects) : base(objectInstance, classProperty) { _hasChildObjects = hasChildObjects; if (ClassProperty.CanRead) { // Bind to the observable collection. ClassProperty.SetUserOutput(ObjectInstance, _collection); // When the collection is out of date, update it from the wrapped object. _depCollection = new Computed(OnUpdateCollection); } }
public void CanSubscribeToAComputed() { Observable<int> source = new Observable<int>(); Computed<int> target = new Computed<int>(() => source); int count = 0; target.Subscribe(i => count++); Process(); count.Should().Be(1); source.Value = 42; Process(); count.Should().Be(2); }
protected MemberSlot(ViewProxy proxy, MemberMeta member) { Proxy = proxy; Member = member; if (member.CanRead) { // When the property is out of date, update it from the wrapped object. _computed = new Computed(() => BindingInterceptor.Current.UpdateValue(this)); // When the property becomes out of date, trigger an update. // The update should have lower priority than user input & drawing, // to ensure that the app doesn't lock up in case a large model is // being updated outside the UI (e.g. via timers or the network). _computed.Invalidated += () => UpdateScheduler.ScheduleUpdate(UpdateNow); } }
public ObjectPropertyAtom(IObjectInstance objectInstance, ClassProperty classProperty, bool hasChildObject) : base(objectInstance, classProperty) { _hasChildObject = hasChildObject; if (ClassProperty.CanRead) { // When the property is out of date, update it from the wrapped object. _depProperty = new Computed(delegate { object value = ClassProperty.GetObjectValue(ObjectInstance.WrappedObject); if (_hasChildObject) { IObjectInstance oldChild = _child; object oldValue = oldChild == null ? null : oldChild.WrappedObject; _child = null; IObjectInstance wrapper; if (value == null) wrapper = null; else if (value == oldValue) { wrapper = oldChild; _child = wrapper; } else { if (WrapObject(value, out wrapper)) _child = wrapper; } ClassProperty.SetUserOutput(ObjectInstance, wrapper); if (oldChild != _child && oldChild != null) { ObjectInstance.Tree.RemoveKey(oldValue); oldChild.Dispose(); } } else { ClassProperty.SetUserOutput(ObjectInstance, value); } }); } }
public void CanUnsubscribeFromAComputed() { Observable<int> source = new Observable<int>(); Computed<int> target = new Computed<int>(() => source); int count = 0; var subscription = target.Subscribe(i => count++); Process(); count.Should().Be(1); source.Value = 42; Process(); count.Should().Be(2); subscription.Unsubscribe(); source.Value = 24; Process(); count.Should().Be(2); }
public void ComputedIsAsSmallAsPossible() { GC.Collect(); long start = GC.GetTotalMemory(true); Computed<int> newComputed = new Computed<int>(() => 42); long end = GC.GetTotalMemory(true); // Started at 260. // Making Precedent a base class: 248. // Removing Gain/LoseComputed events: 232. // Making IsUpToDate no longer a precident: 192. // Custom linked list implementation for dependents: 152. // Custom linked list implementation for precedents: 112. // Other optimizations: 104. // Added WeakReferenceToSelf: 108. // Removed WeakReferenceToSelf: 104. Assert.AreEqual(108 + ComputedPlatformOffset, end - start); int value = newComputed; Assert.AreEqual(42, value); }
public void OuterComputedDoesNotTakeADependency() { Observable<int> source = new Observable<int>(); Computed<Counter> outer = new Computed<Counter>(() => new Counter(source)); int created = 0; Counter counter = null; outer.Subscribe(c => { counter = c; created++; }); Process(); created.Should().Be(1); counter.Count.Should().Be(1); source.Value = 42; Process(); created.Should().Be(1); counter.Count.Should().Be(2); }
public DirectComputed(SourceData source) { _source = source; _property = new Computed<int>(() => _source.SourceProperty); }
public Caractéristique() { _carac = new Setable<int>(); _modificateur = new Computed<int>(() => (Carac - 10) / 2); }
public TargetCollection(SourceCollection source) { _source = source; _depResults = new Computed(UpdateResults); }
public ViewModelContainer(Action firePropertyChanged, Func<object> constructor) { _firePropertyChanged = firePropertyChanged; _computed = new Computed(() => _viewModel = ForView.Wrap(constructor())); _computed.Invalidated += () => UpdateScheduler.ScheduleUpdate(UpdateNow); }
public void SingleDependencyBeforeUpdateIsAsSmallAsPossible() { GC.Collect(); long start = GC.GetTotalMemory(true); Observable<int> newObservable = new Observable<int>(); Computed<int> newComputed = new Computed<int>(() => newObservable); newObservable.Value = 42; long end = GC.GetTotalMemory(true); // Started at 336. // Making Precedent a base class: 312. // Removing Gain/LoseComputed events: 288. // Making IsUpToDate no longer a precident: 248. // Custom linked list implementation for dependents: 200. // Custom linked list implementation for precedents: 160. // Other optimizations: 144. // Added WeakReferenceToSelf: 148. // Removed WeakReferenceToSelf: 124. Assert.AreEqual(132 + ObservablePlatformOffset, end - start); int value = newComputed; Assert.AreEqual(42, value); }
public Counter(Observable<int> source) { _target = new Computed<int>(() => source.Value); _target.Subscribe(i => _count++); }
public IndirectComputed(DirectComputed indermediateComputed) { _indermediateComputed = indermediateComputed; _property = new Computed<int>(() => _indermediateComputed.ComputedProperty); }
public Projection(Observable<string> prefix, Contact contact) { _prefix = prefix; _contact = contact; _name = new Computed<string>(() => prefix.Value + _contact.FirstName + _contact.LastName); }