Skip to content

Commit

Permalink
Respect replace only when exists option during remap
Browse files Browse the repository at this point in the history
  • Loading branch information
z4kn4fein committed Oct 31, 2020
1 parent b9bb0fd commit 232a193
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 8 deletions.
3 changes: 2 additions & 1 deletion src/Registration/IRegistrationRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public interface IRegistrationRepository
/// </summary>
/// <param name="registration">The registration.</param>
/// <param name="serviceType">The service type of the registration. Used as the key for the registration mapping.</param>
void AddOrReMapRegistration(ServiceRegistration registration, Type serviceType);
/// <returns>True when the repository changed, otherwise false.</returns>
bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType);

/// <summary>
/// Returns a registration.
Expand Down
19 changes: 12 additions & 7 deletions src/Registration/RegistrationRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,18 @@ public bool AddOrUpdateRegistration(ServiceRegistration registration, Type servi
this.containerConfiguration.RegistrationBehavior);
}


public void AddOrReMapRegistration(ServiceRegistration registration, Type serviceType) =>
Swap.SwapValue(ref this.serviceRepository, (type, newRepo, t3, t4, repo) =>
repo.AddOrUpdate(type, newRepo, true), serviceType,
ImmutableBucket<object, ServiceRegistration>.Empty.Add(registration.RegistrationDiscriminator, registration),
Constants.DelegatePlaceholder,
Constants.DelegatePlaceholder);
public bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType) =>
registration.RegistrationContext.ReplaceExistingRegistrationOnlyIfExists
? Swap.SwapValue(ref this.serviceRepository, (type, newRepo, t3, t4, repo) =>
repo.UpdateIfExists(type, newRepo), serviceType,
ImmutableBucket<object, ServiceRegistration>.Empty.Add(registration.RegistrationDiscriminator, registration),
Constants.DelegatePlaceholder,
Constants.DelegatePlaceholder)
: Swap.SwapValue(ref this.serviceRepository, (type, newRepo, t3, t4, repo) =>
repo.AddOrUpdate(type, newRepo, true), serviceType,
ImmutableBucket<object, ServiceRegistration>.Empty.Add(registration.RegistrationDiscriminator, registration),
Constants.DelegatePlaceholder,
Constants.DelegatePlaceholder);

public bool ContainsRegistration(Type type, object name) =>
serviceRepository.ContainsRegistration(type, name);
Expand Down
47 changes: 47 additions & 0 deletions src/Utils/Data/Immutable/ImmutableTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ public ImmutableTree<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool forc
public ImmutableTree<TKey, TValue> UpdateIfExists(TKey key, Func<TValue, TValue> updateDelegate) =>
this.UpdateIfExists(RuntimeHelpers.GetHashCode(key), key, updateDelegate);

public ImmutableTree<TKey, TValue> UpdateIfExists(TKey key, TValue value) =>
this.UpdateIfExists(RuntimeHelpers.GetHashCode(key), key, value);

[MethodImpl(Constants.Inline)]
public TValue GetOrDefault(TKey key)
{
Expand Down Expand Up @@ -276,6 +279,31 @@ private ImmutableTree<TKey, TValue> UpdateIfExists(int hash, TKey key, Func<TVal
this.storedValue, this.leftNode, this.rightNode, this.collisions);
}

private ImmutableTree<TKey, TValue> UpdateIfExists(int hash, TKey key, TValue value)
{
if (this.IsEmpty)
return this;

if (hash == this.storedHash)
return this.ReplaceInCollisionsIfExist(hash, key, value);

if (hash < this.storedHash)
{
var left = this.leftNode.UpdateIfExists(hash, key, value);
if (ReferenceEquals(left, this.leftNode))
return this;
}
else
{
var right = this.rightNode.UpdateIfExists(hash, key, value);
if (ReferenceEquals(right, this.rightNode))
return this;
}

return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey,
this.storedValue, this.leftNode, this.rightNode, this.collisions);
}

