Skip to content

Commit

Permalink
Merge pull request #22 from Iacentis/feature/link-state-keys
Browse files Browse the repository at this point in the history
Propogate booleans across container chains
  • Loading branch information
carl-andersson-at-westermo authored Nov 15, 2024
2 parents 7039439 + 0e789ea commit 3a0eddd
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
6 changes: 5 additions & 1 deletion FactoryGenerator.Attributes/IContainer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace FactoryGenerator;
#nullable enable
Expand All @@ -14,7 +16,9 @@ public interface ILifetimeScope : IDisposable

bool IsRegistered(Type type);
bool IsRegistered<T>();
public ILifetimeScope BeginLifetimeScope();
bool GetBoolean(string key);
IEnumerable<(string Key, bool Value)> GetBooleans();
ILifetimeScope BeginLifetimeScope();
}

public interface IContainer : ILifetimeScope
Expand Down
42 changes: 39 additions & 3 deletions FactoryGenerator/FactoryGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ private IContainer GetTop()
public IContainer? Inheritor {{ get; set; }}
private object m_lock = new();
private Dictionary<Type,Func<object>> m_lookup;
private Dictionary<string,bool> m_booleans;
private readonly List<WeakReference<IDisposable>> resolvedInstances = new();
public T Resolve<T>()
Expand Down Expand Up @@ -245,6 +246,17 @@ public bool IsRegistered(Type type)
return m_lookup.ContainsKey(type) ? true : Base?.IsRegistered(type) == true;
}}
public bool IsRegistered<T>() => IsRegistered(typeof(T));
public bool GetBoolean(string key)
{{
return m_booleans.TryGetValue(key, out var value) ? value : false;
}}
public IEnumerable<(string Key, bool Value)> GetBooleans()
{{
foreach(var pair in m_booleans)
{{
yield return (pair.Key, pair.Value);
}}
}}
}}";

var booleans = dataInjections.Select(inj => inj.BooleanInjection).Where(b => b is not null)
Expand Down Expand Up @@ -424,7 +436,7 @@ public bool IsRegistered(Type type)
dictSize, interfaceInjectors.Keys,
localizedParameters, requested,
constructorParameters, true, ClassName, lifetimeParameters,
resolvingConstructorAssignments: resolvedConstructorAssignments);
resolvingConstructorAssignments: resolvedConstructorAssignments, booleans: justBooleans);
yield return Declarations(usingStatements, declarations, ClassName);
yield return ArrayDeclarations(usingStatements, arrayDeclarations, ClassName);
yield return $@"{usingStatements}
Expand Down Expand Up @@ -463,6 +475,7 @@ public ILifetimeScope BeginLifetimeScope()
private object m_lock = new();
private {ClassName} m_fallback;
private Dictionary<Type,Func<object>> m_lookup;
private Dictionary<string,bool> m_booleans;
private readonly List<WeakReference<IDisposable>> resolvedInstances = new();
public T Resolve<T>()
Expand Down Expand Up @@ -527,14 +540,26 @@ public bool IsRegistered(Type type)
return m_lookup.ContainsKey(type) ? true : Base?.IsRegistered(type) == true;
}}
public bool IsRegistered<T>() => IsRegistered(typeof(T));
public bool GetBoolean(string key)
{{
return m_booleans.TryGetValue(key, out var value) ? value : false;
}}
public IEnumerable<(string Key, bool Value)> GetBooleans()
{{
foreach(var pair in m_booleans)
{{
yield return (pair.Key, pair.Value);
}}
}}
}}
";
yield return Constructor(usingStatements, constructorFields,
lifetimeConstructor, constructorAssignments,
dictSize, interfaceInjectors.Keys,
localizedParameters, requested,
constructorParameters, false, LifetimeName,
resolvingConstructorAssignments: resolvedConstructorAssignments, addMergingConstructor: false);
resolvingConstructorAssignments: resolvedConstructorAssignments, addMergingConstructor: false, booleans: justBooleans);
yield return Declarations(usingStatements, scopedDeclarations, LifetimeName);
yield return ArrayDeclarations(usingStatements, arrayDeclarations, LifetimeName);
}
Expand Down Expand Up @@ -595,7 +620,7 @@ private static void CheckForCycles(ImmutableArray<Injection> dataInjections)
private static string Constructor(string usingStatements, string constructorFields, string constructor, string constructorAssignments, int dictSize,
IEnumerable<INamedTypeSymbol> interfaceInjectors, List<IParameterSymbol> localizedParameters, List<INamedTypeSymbol> requested,
List<IParameterSymbol> constructorParameters, bool addLifetimeScopeFunction, string className, string? lifetimeParameters = null,
string? fromConstructor = null, string? resolvingConstructorAssignments = null, bool addMergingConstructor = true)
string? fromConstructor = null, string? resolvingConstructorAssignments = null, bool addMergingConstructor = true, List<string> booleans = null!)
{
var lifetimeScopeFunction = addLifetimeScopeFunction
? $@"
Expand All @@ -613,12 +638,19 @@ public ILifetimeScope BeginLifetimeScope()
Base.Inheritor = this;
{resolvingConstructorAssignments}
{string.Join("\n", booleans.Select(b => b.Split(' ').Last()).Select(b => $"\t this.{b} = Base.GetBoolean(\"{b}\");"))}
m_lookup = new({dictSize}) {{
{MakeDictionary(interfaceInjectors)}
{MakeDictionary(localizedParameters)}
{MakeDictionary(requested)}
{MakeDictionary(constructorParameters)}
}};
m_booleans = new();
foreach(var (key, value) in Base.GetBooleans())
{{
m_booleans[key] = value;
}}
}}" : string.Empty;


