Skip to content

Commit

Permalink
#44 Disposable Instances Handling
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Mar 22, 2024
1 parent ce366b4 commit 8cc205d
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 96 deletions.
21 changes: 10 additions & 11 deletions readme/accumulators.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
Accumulators allow you to accumulate instances of certain types and lifetimes.

```c#
interface IAccumulating { }
interface IAccumulating;

class MyAccumulator: List<IAccumulating>;
class MyAccumulator : List<IAccumulating>;

interface IDependency;

class AbcDependency : IDependency, IAccumulating;

class XyzDependency : IDependency;

class Dependency : IDependency;
class XyzDependency : IDependency, IAccumulating;

interface IService: IAccumulating
{
Expand Down Expand Up @@ -48,11 +46,9 @@ DI.Setup(nameof(Composition))
.Root<(IService service, MyAccumulator accumulator)>("Root");

var composition = new Composition();
var root = composition.Root;
var service = root.service;
var accumulator = root.accumulator;
var (service, accumulator) = composition.Root;
accumulator.Count.ShouldBe(3);
accumulator[0].ShouldBeOfType<AbcDependency>();
accumulator[0].ShouldBeOfType<XyzDependency>();
accumulator[1].ShouldBeOfType<AbcDependency>();
accumulator[2].ShouldBeOfType<Service>();

Expand Down Expand Up @@ -130,14 +126,17 @@ partial class Composition
{
var accumulatorM03D22di41 = new Pure.DI.UsageTests.Advanced.AccumulatorScenario.MyAccumulator();
Pure.DI.UsageTests.Advanced.AccumulatorScenario.AbcDependency perBlockM03D22di4_AbcDependency = new Pure.DI.UsageTests.Advanced.AccumulatorScenario.AbcDependency();
accumulatorM03D22di41.Add(perBlockM03D22di4_AbcDependency);
if (ReferenceEquals(_rootM03D22di._singletonM03D22di38_XyzDependency, null))
{
lock (_lockM03D22di)
{
if (ReferenceEquals(_rootM03D22di._singletonM03D22di38_XyzDependency, null))
{
_singletonM03D22di38_XyzDependency = new Pure.DI.UsageTests.Advanced.AccumulatorScenario.XyzDependency();
Pure.DI.UsageTests.Advanced.AccumulatorScenario.XyzDependency _singletonM03D22di38_XyzDependencyTemp;
_singletonM03D22di38_XyzDependencyTemp = new Pure.DI.UsageTests.Advanced.AccumulatorScenario.XyzDependency();
accumulatorM03D22di41.Add(_singletonM03D22di38_XyzDependencyTemp);
global::System.Threading.Thread.MemoryBarrier();
_singletonM03D22di38_XyzDependency = _singletonM03D22di38_XyzDependencyTemp;
_rootM03D22di._singletonM03D22di38_XyzDependency = _singletonM03D22di38_XyzDependency;
}
}
Expand Down
2 changes: 0 additions & 2 deletions readme/tag-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ class AbcDependency : IDependency;

class XyzDependency : IDependency;

class Dependency : IDependency;

interface IService
{
IDependency Dependency1 { get; }
Expand Down
23 changes: 0 additions & 23 deletions src/Pure.DI.Core/Core/AccumulatorKey.cs

This file was deleted.

1 change: 1 addition & 0 deletions src/Pure.DI.Core/Core/Code/Accumulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ internal record Accumulator(
string Name,
bool IsDeclared,
ITypeSymbol Type,
Lifetime Lifetime,
ITypeSymbol AccumulatorType);
7 changes: 3 additions & 4 deletions src/Pure.DI.Core/Core/Code/BlockCodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,18 @@ variable.Node.Lifetime is Lifetime.Singleton or Lifetime.Scoped
{
parent = $"{Names.ParentFieldName}.";
}

var accumulators = new List<Accumulator>();

var uniqueAccumulators = ctx.Accumulators
.Where(accumulator => !accumulator.IsDeclared)
.GroupBy(i => i.AccumulatorType, SymbolEqualityComparer.Default)
.GroupBy(i => i.Name)
.Select(i => i.First());

foreach (var accumulator in uniqueAccumulators)
{
code.AppendLine($"var {accumulator.Name} = new {accumulator.AccumulatorType}();");
accumulators.Add(accumulator with { IsDeclared = true });
}

var accumulators = ctx.Accumulators.Select(accumulator => accumulator with { IsDeclared = true }).ToList();
if (accumulators.Count > 0)
{
ctx = ctx with { Accumulators = accumulators.ToImmutableArray() };
Expand Down
20 changes: 17 additions & 3 deletions src/Pure.DI.Core/Core/Code/BuildTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public IEnumerable<Line> OnCreated(BuildContext ctx, Variable variable)
var lines = ctx.Accumulators
.Where(i => FilterAccumulator(i, variable.Node.Lifetime))
.Where(i => baseTypes.Contains(i.Type))
.GroupBy(i => i.Name)
.Select(i => i.First())
.OrderBy(i => i.Name)
.Select(i => new Line(0, $"{i.Name}.Add({variable.VariableName});"))
.ToList();

Expand All @@ -76,9 +79,20 @@ public IEnumerable<Line> OnCreated(BuildContext ctx, Variable variable)
return lines;
}

private static bool FilterAccumulator(Accumulator accumulator, Lifetime lifetime) =>
accumulator.IsRoot
|| lifetime is not (Lifetime.Singleton or Lifetime.Scoped or Lifetime.PerResolve);
private static bool FilterAccumulator(Accumulator accumulator, Lifetime lifetime)
{
if (accumulator.Lifetime != lifetime)
{
return false;
}

if (accumulator.IsRoot)
{
return true;
}

return lifetime is not (Lifetime.Singleton or Lifetime.Scoped or Lifetime.PerResolve);
}

private static object? GetTag(BuildContext ctx, Variable variable)
{
Expand Down
19 changes: 16 additions & 3 deletions src/Pure.DI.Core/Core/Code/VariablesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public Block Build(

case Variable variable:
{
var isAccumulator = IsAccumulator(variable, out var construct);
var isAccumulator = IsAccumulator(variable, out var construct, out var mdAccumulators);
IReadOnlyCollection<Dependency> dependencies = Array.Empty<Dependency>();
if (!isAccumulator)
{
Expand Down Expand Up @@ -73,7 +73,18 @@ public Block Build(
accumulators ??= rootNode.Accumulators;
if (isAccumulator)
{
accumulators.Add(new Accumulator(isRoot, GetAccumulatorName(variable), false, construct.ElementType, construct.Type));
var name = GetAccumulatorName(variable);
foreach (var mdAccumulator in mdAccumulators)
{
accumulators.Add(
new Accumulator(
isRoot,
name,
false,
construct.ElementType,
mdAccumulator.Lifetime,
construct.Type));
}
}

foreach (var (isDepResolved, depNode, depInjection, _) in dependencies)
Expand Down Expand Up @@ -139,15 +150,17 @@ public Block Build(
return rootBlock;
}

private static bool IsAccumulator(Variable variable, out MdConstruct mdConstruct)
private static bool IsAccumulator(Variable variable, out MdConstruct mdConstruct, out IReadOnlyCollection<MdAccumulator> accumulators)
{
if(variable.Node.Construct?.Source is { Kind: MdConstructKind.Accumulator } construct)
{
mdConstruct = construct;
accumulators = construct.State as IReadOnlyCollection<MdAccumulator> ?? ImmutableArray<MdAccumulator>.Empty;
return true;
}

mdConstruct = default;
accumulators = ImmutableArray<MdAccumulator>.Empty;
return false;
}

Expand Down
39 changes: 20 additions & 19 deletions src/Pure.DI.Core/Core/DependencyGraphBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// ReSharper disable InvertIf
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
// ReSharper disable IdentifierTypo
namespace Pure.DI.Core;

internal sealed class DependencyGraphBuilder(
Expand Down Expand Up @@ -52,10 +53,16 @@ public IEnumerable<DependencyNode> TryBuild(
}
}

var accumulators = new Dictionary<AccumulatorKey, MdAccumulator>();
var accumulators = new Dictionary<ITypeSymbol, List<MdAccumulator>>(SymbolEqualityComparer.Default);
foreach (var accumulator in setup.Accumulators)
{
accumulators[new AccumulatorKey(accumulator.AccumulatorType, accumulator.Lifetime)] = accumulator;
if (!accumulators.TryGetValue(accumulator.AccumulatorType, out var accs))
{
accs = [];
accumulators.Add(accumulator.AccumulatorType, accs);
}

accs.Add(accumulator);
}

var processed = new HashSet<ProcessingNode>();
Expand All @@ -76,13 +83,13 @@ public IEnumerable<DependencyNode> TryBuild(
}
}

if (accumulators.TryGetValue(new AccumulatorKey(injection.Type, node.Node.Lifetime), out var accumulator))
if (accumulators.TryGetValue(injection.Type, out var accs))
{
var accumulatorBinding = CreateAccumulatorBinding(
setup,
targetNode,
ref maxId,
accumulator,
accs,
hasExplicitDefaultValue,
explicitDefaultValue);

Expand Down Expand Up @@ -143,16 +150,6 @@ public IEnumerable<DependencyNode> TryBuild(
case MdConstructKind.None:
break;

case MdConstructKind.Accumulator:
var accumulatorBinding = CreateAccumulatorBinding(
setup,
targetNode,
ref maxId,
accumulator,
hasExplicitDefaultValue,
explicitDefaultValue);
return CreateNodes(setup, accumulatorBinding);

default:
var lifetime = constructKind == MdConstructKind.Enumerable ? Lifetime.PerBlock : Lifetime.Transient;
var constructBinding = CreateConstructBinding(
Expand Down Expand Up @@ -439,10 +436,12 @@ private MdBinding CreateGenericBinding(
private static MdBinding CreateAccumulatorBinding(MdSetup setup,
DependencyNode targetNode,
ref int maxId,
MdAccumulator accumulator,
IReadOnlyCollection<MdAccumulator> accumulators,
bool hasExplicitDefaultValue,
object? explicitDefaultValue) =>
new(
object? explicitDefaultValue)
{
var accumulator = accumulators.First();
return new MdBinding(
++maxId,
targetNode.Binding.Source,
setup,
Expand All @@ -459,9 +458,11 @@ private static MdBinding CreateAccumulatorBinding(MdSetup setup,
accumulator.AccumulatorType,
accumulator.Type,
MdConstructKind.Accumulator,
ImmutableArray<MdContract>.Empty,
ImmutableArray<MdContract>.Empty,
hasExplicitDefaultValue,
explicitDefaultValue));
explicitDefaultValue,
accumulators));
}

private MdBinding CreateAutoBinding(
MdSetup setup,
Expand Down
3 changes: 2 additions & 1 deletion src/Pure.DI.Core/Core/Models/MdConstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ internal readonly record struct MdConstruct(
MdConstructKind Kind,
ImmutableArray<MdContract> Dependencies,
bool HasExplicitDefaultValue,
object? ExplicitDefaultValue)
object? ExplicitDefaultValue,
object? State = default)
{
public override string ToString() => $"To<{Kind}<{Type}>>()";
}
Loading

0 comments on commit 8cc205d

Please sign in to comment.