Skip to content

Commit

Permalink
OnItemAdded behaves as a list if the rest implements it
Browse files Browse the repository at this point in the history
  • Loading branch information
YohDeadfall committed Jul 4, 2024
1 parent c415d2e commit 28cca98
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 5 deletions.
62 changes: 57 additions & 5 deletions src/Kinetic/Linq/ObservableView.OnItemAdded.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,69 @@
using System;
using System.Collections.Generic;
using Kinetic.Linq.StateMachines;

namespace Kinetic.Linq;

public static partial class ObservableView
{
public static ObserverBuilder<ListChange<TSource>> OnItemAdded<TSource>(this ObserverBuilder<ListChange<TSource>> source, Action<TSource> action) =>
source.Do(change =>
{
if (change.Action is ListChangeAction.Insert or ListChangeAction.Replace)
action(change.NewItem);
});
source.ContinueWith<OnItemAddedStateMachineFactory<TSource>, ListChange<TSource>>(new() { Action = action });

public static ObserverBuilder<ListChange<TSource>> OnItemAdded<TSource>(this ReadOnlyObservableList<TSource> source, Action<TSource> action) =>
source.Changed.ToBuilder().OnItemAdded(action);

private struct OnItemAddedStateMachineFactory<TSource> : IStateMachineFactory<ListChange<TSource>, ListChange<TSource>>
{
public required Action<TSource> Action { get; init; }

public void Create<TContinuation>(in TContinuation continuation, ObserverStateMachine<ListChange<TSource>> source)
where TContinuation : struct, IStateMachine<ListChange<TSource>>
{
source.ContinueWith<OnItemAddedStateMachine<TSource, TContinuation>>(new(continuation, Action));
}
}

private struct OnItemAddedStateMachine<TSource, TContinuation> : IStateMachine<ListChange<TSource>>
where TContinuation : struct, IStateMachine<ListChange<TSource>>
{
private TContinuation _continuation;
private readonly Action<TSource> _action;

public OnItemAddedStateMachine(in TContinuation continuation, Action<TSource> action)
{
_continuation = continuation;
_action = action;
}

public StateMachineBox Box =>
_continuation.Box;

public StateMachine<ListChange<TSource>> Reference =>
_continuation.Reference is IReadOnlyList<TSource> list
? new ListProxyStateMachine<TSource, OnItemAddedStateMachine<TSource, TContinuation>>(ref this, list)
: StateMachine<ListChange<TSource>>.Create(ref this);

public StateMachine? Continuation =>
_continuation.Reference;

public void Initialize(StateMachineBox box) =>
_continuation.Initialize(box);

public void Dispose() =>
_continuation.Dispose();

public void OnCompleted() =>
_continuation.OnCompleted();

public void OnError(Exception error) =>
_continuation.OnError(error);

public void OnNext(ListChange<TSource> value)
{
if (value.Action is ListChangeAction.Insert or ListChangeAction.Replace)
_action(value.NewItem);

_continuation.OnNext(value);
}
}
}
28 changes: 28 additions & 0 deletions src/Kinetic/Linq/StateMachines/ListProxyStateMachine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;

namespace Kinetic.Linq.StateMachines;

internal sealed class ListProxyStateMachine<T, TStateMachine> : StateMachine<ListChange<T>, TStateMachine>, IReadOnlyList<T>
where TStateMachine : struct, IStateMachine<ListChange<T>>
{
private readonly IReadOnlyList<T> _list;

public ListProxyStateMachine(ref TStateMachine stateMachine, IReadOnlyList<T> list) :
base(ref stateMachine) => _list = list;

public ListProxyStateMachine(StateMachineReference<ListChange<T>, TStateMachine> stateMachine, IReadOnlyList<T> list) :
base(stateMachine) => _list = list;

public T this[int index] =>
_list[index];

public int Count =>
_list.Count;

public IEnumerator<T> GetEnumerator() =>
_list.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() =>
_list.GetEnumerator();
}
1 change: 1 addition & 0 deletions test/Kinetic.Tests/ObservableViewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ public void OnItemRemoved()
.Subscribe();

list.Add(0);
list.RemoveAt(0);

Assert.True(handledBefore);
Assert.True(handledAfter);
Expand Down

0 comments on commit 28cca98

Please sign in to comment.