Expand All @@ -638,6 +670,10 @@ public partial class {className}
{MakeDictionary(requested)}
{MakeDictionary(constructorParameters)}
}};
m_booleans = new({booleans.Count}) {{
{string.Join("\n", booleans.Select(b => b.Split(' ').Last()).Select(b => $"\t\t{{ \"{b}\", {b} }},"))}
}};
}}
{mergingConstructor}
{lifetimeScopeFunction}
Expand Down
29 changes: 29 additions & 0 deletions Tests/FactoryGenerator.Tests/InjectionDetectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,26 @@ public void HierarchicalContainersResolveUsesFallBackIfItCannotFindImplementatio
var newContainer = new DependencyInjectionContainer(new DummyContainer());
newContainer.Resolve<string>().ShouldBe(DummyContainer.DummyText);
}

[Fact]
public void ContainerPropgatesRelevantBooleansCreateItself()
{
var baseContainer = new DependencyInjectionContainer(true, false, new());
baseContainer.GetBoolean("A").ShouldBeFalse();
baseContainer.GetBoolean("TestBool").ShouldBeTrue();

var newContainer = new DependencyInjectionContainer(baseContainer);

newContainer.GetBoolean("A").ShouldBeFalse();
newContainer.GetBoolean("TestBool").ShouldBeTrue();
}
[Fact]
public void HierarchicalContainersPropgatesBooleansUnknownToIt()
{
var newContainer = new DependencyInjectionContainer(new DummyContainer());
newContainer.GetBoolean("B").ShouldBe(true);
newContainer.GetBoolean("C").ShouldBe(false);
}
private class DummyContainer : IContainer
{
public const string DummyText = "I am a bit of text";
Expand All @@ -257,6 +277,11 @@ public void Dispose()
{
}

public bool GetBoolean(string key)
{
return false;
}

public bool IsRegistered(System.Type type)
{
return true;
Expand Down Expand Up @@ -292,6 +317,10 @@ public bool TryResolve<T>(out T? resolved)
if (typeof(T) == typeof(string)) resolved = (T) (object) DummyText;
return resolved != null;
}
public IEnumerable<(string Key, bool Value)> GetBooleans()
{
return [("B", true), ("C", false)];
}

}
}

0 comments on commit 3a0eddd

Please sign in to comment.