Skip to content

Commit

Permalink
Add ability to aggregate converted bindable values (#6)
Browse files Browse the repository at this point in the history
* Add ability to use bindable decorators in aggregation

* Run ci for feature branches

---------

Co-authored-by: Nikolai Selivanov <[email protected]>
  • Loading branch information
kekchpek and Nikolai Selivanov committed Aug 23, 2024
1 parent d36b6ef commit 85d3455
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- 'master'
- 'develop'
- 'release/*'
- 'feature/*'
- 'fix/*'

jobs:
build:
Expand Down
34 changes: 33 additions & 1 deletion src/AsyncReactAwait/Bindable/BindableDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace AsyncReactAwait.Bindable
{
internal class BindableDecorator<T, TSource> : IBindable<T>
internal class BindableDecorator<T, TSource> : IBindable<T>, IBindableRaw
{
private readonly IBindable<TSource> _bindable;
private readonly Func<TSource, T> _predicate;
Expand All @@ -12,6 +12,38 @@ internal class BindableDecorator<T, TSource> : IBindable<T>

public T Value => _predicate(_bindable.Value);

object? IBindableRaw.Value => Value;

public void Bind(Action<object?> handler, bool callImmediately = true)
{
void NewHandler(TSource x) => handler(_predicate(x));
_handlersMap.Add(handler, (Action<TSource>)NewHandler);
_bindable.Bind(NewHandler, callImmediately);
}

public void Bind(Action<object?, object?> handler)
{
void NewHandler(TSource prev, TSource next) => handler(_predicate(prev), _predicate(next));
_handlersMap.Add(handler, (Action<TSource, TSource>)NewHandler);
_bindable.Bind(NewHandler);
}

public void Unbind(Action<object?> handler)
{
if (_handlersMap.TryGetValue(handler, out var newHandler))
{
_bindable.Unbind((Action<TSource>)newHandler);
}
}

public void Unbind(Action<object?, object?> handler)
{
if (_handlersMap.TryGetValue(handler, out var newHandler))
{
_bindable.Unbind((Action<TSource, TSource>)newHandler);
}
}

public BindableDecorator(IBindable<TSource> bindable, Func<TSource, T> predicate)
{
_bindable = bindable;
Expand Down
125 changes: 124 additions & 1 deletion src/Autotests/UnitTests/Bindables/BindableAggregationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,130 @@ public void Aggregate1000Bindables_AggregationCalled()

// Assert
Assert.AreEqual(
floatBindables.Length + 1,
floatBindables.Length + 1, // additional one on creation
aggregationCallsCount);
}


[Test]
public void Aggregate1000Decorators_AggregationCalled()
{
// Arrange
var sourceFloatBindables = new Mutable<float>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i] = new Mutable<float>();
}

var stringBindables = new IBindable<string>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
stringBindables[i] = sourceFloatBindables[i].ConvertTo(x => x.ToString());
}
var aggregationCallsCount = 0;
var aggregatedBindable =
Bindable.Aggregate(stringBindables, _ => 0f);
aggregatedBindable.Bind(_ => aggregationCallsCount++);

// Act
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i].ForceSet(i);
}

// Assert
Assert.AreEqual(
stringBindables.Length + 1, // additional one on creation
aggregationCallsCount);
}

[Test]
public void Aggregate1000Bindables_ValToVal_AggregatedCorrectly()
{
// Arrange
var sourceFloatBindables = new Mutable<float>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i] = new Mutable<float>();
}

var floatBindables = new IBindable<float>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
floatBindables[i] = sourceFloatBindables[i].ConvertTo(x => x + 1f);
}
var aggregatedBindable =
Bindable.Aggregate(floatBindables, values => values.Sum());

// Act
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i].ForceSet(i);
}

// Assert
Assert.AreEqual(
floatBindables.Select(x => x.Value).Sum(),
aggregatedBindable.Value);
}

[Test]
public void Aggregate1000Bindables_ValToRef_AggregatedCorrectly()
{
// Arrange
var sourceFloatBindables = new Mutable<float>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i] = new Mutable<float>();
}

var stringBindables = new IBindable<string>[1000];
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
stringBindables[i] = sourceFloatBindables[i].ConvertTo(x => x.ToString());
}
var aggregatedBindable =
Bindable.Aggregate(stringBindables, values => string.Join("", values));

// Act
for (int i = 0; i < sourceFloatBindables.Length; i++)
{
sourceFloatBindables[i].ForceSet(i);
}

// Assert
Assert.AreEqual(
string.Join("", stringBindables.Select(x => x.Value)),
aggregatedBindable.Value);
}

[Test]
public void Aggregate1000Bindables_RefToVal_AggregatedCorrectly()
{
// Arrange
var sourceStringBindables = new Mutable<string>[1000];
for (int i = 0; i < sourceStringBindables.Length; i++)
{
sourceStringBindables[i] = new Mutable<string>("0");
}

var floatBindables = new IBindable<float>[1000];
for (int i = 0; i < sourceStringBindables.Length; i++)
{
floatBindables[i] = sourceStringBindables[i].ConvertTo(float.Parse);
}
var aggregatedBindable =
Bindable.Aggregate(floatBindables, values => values.Sum());

// Act
for (int i = 0; i < sourceStringBindables.Length; i++)
{
sourceStringBindables[i].ForceSet(i.ToString());
}

// Assert
Assert.AreEqual(
floatBindables.Select(x => x.Value).Sum(),
aggregatedBindable.Value);
}
}

0 comments on commit 85d3455

Please sign in to comment.