private ImmutableTree<TKey, TValue> CheckCollision(int hash, TKey key, TValue value, Func<TValue, TValue, TValue> updateDelegate, bool forceUpdate)
{
if (ReferenceEquals(key, this.storedKey))
Expand Down Expand Up @@ -329,6 +357,25 @@ private ImmutableTree<TKey, TValue> ReplaceInCollisionsIfExist(int hash, TKey ke
return this;
}

private ImmutableTree<TKey, TValue> ReplaceInCollisionsIfExist(int hash, TKey key, TValue value)
{
if (ReferenceEquals(key, this.storedKey))
return new ImmutableTree<TKey, TValue>(hash, key, value,
this.leftNode, this.rightNode, this.collisions);

if (this.collisions != null)
{
var collisions = this.collisions.ReplaceIfExists(key, value, true);
if (ReferenceEquals(collisions, this.collisions))
return this;

return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey,
this.storedValue, this.leftNode, this.rightNode, collisions);
}

return this;
}

private static ImmutableTree<TKey, TValue> Balance(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)
{
var balance = left.height - right.height;
Expand Down
74 changes: 74 additions & 0 deletions test/ReMapTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ public void ReMapTests_Replace_Enumerable_Named()
Assert.IsType<Test12>(coll2[1]);
}

[Fact]
public void ReMapTests_ReMap_Replace_Only_If_Exists()
{
using var container = new StashboxContainer();
container.Register<ITest1, Test1>(context => context.WithName("teszt"));
container.Register<ITest1, Test12>(context => context.WithName("teszt2"));

var test1 = container.Resolve<ITest1>("teszt");
var test2 = container.Resolve<ITest1>("teszt2");

Assert.IsType<Test1>(test1);
Assert.IsType<Test12>(test2);

container.ReMap<ITest1, Test11>(context => context.WithName("teszt").ReplaceOnlyIfExists());

Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>("teszt2"));

var test11 = container.Resolve<ITest1>("teszt");
Assert.IsType<Test11>(test11);
}

[Fact]
public void ReMapTests_Replace_Only_If_Exists()
{
Expand Down Expand Up @@ -90,6 +111,23 @@ public void ReMapTests_Dont_Replace_If_Not_Exists()
Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>("teszt2"));
}

[Fact]
public void ReMapTests_ReMap_Replaces_Every_Registration()
{
using var container = new StashboxContainer();
container.Register<ITest1, Test1>(context => context.WithName("teszt"));

var test1 = container.Resolve<ITest1>("teszt");
Assert.IsType<Test1>(test1);

container.ReMap<ITest1, Test11>(context => context.WithName("teszt2").ReplaceOnlyIfExists());

Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>("teszt"));

var test11 = container.Resolve<ITest1>("teszt2");
Assert.IsType<Test11>(test11);
}

[Fact]
public void ReMapTests_Replace_Only_If_Exists_Instance()
{
Expand All @@ -116,6 +154,32 @@ public void ReMapTests_Replace_Only_If_Exists_Instance()
Assert.NotSame(t1, i2);
}

[Fact]
public void ReMapTests_ReMap_Replace_Only_If_Exists_Instance()
{
using var container = new StashboxContainer();
var t1 = new Test1();
container.Register<Test1>(c => c.WithInstance(t1));

var i1 = container.Resolve<Test1>();
var i2 = container.Resolve<Test1>();

Assert.Same(t1, i1);
Assert.Same(i1, i2);

var t2 = new Test1();
container.ReMap<Test1>(c => c.WithInstance(t2).ReplaceOnlyIfExists());

i1 = container.Resolve<Test1>();
i2 = container.Resolve<Test1>();

Assert.Same(t2, i1);
Assert.Same(i1, i2);

Assert.NotSame(t1, i1);
Assert.NotSame(t1, i2);
}

[Fact]
public void ReMapTests_Dont_Replace_If_Instance_Is_Not_Existing()
{
Expand All @@ -126,6 +190,16 @@ public void ReMapTests_Dont_Replace_If_Instance_Is_Not_Existing()
Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test1>());
}

[Fact]
public void ReMapTests_ReMap_Dont_Replace_If_Instance_Is_Not_Existing()
{
using var container = new StashboxContainer();
var t1 = new Test1();
container.ReMap<Test1>(c => c.WithInstance(t1).ReplaceOnlyIfExists());

Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test1>());
}

[Fact]
public void ReMapTests_Enumerable_Named()
{
Expand Down

0 comments on commit 232a193

Please sign in to comment.