Skip to content

Commit

Permalink
Merge pull request #513 from hadashiA/ku/fix-enqueue
Browse files Browse the repository at this point in the history
Support LifetimeScope.Enqueue* multiply
  • Loading branch information
hadashiA authored May 7, 2023
2 parents f245787 + fbcd9b5 commit 272c731
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 90 deletions.
23 changes: 0 additions & 23 deletions VContainer/Assets/VContainer/Runtime/Unity/ExtraInstaller.cs

This file was deleted.

11 changes: 0 additions & 11 deletions VContainer/Assets/VContainer/Runtime/Unity/ExtraInstaller.cs.meta

This file was deleted.

84 changes: 43 additions & 41 deletions VContainer/Assets/VContainer/Runtime/Unity/LifetimeScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,40 @@ public partial class LifetimeScope : MonoBehaviour, IDisposable
{
public readonly struct ParentOverrideScope : IDisposable
{
readonly LifetimeScope parent;

public ParentOverrideScope(LifetimeScope nextParent)
{
parent = nextParent;
overrideParent = nextParent;
lock (SyncRoot)
{
GlobalOverrideParents.Push(nextParent);
}
}

public void Dispose()
{
//don't remove in case it was overwritten
if(overrideParent == parent)
overrideParent = null;
lock (SyncRoot)
{
GlobalOverrideParents.Pop();
}
}
}

public readonly struct ExtraInstallationScope : IDisposable
{
public ExtraInstallationScope(IInstaller installer) => EnqueueExtra(installer);
void IDisposable.Dispose() => RemoveExtra();
public ExtraInstallationScope(IInstaller installer)
{
lock (SyncRoot)
{
GlobalExtraInstallers.Push(installer);
}
}

void IDisposable.Dispose()
{
lock (SyncRoot)
{
GlobalExtraInstallers.Pop();
}
}
}

[SerializeField]
Expand All @@ -42,8 +56,8 @@ public void Dispose()
[SerializeField]
protected List<GameObject> autoInjectGameObjects;

static LifetimeScope overrideParent;
static ExtraInstaller extraInstaller;
static readonly Stack<LifetimeScope> GlobalOverrideParents = new Stack<LifetimeScope>();
static readonly Stack<IInstaller> GlobalExtraInstallers = new Stack<IInstaller>();
static readonly object SyncRoot = new object();

static LifetimeScope Create(IInstaller installer = null)
Expand All @@ -53,7 +67,7 @@ static LifetimeScope Create(IInstaller installer = null)
var newScope = gameObject.AddComponent<LifetimeScope>();
if (installer != null)
{
newScope.extraInstallers.Add(installer);
newScope.localExtraInstallers.Add(installer);
}
gameObject.SetActive(true);
return newScope;
Expand Down Expand Up @@ -101,27 +115,11 @@ static LifetimeScope Find(Type type)
return (LifetimeScope)FindObjectOfType(type);
}

static void EnqueueExtra(IInstaller installer)
{
lock (SyncRoot)
{
if (extraInstaller != null)
extraInstaller.Add(installer);
else
extraInstaller = new ExtraInstaller { installer };
}
}

static void RemoveExtra()
{
lock (SyncRoot) extraInstaller = null;
}

public IObjectResolver Container { get; private set; }
public LifetimeScope Parent { get; private set; }
public bool IsRoot { get; set; }

readonly List<IInstaller> extraInstallers = new List<IInstaller>();
readonly List<IInstaller> localExtraInstallers = new List<IInstaller>();

protected virtual void Awake()
{
Expand Down Expand Up @@ -198,8 +196,6 @@ public void Build()
Container = builder.Build();
}

extraInstallers.Clear();

AutoInjectAll();
AwakeWaitingChildren(this);
}
Expand All @@ -220,7 +216,7 @@ public TScope CreateChild<TScope>(IInstaller installer = null)
var child = childGameObject.AddComponent<TScope>();
if (installer != null)
{
child.extraInstallers.Add(installer);
child.localExtraInstallers.Add(installer);
}
child.parentReference.Object = this;
childGameObject.SetActive(true);
Expand Down Expand Up @@ -248,7 +244,7 @@ public TScope CreateChildFromPrefab<TScope>(TScope prefab, IInstaller installer
var child = Instantiate(prefab, transform, false);
if (installer != null)
{
child.extraInstallers.Add(installer);
child.localExtraInstallers.Add(installer);
}
child.parentReference.Object = this;
if (wasActive)
Expand All @@ -267,17 +263,19 @@ void InstallTo(IContainerBuilder builder)
{
Configure(builder);

foreach (var installer in extraInstallers)
foreach (var installer in localExtraInstallers)
{
installer.Install(builder);
}
localExtraInstallers.Clear();

ExtraInstaller extraInstallerStatic;
lock (SyncRoot)
{
extraInstallerStatic = LifetimeScope.extraInstaller;
foreach (var installer in GlobalExtraInstallers)
{
installer.Install(builder);
}
}
extraInstallerStatic?.Install(builder);

builder.RegisterInstance<LifetimeScope>(this).AsSelf();
EntryPointsBuilder.EnsureDispatcherRegistered(builder);
Expand All @@ -303,9 +301,13 @@ LifetimeScope GetRuntimeParent()
$"{name} could not found parent reference of type : {parentReference.Type}");
}

var nextParent = overrideParent;
if (nextParent != null)
return nextParent;
lock (SyncRoot)
{
if (GlobalOverrideParents.Count > 0)
{
return GlobalOverrideParents.Peek();
}
}

// Find root from settings
if (VContainerSettings.Instance != null)
Expand Down
82 changes: 67 additions & 15 deletions VContainer/Assets/VContainer/Tests/Unity/LifetimeScopeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,6 @@ namespace VContainer.Tests.Unity
{
public class LifetimeScopeTest
{
[Test]
public void EnqueueParent()
{
var parent = new GameObject("LifetimeScope").AddComponent<LifetimeScope>();

using (LifetimeScope.EnqueueParent(parent))
{
var child = new GameObject("LifetimeScope Child 1").AddComponent<LifetimeScope>();
Assert.That(child.Parent, Is.EqualTo(parent));
}

var child2 = new GameObject("LifetimeScope Child 2").AddComponent<LifetimeScope>();
Assert.That(child2.Parent, Is.Null);
}

[UnityTest]
public IEnumerator Create()
{
Expand Down Expand Up @@ -159,6 +144,73 @@ public void CreateScopeWithSingleton()
Assert.That(childEntryPoint, Is.EqualTo(parentEntryPoint));
}

[Test]
public void EnqueueParent()
{
var parent = new GameObject("LifetimeScope").AddComponent<LifetimeScope>();

using (LifetimeScope.EnqueueParent(parent))
{
var child = new GameObject("LifetimeScope Child 1").AddComponent<LifetimeScope>();
Assert.That(child.Parent, Is.EqualTo(parent));
}

var child2 = new GameObject("LifetimeScope Child 2").AddComponent<LifetimeScope>();
Assert.That(child2.Parent, Is.Null);
}

[Test]
public void EnqueueParent_Multiply()
{
var parent1 = new GameObject("LifetimeScope Parent 1").AddComponent<LifetimeScope>();

using (LifetimeScope.EnqueueParent(parent1))
{
var parent2 = new GameObject("LifetimeScope Parent 2").AddComponent<LifetimeScope>();
Assert.That(parent2.Parent, Is.EqualTo(parent1));

using (LifetimeScope.EnqueueParent(parent2))
{
var child = new GameObject("LifetimeScope Child").AddComponent<LifetimeScope>();
Assert.That(child.Parent, Is.EqualTo(parent2));
}
}
}

[Test]
public void EnqueueExtraInstaller()
{
using (LifetimeScope.Enqueue(builder => builder.Register<NoDependencyServiceA>(Lifetime.Scoped)))
{
var scope1 = new GameObject("LifetimeScope 1").AddComponent<LifetimeScope>();
Assert.That(scope1.Container.Resolve<NoDependencyServiceA>(), Is.InstanceOf<NoDependencyServiceA>());

using (LifetimeScope.Enqueue(builder => builder.Register<NoDependencyServiceB>(Lifetime.Scoped)))
{
var scope2 = new GameObject("LifetimeScope 2").AddComponent<LifetimeScope>();
Assert.That(scope2.Container.Resolve<NoDependencyServiceA>(), Is.InstanceOf<NoDependencyServiceA>());
Assert.That(scope2.Container.Resolve<NoDependencyServiceB>(), Is.InstanceOf<NoDependencyServiceB>());
}

var scope3 = new GameObject("LifetimeScope 3").AddComponent<LifetimeScope>();
Assert.That(scope3.Container.Resolve<NoDependencyServiceA>(), Is.InstanceOf<NoDependencyServiceA>());
Assert.Throws<VContainerException>(() =>
{
scope3.Container.Resolve<NoDependencyServiceB>();
});
}

var scope4 = new GameObject("LifetimeScope 4").AddComponent<LifetimeScope>();
Assert.Throws<VContainerException>(() =>
{
scope4.Container.Resolve<NoDependencyServiceA>();
});
Assert.Throws<VContainerException>(() =>
{
scope4.Container.Resolve<NoDependencyServiceB>();
});
}

[Test]
[Ignore("Resources/ will be included in the build and we want to use a different approch")]
public void ParentTypeReference()
Expand Down
4 changes: 4 additions & 0 deletions VContainer/ProjectSettings/EditorSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ EditorSettings:
m_PrefabUIEnvironment: {fileID: 0}
m_SpritePackerMode: 0
m_SpritePackerPaddingPower: 1
m_Bc7TextureCompressor: 0
m_EtcTextureCompressorBehavior: 1
m_EtcTextureFastCompressor: 1
m_EtcTextureNormalCompressor: 2
Expand All @@ -31,10 +32,13 @@ EditorSettings:
m_SerializeInlineMappingsOnOneLine: 0
m_DisableCookiesInLightmapper: 1
m_AssetPipelineMode: 1
m_RefreshImportMode: 0
m_CacheServerMode: 0
m_CacheServerEndpoint:
m_CacheServerNamespacePrefix: default
m_CacheServerEnableDownload: 1
m_CacheServerEnableUpload: 1
m_CacheServerEnableAuth: 0
m_CacheServerEnableTls: 0
m_CacheServerValidationMode: 2
m_CacheServerDownloadBatchSize: 128

1 comment on commit 272c731

@vercel
Copy link

@vercel vercel bot commented on 272c731 May 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.