Initial commit: Unity WordConnect project

This commit is contained in:
2025-08-01 19:12:05 +08:00
commit f14db75802
3503 changed files with 448337 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1eb05967f0cc40c59ebf679dcc359905
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,53 @@
//
// Copyright (c) 2025 left (https://github.com/left-/)
// Copyright (c) 2020 hadashiA
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#if UNITY_2021_3_OR_NEWER
using System;
#if UNITY_2023_1_OR_NEWER
using UnityEngine;
#else
using Awaitable = System.Threading.Tasks.Task;
#endif
namespace VContainer.Unity
{
internal static class AwaitableExtensions
{
public static async Awaitable Forget(this Awaitable awaitable,
EntryPointExceptionHandler exceptionHandler = null)
{
try
{
await awaitable;
}
catch (Exception ex)
{
if (exceptionHandler != null)
exceptionHandler.Publish(ex);
else
throw;
}
}
}
}
#endif

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9cbf97ce69c64b73a70d6514c63fba00
timeCreated: 1717651770

View File

@ -0,0 +1,16 @@
using System.Threading;
#if VCONTAINER_UNITASK_INTEGRATION
using Awaitable = Cysharp.Threading.Tasks.UniTask;
#elif UNITY_2023_1_OR_NEWER
using UnityEngine;
#else
using Awaitable = System.Threading.Tasks.Task;
#endif
namespace VContainer.Unity
{
public interface IAsyncStartable
{
Awaitable StartAsync(CancellationToken cancellation = default);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cf8c4b2a3efd465ba893956bd3e16207
timeCreated: 1612009971

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IFixedTickable
{
void FixedTick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e83f6a64504c4d1da11c1f6d046a0ecc
timeCreated: 1612009716

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IInitializable
{
void Initialize();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e3cb2445077468db349bf4dadae84be
timeCreated: 1612009493

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface ILateTickable
{
void LateTick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9b82ce93c2104d6c91ce9868c02dafc7
timeCreated: 1612009914

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IPostFixedTickable
{
void PostFixedTick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2bf16fe4c16a465b8a8f1d68a8685e11
timeCreated: 1612009787

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IPostInitializable
{
void PostInitialize();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ff6e6d963c0544649d8fedd94d25b8da
timeCreated: 1612009543

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IPostLateTickable
{
void PostLateTick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dcd967d55bd245408860956770845c3d
timeCreated: 1612009947

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IPostStartable
{
void PostStart();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 90378302abd9404eb23d078553c60031
timeCreated: 1612009663

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IPostTickable
{
void PostTick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 968f5691c67f4f64b8deed98e6a62cc2
timeCreated: 1612009893

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface IStartable
{
void Start();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 29296d5987f24dce8ee347cc39fdf1e0
timeCreated: 1612009633

View File

@ -0,0 +1,7 @@
namespace VContainer.Unity
{
public interface ITickable
{
void Tick();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e6460471a1864836afaf0617f182a721
timeCreated: 1612009837

View File

@ -0,0 +1,24 @@
using System;
namespace VContainer
{
public class PreserveAttribute : Attribute
{
}
#if UNITY_2018_4_OR_NEWER
[JetBrains.Annotations.MeansImplicitUse(
JetBrains.Annotations.ImplicitUseKindFlags.Access |
JetBrains.Annotations.ImplicitUseKindFlags.Assign |
JetBrains.Annotations.ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
#endif
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : PreserveAttribute
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class InjectIgnoreAttribute : Attribute
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9445a99bad3a60af9f20ca441c14bca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("VContainer.Tests")]
[assembly: InternalsVisibleTo("VContainer.StandaloneTests")]
[assembly: InternalsVisibleTo("VContainer.Editor")]
[assembly: InternalsVisibleTo("Unity.VContainer.CodeGen")]

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6158fbf642b64910aac0b04e9a4d62ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,310 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using VContainer.Diagnostics;
using VContainer.Internal;
namespace VContainer
{
public interface IObjectResolver : IDisposable
{
object ApplicationOrigin { get; }
DiagnosticsCollector Diagnostics { get; set; }
/// <summary>
/// Resolve from type
/// </summary>
/// <remarks>
/// This version of resolve looks for all of scopes
/// </remarks>
object Resolve(Type type);
/// <summary>
/// Try resolve from type
/// </summary>
/// <remarks>
/// This version of resolve looks for all of scopes
/// </remarks>
/// <returns>Successfully resolved</returns>
bool TryResolve(Type type, out object resolved);
/// <summary>
/// Resolve from meta with registration
/// </summary>
/// <remarks>
/// This version of resolve will look for instances from only the registration information already founds.
/// </remarks>
object Resolve(Registration registration);
IScopedObjectResolver CreateScope(Action<IContainerBuilder> installation = null);
void Inject(object instance);
bool TryGetRegistration(Type type, out Registration registration);
}
public interface IScopedObjectResolver : IObjectResolver
{
IObjectResolver Root { get; }
IScopedObjectResolver Parent { get; }
}
public enum Lifetime
{
Transient,
Singleton,
Scoped
}
public sealed class ScopedContainer : IScopedObjectResolver
{
public IObjectResolver Root { get; }
public IScopedObjectResolver Parent { get; }
public object ApplicationOrigin { get; }
public DiagnosticsCollector Diagnostics { get; set; }
readonly Registry registry;
readonly ConcurrentDictionary<Registration, Lazy<object>> sharedInstances = new ConcurrentDictionary<Registration, Lazy<object>>();
readonly CompositeDisposable disposables = new CompositeDisposable();
readonly Func<Registration, Lazy<object>> createInstance;
internal ScopedContainer(
Registry registry,
IObjectResolver root,
IScopedObjectResolver parent = null,
object applicationOrigin = null)
{
Root = root;
Parent = parent;
ApplicationOrigin = applicationOrigin;
this.registry = registry;
createInstance = registration =>
{
return new Lazy<object>(() => registration.SpawnInstance(this));
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object Resolve(Type type)
{
if (TryFindRegistration(type, out var registration))
{
return Resolve(registration);
}
throw new VContainerException(type, $"No such registration of type: {type}");
}
public bool TryResolve(Type type, out object resolved)
{
if (TryFindRegistration(type, out var registration))
{
resolved = Resolve(registration);
return true;
}
resolved = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object Resolve(Registration registration)
{
if (Diagnostics != null)
{
return Diagnostics.TraceResolve(registration, ResolveCore);
}
return ResolveCore(registration);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IScopedObjectResolver CreateScope(Action<IContainerBuilder> installation = null)
{
var containerBuilder = new ScopedContainerBuilder(Root, this)
{
ApplicationOrigin = ApplicationOrigin
};
installation?.Invoke(containerBuilder);
return containerBuilder.BuildScope();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Inject(object instance)
{
var injector = InjectorCache.GetOrBuild(instance.GetType());
injector.Inject(instance, this, null);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetRegistration(Type type, out Registration registration)
=> registry.TryGet(type, out registration);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
if (Diagnostics != null)
{
Diagnostics.Clear();
}
disposables.Dispose();
sharedInstances.Clear();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
object ResolveCore(Registration registration)
{
switch (registration.Lifetime)
{
case Lifetime.Singleton:
if (Parent is null)
return Root.Resolve(registration);
if (!registry.Exists(registration.ImplementationType))
return Parent.Resolve(registration);
return CreateTrackedInstance(registration);
case Lifetime.Scoped:
return CreateTrackedInstance(registration);
default:
return registration.SpawnInstance(this);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
object CreateTrackedInstance(Registration registration)
{
var lazy = sharedInstances.GetOrAdd(registration, createInstance);
var created = lazy.IsValueCreated;
var instance = lazy.Value;
if (!created && instance is IDisposable disposable && !(registration.Provider is ExistingInstanceProvider))
{
disposables.Add(disposable);
}
return instance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool TryFindRegistration(Type type, out Registration registration)
{
IScopedObjectResolver scope = this;
while (scope != null)
{
if (scope.TryGetRegistration(type, out registration))
{
return true;
}
scope = scope.Parent;
}
registration = default;
return false;
}
}
public sealed class Container : IObjectResolver
{
public object ApplicationOrigin { get; }
public DiagnosticsCollector Diagnostics { get; set; }
readonly Registry registry;
readonly IScopedObjectResolver rootScope;
readonly ConcurrentDictionary<Registration, Lazy<object>> sharedInstances = new ConcurrentDictionary<Registration, Lazy<object>>();
readonly CompositeDisposable disposables = new CompositeDisposable();
readonly Func<Registration, Lazy<object>> createInstance;
internal Container(Registry registry, object applicationOrigin = null)
{
this.registry = registry;
rootScope = new ScopedContainer(registry, this, applicationOrigin: applicationOrigin);
createInstance = registration =>
{
return new Lazy<object>(() => registration.SpawnInstance(this));
};
ApplicationOrigin = applicationOrigin;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object Resolve(Type type)
{
if (TryGetRegistration(type, out var registration))
{
return Resolve(registration);
}
throw new VContainerException(type, $"No such registration of type: {type}");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryResolve(Type type, out object resolved)
{
if (TryGetRegistration(type, out var registration))
{
resolved = Resolve(registration);
return true;
}
resolved = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object Resolve(Registration registration)
{
if (Diagnostics != null)
{
return Diagnostics.TraceResolve(registration, ResolveCore);
}
return ResolveCore(registration);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IScopedObjectResolver CreateScope(Action<IContainerBuilder> installation = null)
=> rootScope.CreateScope(installation);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Inject(object instance)
{
var injector = InjectorCache.GetOrBuild(instance.GetType());
injector.Inject(instance, this, null);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetRegistration(Type type, out Registration registration)
=> registry.TryGet(type, out registration);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
if (Diagnostics != null)
{
Diagnostics.Clear();
}
rootScope.Dispose();
disposables.Dispose();
sharedInstances.Clear();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
object ResolveCore(Registration registration)
{
switch (registration.Lifetime)
{
case Lifetime.Singleton:
var singleton = sharedInstances.GetOrAdd(registration, createInstance);
if (!singleton.IsValueCreated && singleton.Value is IDisposable disposable && !(registration.Provider is ExistingInstanceProvider))
{
disposables.Add(disposable);
}
return singleton.Value;
case Lifetime.Scoped:
return rootScope.Resolve(registration);
default:
return registration.SpawnInstance(this);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb5df50ba586a47e5a93a5045e69bca7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using VContainer.Diagnostics;
using VContainer.Internal;
#if VCONTAINER_PARALLEL_CONTAINER_BUILD
using System.Threading.Tasks;
#endif
namespace VContainer
{
public interface IContainerBuilder
{
object ApplicationOrigin { get; set; }
DiagnosticsCollector Diagnostics { get; set; }
int Count { get; }
RegistrationBuilder this[int index] { get; set; }
T Register<T>(T registrationBuilder) where T : RegistrationBuilder;
void RegisterBuildCallback(Action<IObjectResolver> container);
bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false);
}
public sealed class ScopedContainerBuilder : ContainerBuilder
{
readonly IObjectResolver root;
readonly IScopedObjectResolver parent;
internal ScopedContainerBuilder(IObjectResolver root, IScopedObjectResolver parent)
{
this.root = root;
this.parent = parent;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IScopedObjectResolver BuildScope()
{
var registry = BuildRegistry();
var container = new ScopedContainer(registry, root, parent, ApplicationOrigin);
container.Diagnostics = Diagnostics;
EmitCallbacks(container);
return container;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override IObjectResolver Build() => BuildScope();
public override bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false)
{
if (base.Exists(type, includeInterfaceTypes, findParentScopes))
{
return true;
}
if (findParentScopes)
{
var next = parent;
while (next != null)
{
if (next.TryGetRegistration(type, out var registration))
{
if (includeInterfaceTypes || registration.ImplementationType == type)
{
return true;
}
}
next = next.Parent;
}
}
return false;
}
}
public class ContainerBuilder : IContainerBuilder
{
public object ApplicationOrigin { get; set; }
public int Count => registrationBuilders.Count;
public RegistrationBuilder this[int index]
{
get => registrationBuilders[index];
set => registrationBuilders[index] = value;
}
public DiagnosticsCollector Diagnostics
{
get => diagnostics;
set
{
diagnostics = value;
diagnostics?.Clear();
}
}
readonly List<RegistrationBuilder> registrationBuilders = new List<RegistrationBuilder>();
Action<IObjectResolver> buildCallback;
DiagnosticsCollector diagnostics;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Register<T>(T registrationBuilder) where T : RegistrationBuilder
{
registrationBuilders.Add(registrationBuilder);
Diagnostics?.TraceRegister(new RegisterInfo(registrationBuilder));
return registrationBuilder;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RegisterBuildCallback(Action<IObjectResolver> callback)
{
buildCallback += callback;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false)
{
foreach (var registrationBuilder in registrationBuilders)
{
if (registrationBuilder.ImplementationType == type ||
includeInterfaceTypes && registrationBuilder.InterfaceTypes?.Contains(type) == true)
{
return true;
}
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual IObjectResolver Build()
{
var registry = BuildRegistry();
var container = new Container(registry, ApplicationOrigin);
container.Diagnostics = Diagnostics;
EmitCallbacks(container);
return container;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected Registry BuildRegistry()
{
var registrations = new Registration[registrationBuilders.Count + 1];
#if VCONTAINER_PARALLEL_CONTAINER_BUILD
Parallel.For(0, registrationBuilders.Count, i =>
{
var registrationBuilder = registrationBuilders[i];
var registration = registrationBuilder.Build();
Diagnostics?.TraceBuild(registrationBuilder, registration);
registrations[i] = registration;
});
#else
for (var i = 0; i < registrationBuilders.Count; i++)
{
var registrationBuilder = registrationBuilders[i];
var registration = registrationBuilder.Build();
Diagnostics?.TraceBuild(registrationBuilder, registration);
registrations[i] = registration;
}
#endif
registrations[registrations.Length - 1] = new Registration(
typeof(IObjectResolver),
Lifetime.Transient,
null,
ContainerInstanceProvider.Default);
var registry = Registry.Build(registrations);
TypeAnalyzer.CheckCircularDependency(registrations, registry);
return registry;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void EmitCallbacks(IObjectResolver container)
{
buildCallback?.Invoke(container);
Diagnostics?.NotifyContainerBuilt(container);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc776071549c945db9e79411839a1bb6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using VContainer.Internal;
namespace VContainer
{
public static class ContainerBuilderExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register(
this IContainerBuilder builder,
Type type,
Lifetime lifetime) =>
builder.Register(type.IsGenericType && type.IsGenericTypeDefinition
? new OpenGenericRegistrationBuilder(type, lifetime)
: new RegistrationBuilder(type, lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register(
this IContainerBuilder builder,
Type interfaceType,
Type implementationType,
Lifetime lifetime) =>
builder.Register(implementationType, lifetime).As(interfaceType);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register<T>(
this IContainerBuilder builder,
Lifetime lifetime) =>
builder.Register(typeof(T), lifetime);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register<TInterface, TImplement>(
this IContainerBuilder builder,
Lifetime lifetime)
where TImplement : TInterface =>
builder.Register<TImplement>(lifetime).As<TInterface>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register<TInterface1, TInterface2, TImplement>(
this IContainerBuilder builder,
Lifetime lifetime)
where TImplement : TInterface1, TInterface2 =>
builder.Register<TImplement>(lifetime).As(typeof(TInterface1), typeof(TInterface2));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register<TInterface1, TInterface2, TInterface3, TImplement>(
this IContainerBuilder builder,
Lifetime lifetime)
where TImplement : TInterface1, TInterface2, TInterface3
=> builder.Register<TImplement>(lifetime).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder Register<TInterface>(
this IContainerBuilder builder,
Func<IObjectResolver, TInterface> implementationConfiguration,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(container => implementationConfiguration(container), typeof(TInterface), lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterInstance<TInterface>(
this IContainerBuilder builder,
TInterface instance)
=> builder.Register(new InstanceRegistrationBuilder(instance)).As(typeof(TInterface));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterInstance<TInterface1, TInterface2>(
this IContainerBuilder builder,
TInterface1 instance)
=> builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterInstance<TInterface1, TInterface2, TInterface3>(
this IContainerBuilder builder,
TInterface1 instance)
=> builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<T>(
this IContainerBuilder builder,
Func<T> factory)
=> builder.RegisterInstance(factory);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, T>(
this IContainerBuilder builder,
Func<TParam1, T> factory)
=> builder.RegisterInstance(factory);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, T>(
this IContainerBuilder builder,
Func<TParam1, TParam2, T> factory)
=> builder.RegisterInstance(factory);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, TParam3, T>(
this IContainerBuilder builder,
Func<TParam1, TParam2, TParam3, T> factory)
=> builder.RegisterInstance(factory);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, TParam3, TParam4, T>(
this IContainerBuilder builder,
Func<TParam1, TParam2, TParam3, TParam4, T> factory)
=> builder.RegisterInstance(factory);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<T>(
this IContainerBuilder builder,
Func<IObjectResolver, Func<T>> factoryFactory,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(factoryFactory, typeof(Func<T>), lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, T>(
this IContainerBuilder builder,
Func<IObjectResolver, Func<TParam1, T>> factoryFactory,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(factoryFactory, typeof(Func<TParam1, T>), lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, T>(
this IContainerBuilder builder,
Func<IObjectResolver, Func<TParam1, TParam2, T>> factoryFactory,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(factoryFactory, typeof(Func<TParam1, TParam2, T>), lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, TParam3, T>(
this IContainerBuilder builder,
Func<IObjectResolver, Func<TParam1, TParam2, TParam3, T>> factoryFactory,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(factoryFactory, typeof(Func<TParam1, TParam2, TParam3, T>), lifetime));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RegistrationBuilder RegisterFactory<TParam1, TParam2, TParam3, TParam4, T>(
this IContainerBuilder builder,
Func<IObjectResolver, Func<TParam1, TParam2, TParam3, TParam4, T>> factoryFactory,
Lifetime lifetime)
=> builder.Register(new FuncRegistrationBuilder(factoryFactory, typeof(Func<TParam1, TParam2, TParam3, TParam4, T>), lifetime));
public static void RegisterDisposeCallback(this IContainerBuilder builder, Action<IObjectResolver> callback)
{
if (!builder.Exists(typeof(BuilderCallbackDisposable)))
{
builder.Register<BuilderCallbackDisposable>(Lifetime.Singleton);
}
builder.RegisterBuildCallback(container =>
{
var disposable = container.Resolve<BuilderCallbackDisposable>();
disposable.Disposing += callback;
});
}
[Obsolete("IObjectResolver is registered by default. This method does nothing.")]
public static void RegisterContainer(this IContainerBuilder builder)
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76ede31a370f45ffa838fe2da30f58a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f6de57dc253147c896d75dc9c2cfeab5
timeCreated: 1632059553

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using VContainer.Internal;
namespace VContainer.Diagnostics
{
public sealed class DiagnosticsCollector
{
public string ScopeName { get; }
readonly List<DiagnosticsInfo> diagnosticsInfos = new List<DiagnosticsInfo>();
readonly ThreadLocal<Stack<DiagnosticsInfo>> resolveCallStack
= new ThreadLocal<Stack<DiagnosticsInfo>>(() => new Stack<DiagnosticsInfo>());
public DiagnosticsCollector(string scopeName)
{
ScopeName = scopeName;
}
public IReadOnlyList<DiagnosticsInfo> GetDiagnosticsInfos()
{
return diagnosticsInfos;
}
public void Clear()
{
lock (diagnosticsInfos)
{
diagnosticsInfos.Clear();
}
}
public void TraceRegister(RegisterInfo registerInfo)
{
lock (diagnosticsInfos)
{
diagnosticsInfos.Add(new DiagnosticsInfo(ScopeName, registerInfo));
}
}
public void TraceBuild(RegistrationBuilder registrationBuilder, Registration registration)
{
lock (diagnosticsInfos)
{
foreach (var x in diagnosticsInfos)
{
if (x.RegisterInfo.RegistrationBuilder == registrationBuilder)
{
x.ResolveInfo = new ResolveInfo(registration);
return;
}
}
}
}
public object TraceResolve(Registration registration, Func<Registration, object> resolving)
{
var current = DiagnositcsContext.FindByRegistration(registration);
var owner = resolveCallStack.Value.Count > 0 ? resolveCallStack.Value.Peek() : null;
if (!(registration.Provider is CollectionInstanceProvider) && current != null && current != owner)
{
current.ResolveInfo.RefCount += 1;
current.ResolveInfo.MaxDepth = current.ResolveInfo.MaxDepth < 0
? resolveCallStack.Value.Count
: Math.Max(current.ResolveInfo.MaxDepth, resolveCallStack.Value.Count);
owner?.Dependencies.Add(current);
resolveCallStack.Value.Push(current);
var watch = Stopwatch.StartNew();
var instance = resolving(registration);
watch.Stop();
resolveCallStack.Value.Pop();
SetResolveTime(current, watch.ElapsedMilliseconds);
if (!current.ResolveInfo.Instances.Contains(instance))
{
current.ResolveInfo.Instances.Add(instance);
}
return instance;
}
return resolving(registration);
}
private static void SetResolveTime(DiagnosticsInfo current, long elapsedMilliseconds)
{
var resolves = current.ResolveInfo.RefCount;
var resolveTime = current.ResolveInfo.ResolveTime;
switch (current.ResolveInfo.Registration.Lifetime)
{
case Lifetime.Transient:
resolveTime = (resolveTime * (resolves - 1) + elapsedMilliseconds) / resolves;
break;
case Lifetime.Scoped:
case Lifetime.Singleton:
if (elapsedMilliseconds > resolveTime)
resolveTime = elapsedMilliseconds;
break;
default:
throw new ArgumentOutOfRangeException();
}
current.ResolveInfo.ResolveTime = resolveTime;
}
public void NotifyContainerBuilt(IObjectResolver container)
=> DiagnositcsContext.NotifyContainerBuilt(container);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 689fb82515a24c2887f2693a3a11010b
timeCreated: 1632059581

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace VContainer.Diagnostics
{
public static class DiagnositcsContext
{
static readonly Dictionary<string, DiagnosticsCollector> collectors
= new Dictionary<string, DiagnosticsCollector>();
public static event Action<IObjectResolver> OnContainerBuilt;
public static DiagnosticsCollector GetCollector(string name)
{
lock (collectors)
{
if (!collectors.TryGetValue(name, out var collector))
{
collector = new DiagnosticsCollector(name);
collectors.Add(name, collector);
}
return collector;
}
}
public static ILookup<string, DiagnosticsInfo> GetGroupedDiagnosticsInfos()
{
lock (collectors)
{
return collectors
.SelectMany(x => x.Value.GetDiagnosticsInfos())
.Where(x => x.ResolveInfo.MaxDepth <= 1)
.ToLookup(x => x.ScopeName);
}
}
public static IEnumerable<DiagnosticsInfo> GetDiagnosticsInfos()
{
lock (collectors)
{
return collectors.SelectMany(x => x.Value.GetDiagnosticsInfos());
}
}
public static void NotifyContainerBuilt(IObjectResolver container)
{
OnContainerBuilt?.Invoke(container);
}
internal static DiagnosticsInfo FindByRegistration(Registration registration)
{
return GetDiagnosticsInfos().FirstOrDefault(x => x.ResolveInfo.Registration == registration);
}
public static void RemoveCollector(string name)
{
lock (collectors)
{
collectors.Remove(name);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a87e62523cc246f2917f3ba78f7c6e99
timeCreated: 1633441412

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace VContainer.Diagnostics
{
public sealed class DiagnosticsInfo
{
public string ScopeName { get; }
public RegisterInfo RegisterInfo { get; }
public ResolveInfo ResolveInfo { get; set; }
public List<DiagnosticsInfo> Dependencies { get; } = new List<DiagnosticsInfo>();
public DiagnosticsInfo(string scopeName, RegisterInfo registerInfo)
{
ScopeName = scopeName;
RegisterInfo = registerInfo;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af9e78dd14ec4031998bbf9c34cc93ae
timeCreated: 1633441316

View File

@ -0,0 +1,119 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Threading;
namespace VContainer.Diagnostics
{
public sealed class RegisterInfo
{
static bool displayFileNames = true;
static int idSeed;
public int Id { get; }
public RegistrationBuilder RegistrationBuilder { get; }
public StackTrace StackTrace { get; }
StackFrame headLineStackFrame;
internal string formattedStackTrace = default; // cache field for internal use(Unity Editor, etc...)
public RegisterInfo(RegistrationBuilder registrationBuilder)
{
Id = Interlocked.Increment(ref idSeed);
RegistrationBuilder = registrationBuilder;
StackTrace = new StackTrace(true);
headLineStackFrame = GetHeadlineFrame(StackTrace);
}
public string GetFilename()
{
if (headLineStackFrame != null && displayFileNames && headLineStackFrame.GetILOffset() != -1)
{
try
{
return headLineStackFrame.GetFileName();
}
catch (NotSupportedException)
{
displayFileNames = false;
}
catch (SecurityException)
{
displayFileNames = false;
}
}
return null;
}
public int GetFileLineNumber()
{
if (headLineStackFrame != null && displayFileNames && headLineStackFrame.GetILOffset() != -1)
{
try
{
return headLineStackFrame.GetFileLineNumber();
}
catch (NotSupportedException)
{
displayFileNames = false;
}
catch (SecurityException)
{
displayFileNames = false;
}
}
return -1;
}
public string GetScriptAssetPath()
{
var filename = GetFilename();
if (filename == null)
return "";
var prefixIndex = filename.LastIndexOf("Assets/");
return prefixIndex > 0 ? filename.Substring(prefixIndex) : "";
}
public string GetHeadline()
{
if (headLineStackFrame == null)
return "";
var method = headLineStackFrame.GetMethod();
var filename = GetFilename();
if (filename != null)
{
var lineNumber = GetFileLineNumber();
return $"{method.DeclaringType?.FullName}.{method.Name} (at {Path.GetFileName(filename)}:{lineNumber})";
}
var ilOffset = headLineStackFrame.GetILOffset();
if (ilOffset != -1)
{
return $"{method.DeclaringType?.FullName}.{method.Name}(offset: {ilOffset})";
}
return $"{method.DeclaringType?.FullName}.{method.Name}";
}
StackFrame GetHeadlineFrame(StackTrace stackTrace)
{
for (var i = 0; i < stackTrace.FrameCount; i++)
{
var sf = stackTrace.GetFrame(i);
if (sf == null) continue;
var m = sf.GetMethod();
if (m == null) continue;
if (m.DeclaringType == null) continue;
if (m.DeclaringType.Namespace == null || !m.DeclaringType.Namespace.StartsWith("VContainer"))
{
return sf;
}
}
return stackTrace.FrameCount > 0 ? stackTrace.GetFrame(0) : null;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4359f1f8bb3b4540835998a60eb93049
timeCreated: 1633272541

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace VContainer.Diagnostics
{
public sealed class ResolveInfo
{
public Registration Registration { get; }
public List<object> Instances { get; } = new List<object>();
public int MaxDepth { get; set; } = -1;
public int RefCount { get; set; }
public long ResolveTime { get; set; }
public ResolveInfo(Registration registration)
{
Registration = registration;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f53a6c226cf4a04ae556c00dc477f4b
timeCreated: 1633102576

View File

@ -0,0 +1,10 @@
using System;
namespace VContainer
{
public interface IInjectParameter
{
bool Match(Type parameterType, string parameterName);
object GetValue(IObjectResolver resolver);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 890f74c4a6fb42db8340eb8f1a505330
timeCreated: 1595654174

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace VContainer
{
public interface IInjector
{
void Inject(object instance, IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters);
object CreateInstance(IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ddd3eeb838dd449228703d913f0e9108
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
namespace VContainer
{
public interface IInstanceProvider
{
object SpawnInstance(IObjectResolver resolver);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0474f1261ed04e1e91e41b96a52297e9
timeCreated: 1637894248

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer
{
public static class IObjectResolverExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T Resolve<T>(this IObjectResolver resolver) => (T)resolver.Resolve(typeof(T));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryResolve<T>(this IObjectResolver resolver, out T resolved)
{
if (resolver.TryResolve(typeof(T), out var r))
{
resolved = (T)r;
return true;
}
resolved = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T ResolveOrDefault<T>(this IObjectResolver resolver, T defaultValue = default)
{
if (resolver.TryResolve(typeof(T), out var value))
{
return (T)value;
}
return defaultValue;
}
// Using from CodeGen
[Preserve]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static object ResolveNonGeneric(this IObjectResolver resolve, Type type) => resolve.Resolve(type);
public static object ResolveOrParameter(
this IObjectResolver resolver,
Type parameterType,
string parameterName,
IReadOnlyList<IInjectParameter> parameters)
{
if (parameters != null)
{
// ReSharper disable once ForCanBeConvertedToForeach
for (var i = 0; i < parameters.Count; i++)
{
var parameter = parameters[i];
if (parameter.Match(parameterType, parameterName))
{
return parameter.GetValue(resolver);
}
}
}
return resolver.Resolve(parameterType);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b7dc27e3935451ba5ca0f67efba7e6f
timeCreated: 1595619880

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 853495921eac94a55bba66a67ce6feb7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
using System;
namespace VContainer.Internal
{
class BuilderCallbackDisposable : IDisposable
{
public event Action<IObjectResolver> Disposing;
readonly IObjectResolver container;
public BuilderCallbackDisposable(IObjectResolver container)
{
this.container = container;
}
public void Dispose()
{
if (Disposing != null) Disposing.Invoke(container);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 04c6203c157b4898b815f392b47d02ba
timeCreated: 1703318719

View File

@ -0,0 +1,76 @@
using System;
namespace VContainer.Internal
{
sealed class CappedArrayPool<T>
{
internal const int InitialBucketSize = 4;
public static readonly CappedArrayPool<T> Shared8Limit = new CappedArrayPool<T>(8);
readonly T[][][] buckets;
readonly object syncRoot = new object();
readonly int[] tails;
internal CappedArrayPool(int maxLength)
{
buckets = new T[maxLength][][];
tails = new int[maxLength];
for (var i = 0; i < maxLength; i++)
{
var arrayLength = i + 1;
buckets[i] = new T[InitialBucketSize][];
for (var j = 0; j < InitialBucketSize; j++)
{
buckets[i][j] = new T[arrayLength];
}
tails[i] = 0;
}
}
public T[] Rent(int length)
{
if (length <= 0)
return Array.Empty<T>();
if (length > buckets.Length)
return new T[length]; // Not supported
var i = length - 1;
lock (syncRoot)
{
var bucket = buckets[i];
var tail = tails[i];
if (tail >= bucket.Length)
{
Array.Resize(ref bucket, bucket.Length * 2);
buckets[i] = bucket;
}
if (bucket[tail] == null)
{
bucket[tail] = new T[length];
}
var result = bucket[tail];
tails[i] += 1;
return result;
}
}
public void Return(T[] array)
{
if (array.Length <= 0 || array.Length > buckets.Length)
return;
var i = array.Length - 1;
lock (syncRoot)
{
Array.Clear(array, 0, array.Length);
if (tails[i] > 0)
tails[i] -= 1;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 798af9f34fc7941f6a89a12f634db404
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class CompositeDisposable : IDisposable
{
readonly Stack<IDisposable> disposables = new Stack<IDisposable>();
public void Dispose()
{
IDisposable disposable;
do
{
lock (disposables)
{
disposable = disposables.Count > 0
? disposables.Pop()
: null;
}
disposable?.Dispose();
} while (disposable != null);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(IDisposable disposable)
{
lock (disposables)
{
disposables.Push(disposable);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4308506e1771d4ec69df54d5a890d67b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
namespace VContainer.Internal
{
public sealed class ContainerLocal<T>
{
public readonly T Value;
[Inject]
public ContainerLocal(T value)
{
Value = value;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7868bf6fa13e45b39973d776a3fad130
timeCreated: 1637458343

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
// http://neue.cc/2017/07/11_555.html
sealed class FixedTypeKeyHashtable<TValue>
{
readonly struct HashEntry
{
public readonly Type Type;
public readonly TValue Value;
public HashEntry(Type key, TValue value)
{
Type = key;
Value = value;
}
}
readonly HashEntry[][] table;
readonly int indexFor;
public FixedTypeKeyHashtable(KeyValuePair<Type, TValue>[] values, float loadFactor = 0.75f)
{
var initialCapacity = (int)((float)values.Length / loadFactor);
// make power of 2(and use mask)
// see: Hashing https://en.wikipedia.org/wiki/Hash_table
var capacity = 1;
while (capacity < initialCapacity)
{
capacity <<= 1;
}
table = new HashEntry[(int)capacity][];
indexFor = table.Length - 1;
foreach (var item in values)
{
var hash = RuntimeHelpers.GetHashCode(item.Key);
var array = table[hash & indexFor];
if (array == null)
{
array = new HashEntry[1];
array[0] = new HashEntry(item.Key, item.Value);
}
else
{
var newArray = new HashEntry[array.Length + 1];
Array.Copy(array, newArray, array.Length);
array = newArray;
array[array.Length - 1] = new HashEntry(item.Key, item.Value);
}
table[hash & indexFor] = array;
}
}
public TValue Get(Type type)
{
var hashCode = RuntimeHelpers.GetHashCode(type);
var buckets = table[hashCode & indexFor];
if (buckets == null) goto ERROR;
if (buckets[0].Type == type)
{
return buckets[0].Value;
}
for (int i = 1; i < buckets.Length; i++)
{
if (buckets[i].Type == type)
{
return buckets[i].Value;
}
}
ERROR:
throw new KeyNotFoundException("Type was not found, Type: " + type.FullName);
}
public bool TryGet(Type type, out TValue value)
{
var hashCode = RuntimeHelpers.GetHashCode(type);
var buckets = table[hashCode & indexFor];
if (buckets == null) goto END;
if (buckets[0].Type == type)
{
value = buckets[0].Value;
return true;
}
for (int i = 1; i < buckets.Length; i++)
{
if (buckets[i].Type == type)
{
value = buckets[i].Value;
return true;
}
}
END:
value = default;
return false;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d640b33996034830abfbef71b7f8e440
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
#if UNITY_2021_3_OR_NEWER
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
#endif
namespace VContainer.Internal
{
class FreeList<T> where T : class
{
public bool IsDisposed => lastIndex == -2;
public int Length => lastIndex + 1;
readonly object gate = new object();
T[] values;
int lastIndex = -1;
public FreeList(int initialCapacity)
{
values = new T[initialCapacity];
}
#if NETSTANDARD2_1
public ReadOnlySpan<T> AsSpan()
{
if (lastIndex < 0)
{
return ReadOnlySpan<T>.Empty;
}
return values.AsSpan(0, lastIndex + 1);
}
#endif
public T this[int index] => values[index];
public void Add(T item)
{
lock (gate)
{
CheckDispose();
// try find blank
var index = FindNullIndex(values);
if (index == -1)
{
// full, 1, 4, 6,...resize(x1.5)
var len = values.Length;
var newValues = new T[len + len / 2];
Array.Copy(values, newValues, len);
values = newValues;
index = len;
}
values[index] = item;
if (lastIndex < index)
{
lastIndex = index;
}
}
}
public void RemoveAt(int index)
{
lock (gate)
{
if (index < values.Length)
{
ref var v = ref values[index];
if (v == null) throw new KeyNotFoundException($"key index {index} is not found.");
v = null;
if (index == lastIndex)
{
lastIndex = FindLastNonNullIndex(values, index);
}
}
}
}
public bool Remove(T value)
{
lock (gate)
{
if (lastIndex < 0) return false;
var index = -1;
for (var i = 0; i < values.Length; i++)
{
if (values[i] == value)
{
index = i;
break;
}
}
if (index != -1)
{
RemoveAt(index);
return true;
}
}
return false;
}
public void Clear()
{
lock (gate)
{
if (lastIndex > 0)
{
Array.Clear(values, 0, lastIndex + 1);
lastIndex = -1;
}
}
}
public void Dispose()
{
lock (gate)
{
lastIndex = -2; // -2 is disposed.
}
}
void CheckDispose()
{
if (IsDisposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
}
#if UNITY_2021_3_OR_NEWER
static unsafe int FindNullIndex(T[] target)
{
ref var head = ref UnsafeUtility.As<T, IntPtr>(ref MemoryMarshal.GetReference(target.AsSpan()));
fixed (void* p = &head)
{
var span = new ReadOnlySpan<IntPtr>(p, target.Length);
#if NETSTANDARD2_1
return span.IndexOf(IntPtr.Zero);
#else
for (int i = 0; i < span.Length; i++)
{
if (span[i] == IntPtr.Zero) return i;
}
return -1;
#endif
}
}
static unsafe int FindLastNonNullIndex(T[] target, int lastIndex)
{
ref var head = ref UnsafeUtility.As<T, IntPtr>(ref MemoryMarshal.GetReference(target.AsSpan()));
fixed (void* p = &head)
{
var span = new ReadOnlySpan<IntPtr>(p, lastIndex); // without lastIndexed value.
for (var i = span.Length - 1; i >= 0; i--)
{
if (span[i] != IntPtr.Zero) return i;
}
return -1;
}
}
#else
static int FindNullIndex(T[] target)
{
for (var i = 0; i < target.Length; i++)
{
if (target[i] == null) return i;
}
return -1;
}
static int FindLastNonNullIndex(T[] target, int lastIndex)
{
for (var i = lastIndex; i >= 0; i--)
{
if (target[i] != null) return i;
}
return -1;
}
#endif
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ab65b7c977d342df8c7b3d914e896b30
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
using System;
namespace VContainer.Internal
{
sealed class FuncRegistrationBuilder : RegistrationBuilder
{
readonly Func<IObjectResolver, object> implementationProvider;
public FuncRegistrationBuilder(
Func<IObjectResolver, object> implementationProvider,
Type implementationType,
Lifetime lifetime) : base(implementationType, lifetime)
{
this.implementationProvider = implementationProvider;
}
public override Registration Build()
{
var spawner = new FuncInstanceProvider(implementationProvider);
return new Registration(ImplementationType, Lifetime, InterfaceTypes, spawner);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 959eabb8a5cb4f198c7e96512ea177b8
timeCreated: 1619866780

View File

@ -0,0 +1,80 @@
using System;
namespace VContainer.Internal
{
sealed class TypedParameter : IInjectParameter
{
public readonly Type Type;
public readonly object Value;
public TypedParameter(Type type, object value)
{
Type = type;
Value = value;
}
public bool Match(Type parameterType, string _) => parameterType == Type;
public object GetValue(IObjectResolver _)
{
return Value;
}
}
sealed class FuncTypedParameter : IInjectParameter
{
public readonly Type Type;
public readonly Func<IObjectResolver, object> Func;
public FuncTypedParameter(Type type, Func<IObjectResolver, object> func)
{
Type = type;
Func = func;
}
public bool Match(Type parameterType, string _) => parameterType == Type;
public object GetValue(IObjectResolver resolver)
{
return Func(resolver);
}
}
sealed class NamedParameter : IInjectParameter
{
public readonly string Name;
public readonly object Value;
public NamedParameter(string name, object value)
{
Name = name;
Value = value;
}
public bool Match(Type _, string parameterName) => parameterName == Name;
public object GetValue(IObjectResolver _)
{
return Value;
}
}
sealed class FuncNamedParameter : IInjectParameter
{
public readonly string Name;
public readonly Func<IObjectResolver, object> Func;
public FuncNamedParameter(string name, Func<IObjectResolver, object> func)
{
Name = name;
Func = func;
}
public bool Match(Type _, string parameterName) => parameterName == Name;
public object GetValue(IObjectResolver resolver)
{
return Func(resolver);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dbed645399934dceb7271819378c67fe
timeCreated: 1593003624

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Concurrent;
using System.Reflection;
namespace VContainer.Internal
{
public static class InjectorCache
{
static readonly ConcurrentDictionary<Type, IInjector> Injectors = new ConcurrentDictionary<Type, IInjector>();
public static IInjector GetOrBuild(Type type)
{
return Injectors.GetOrAdd(type, key =>
{
// SourceGenerator
var generatedType = key.Assembly.GetType($"{key.FullName}GeneratedInjector", false);
if (generatedType != null)
{
return (IInjector)Activator.CreateInstance(generatedType);
}
// IL weaving (Deprecated)
var getter = key.GetMethod("__GetGeneratedInjector", BindingFlags.Static | BindingFlags.Public);
if (getter != null)
{
return (IInjector)getter.Invoke(null, null);
}
return ReflectionInjector.Build(key);
});
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9868d07fc52841ac9aaef692536402e6
timeCreated: 1595675733

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 975a095af910460bb016e0cc5cf9eb07
timeCreated: 1637894696

View File

@ -0,0 +1,131 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
struct RegistrationElement
{
public Registration Registration;
public IObjectResolver RegisteredContainer;
public RegistrationElement(Registration registration, IObjectResolver registeredContainer)
{
Registration = registration;
RegisteredContainer = registeredContainer;
}
}
sealed class CollectionInstanceProvider : IInstanceProvider, IEnumerable<Registration>
{
public static bool Match(Type openGenericType) => openGenericType == typeof(IEnumerable<>) ||
openGenericType == typeof(IReadOnlyList<>);
public List<Registration>.Enumerator GetEnumerator() => registrations.GetEnumerator();
IEnumerator<Registration> IEnumerable<Registration>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public Type ImplementationType { get; }
public IReadOnlyList<Type> InterfaceTypes => interfaceTypes;
public Lifetime Lifetime => Lifetime.Transient; // Collection reference is transient. So its members can have each lifetimes.
public Type ElementType { get; }
readonly List<Type> interfaceTypes;
readonly List<Registration> registrations = new List<Registration>();
public CollectionInstanceProvider(Type elementType)
{
ElementType = elementType;
ImplementationType = elementType.MakeArrayType();
interfaceTypes = new List<Type>
{
RuntimeTypeCache.EnumerableTypeOf(elementType),
RuntimeTypeCache.ReadOnlyListTypeOf(elementType),
};
}
public override string ToString()
{
var contractTypes = InterfaceTypes != null ? string.Join(", ", InterfaceTypes) : "";
return $"CollectionRegistration {ImplementationType} ContractTypes=[{contractTypes}] {Lifetime}";
}
public void Add(Registration registration)
{
foreach (var x in registrations)
{
if (x.Lifetime == Lifetime.Singleton && x.ImplementationType == registration.ImplementationType)
{
throw new VContainerException(registration.ImplementationType, $"Conflict implementation type : {registration}");
}
}
registrations.Add(registration);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object SpawnInstance(IObjectResolver resolver)
{
if (resolver is IScopedObjectResolver scope)
{
using (ListPool<RegistrationElement>.Get(out var entirelyRegistrations))
{
CollectFromParentScopes(scope, entirelyRegistrations);
return SpawnInstance(resolver, entirelyRegistrations);
}
}
var array = Array.CreateInstance(ElementType, registrations.Count);
for (var i = 0; i < registrations.Count; i++)
{
array.SetValue(resolver.Resolve(registrations[i]), i);
}
return array;
}
internal object SpawnInstance(IObjectResolver currentScope, IReadOnlyList<RegistrationElement> entirelyRegistrations)
{
var array = Array.CreateInstance(ElementType, entirelyRegistrations.Count);
for (var i = 0; i < entirelyRegistrations.Count; i++)
{
var x = entirelyRegistrations[i];
var resolver = x.Registration.Lifetime == Lifetime.Singleton
? x.RegisteredContainer
: currentScope;
array.SetValue(resolver.Resolve(x.Registration), i);
}
return array;
}
internal void CollectFromParentScopes(
IScopedObjectResolver scope,
List<RegistrationElement> registrationsBuffer,
bool localScopeOnly = false)
{
foreach (var registration in registrations)
{
registrationsBuffer.Add(new RegistrationElement(registration, scope));
}
var finderType = InterfaceTypes[0];
scope = scope.Parent;
while (scope != null)
{
if (scope.TryGetRegistration(finderType, out var registration) &&
registration.Provider is CollectionInstanceProvider parentCollection)
{
foreach (var x in parentCollection.registrations)
{
if (!localScopeOnly || x.Lifetime != Lifetime.Singleton)
{
registrationsBuffer.Add(new RegistrationElement(x, scope));
}
}
}
scope = scope.Parent;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 24bcedcfe70849f4b609a3c695bee2da
timeCreated: 1637460174

View File

@ -0,0 +1,12 @@
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class ContainerInstanceProvider : IInstanceProvider
{
public static readonly ContainerInstanceProvider Default = new ContainerInstanceProvider();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object SpawnInstance(IObjectResolver resolver) => resolver;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e5fee000f6274ce19a7ee65eb42604e7
timeCreated: 1637894705

View File

@ -0,0 +1,45 @@
using System;
namespace VContainer.Internal
{
sealed class ContainerLocalInstanceProvider : IInstanceProvider
{
readonly Type wrappedType;
readonly Registration valueRegistration;
public ContainerLocalInstanceProvider(Type wrappedType, Registration valueRegistration)
{
this.wrappedType = wrappedType;
this.valueRegistration = valueRegistration;
}
public object SpawnInstance(IObjectResolver resolver)
{
object value;
if (resolver is ScopedContainer scope &&
valueRegistration.Provider is CollectionInstanceProvider collectionProvider)
{
using (ListPool<RegistrationElement>.Get(out var entirelyRegistrations))
{
collectionProvider.CollectFromParentScopes(scope, entirelyRegistrations, localScopeOnly: true);
value = collectionProvider.SpawnInstance(scope, entirelyRegistrations);
}
}
else
{
value = resolver.Resolve(valueRegistration);
}
var parameterValues = CappedArrayPool<object>.Shared8Limit.Rent(1);
try
{
parameterValues[0] = value;
return Activator.CreateInstance(wrappedType, parameterValues);
}
finally
{
CappedArrayPool<object>.Shared8Limit.Return(parameterValues);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67ec193044734d97aa59126a9cb83398
timeCreated: 1637461669

View File

@ -0,0 +1,17 @@
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class ExistingInstanceProvider : IInstanceProvider
{
readonly object implementationInstance;
public ExistingInstanceProvider(object implementationInstance)
{
this.implementationInstance = implementationInstance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object SpawnInstance(IObjectResolver resolver) => implementationInstance;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4fcef74c11fc4018bbc88bc395ef8657
timeCreated: 1619863673

View File

@ -0,0 +1,18 @@
using System;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class FuncInstanceProvider : IInstanceProvider
{
readonly Func<IObjectResolver, object> implementationProvider;
public FuncInstanceProvider(Func<IObjectResolver, object> implementationProvider)
{
this.implementationProvider = implementationProvider;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object SpawnInstance(IObjectResolver resolver) => implementationProvider(resolver);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a4fb0cd9294e424bb69b28711f95ccc0
timeCreated: 1619867067

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class InstanceProvider : IInstanceProvider
{
readonly IInjector injector;
readonly IReadOnlyList<IInjectParameter> customParameters;
public InstanceProvider(
IInjector injector,
IReadOnlyList<IInjectParameter> customParameters = null)
{
this.injector = injector;
this.customParameters = customParameters;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public object SpawnInstance(IObjectResolver resolver)
=> injector.CreateInstance(resolver, customParameters);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7f72f5485924ec19d7761e215e23a16
timeCreated: 1637903141

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace VContainer.Internal
{
public class OpenGenericInstanceProvider : IInstanceProvider
{
class TypeParametersEqualityComparer : IEqualityComparer<Type[]>
{
public bool Equals(Type[] x, Type[] y)
{
if (x == null || y == null) return x == y;
if (x.Length != y.Length) return false;
for (var i = 0; i < x.Length; i++)
{
if (x[i] != y[i]) return false;
}
return true;
}
public int GetHashCode(Type[] typeParameters)
{
var hash = 5381;
foreach (var typeParameter in typeParameters)
{
hash = ((hash << 5) + hash) ^ typeParameter.GetHashCode();
}
return hash;
}
}
readonly Lifetime lifetime;
readonly Type implementationType;
readonly IReadOnlyList<IInjectParameter> customParameters;
readonly ConcurrentDictionary<Type[], Registration> constructedRegistrations = new ConcurrentDictionary<Type[], Registration>(new TypeParametersEqualityComparer());
readonly Func<Type[], Registration> createRegistrationFunc;
public OpenGenericInstanceProvider(Type implementationType, Lifetime lifetime, List<IInjectParameter> injectParameters)
{
this.implementationType = implementationType;
this.lifetime = lifetime;
customParameters = injectParameters;
createRegistrationFunc = CreateRegistration;
}
public Registration GetClosedRegistration(Type closedInterfaceType, Type[] typeParameters)
{
return constructedRegistrations.GetOrAdd(typeParameters, createRegistrationFunc);
}
Registration CreateRegistration(Type[] typeParameters)
{
var newType = implementationType.MakeGenericType(typeParameters);
var injector = InjectorCache.GetOrBuild(newType);
var spawner = new InstanceProvider(injector, customParameters);
return new Registration(newType, lifetime, new List<Type>(1) { newType }, spawner);
}
public object SpawnInstance(IObjectResolver resolver)
{
throw new InvalidOperationException();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 927f2cb4e816642cba170d66ffc1fcb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,22 @@
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class InstanceRegistrationBuilder : RegistrationBuilder
{
readonly object implementationInstance;
public InstanceRegistrationBuilder(object implementationInstance)
: base(implementationInstance.GetType(), Lifetime.Singleton)
{
this.implementationInstance = implementationInstance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override Registration Build()
{
var spawner = new ExistingInstanceProvider(implementationInstance);
return new Registration(ImplementationType, Lifetime, InterfaceTypes, spawner);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 097b02c25ccf47df97386afb6a4f0c21
timeCreated: 1619863604

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
namespace VContainer.Internal
{
internal static class ListPool<T>
{
const int DefaultCapacity = 32;
private static readonly Stack<List<T>> _pool = new Stack<List<T>>(4);
/// <summary>
/// BufferScope supports releasing a buffer with using clause.
/// </summary>
internal readonly struct BufferScope : IDisposable
{
private readonly List<T> _buffer;
public BufferScope(List<T> buffer)
{
_buffer = buffer;
}
public void Dispose()
{
Release(_buffer);
}
}
/// <summary>
/// Get a buffer from the pool.
/// </summary>
/// <returns></returns>
internal static List<T> Get()
{
lock (_pool)
{
if (_pool.Count == 0)
{
return new List<T>(DefaultCapacity);
}
return _pool.Pop();
}
}
/// <summary>
/// Get a buffer from the pool. Returning a disposable struct to support recycling via using clause.
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
internal static BufferScope Get(out List<T> buffer)
{
buffer = Get();
return new BufferScope(buffer);
}
/// <summary>
/// Declare a buffer won't be used anymore and put it back to the pool.
/// </summary>
/// <param name="buffer"></param>
internal static void Release(List<T> buffer)
{
buffer.Clear();
lock (_pool)
{
_pool.Push(buffer);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da1a74df3eab442e81879a0b2e6fac0e
timeCreated: 1606668004

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
namespace VContainer.Internal
{
public class OpenGenericRegistrationBuilder : RegistrationBuilder
{
public OpenGenericRegistrationBuilder(Type implementationType, Lifetime lifetime)
: base(implementationType, lifetime)
{
if (!implementationType.IsGenericType || implementationType.IsConstructedGenericType)
throw new VContainerException(implementationType, "Type is not open generic type.");
}
public override Registration Build()
{
var provider = new OpenGenericInstanceProvider(ImplementationType, Lifetime, Parameters);
return new Registration(ImplementationType, Lifetime, InterfaceTypes, provider);
}
public override RegistrationBuilder AsImplementedInterfaces()
{
InterfaceTypes = InterfaceTypes ?? new List<Type>();
foreach (var i in ImplementationType.GetInterfaces())
{
if (!i.IsGenericType)
continue;
InterfaceTypes.Add(i.GetGenericTypeDefinition());
}
return this;
}
protected override void AddInterfaceType(Type interfaceType)
{
if (interfaceType.IsConstructedGenericType)
throw new VContainerException(interfaceType, "Type is not open generic type.");
foreach (var i in ImplementationType.GetInterfaces())
{
if (!i.IsGenericType || i.GetGenericTypeDefinition() != interfaceType)
continue;
if (InterfaceTypes is null)
{
InterfaceTypes = new List<Type>();
}
if (!InterfaceTypes.Contains(interfaceType))
InterfaceTypes.Add(interfaceType);
return;
}
base.AddInterfaceType(interfaceType);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41ece9cea6ed8424db8850c90169cb5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
sealed class ReflectionInjector : IInjector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReflectionInjector Build(Type type)
{
var injectTypeInfo = TypeAnalyzer.AnalyzeWithCache(type);
return new ReflectionInjector(injectTypeInfo);
}
readonly InjectTypeInfo injectTypeInfo;
ReflectionInjector(InjectTypeInfo injectTypeInfo)
{
this.injectTypeInfo = injectTypeInfo;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Inject(object instance, IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
InjectFields(instance, resolver, parameters);
InjectProperties(instance, resolver, parameters);
InjectMethods(instance, resolver, parameters);
}
public object CreateInstance(IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
var parameterInfos = injectTypeInfo.InjectConstructor.ParameterInfos;
var parameterValues = CappedArrayPool<object>.Shared8Limit.Rent(parameterInfos.Length);
try
{
for (var i = 0; i < parameterInfos.Length; i++)
{
var parameterInfo = parameterInfos[i];
parameterValues[i] = resolver.ResolveOrParameter(
parameterInfo.ParameterType,
parameterInfo.Name,
parameters);
}
var instance = injectTypeInfo.InjectConstructor.ConstructorInfo.Invoke(parameterValues);
Inject(instance, resolver, parameters);
return instance;
}
catch (VContainerException ex)
{
throw new VContainerException(ex.InvalidType, $"Failed to resolve {injectTypeInfo.Type} : {ex.Message}");
}
finally
{
CappedArrayPool<object>.Shared8Limit.Return(parameterValues);
}
}
void InjectFields(object obj, IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
if (injectTypeInfo.InjectFields == null)
return;
foreach (var x in injectTypeInfo.InjectFields)
{
var fieldValue = resolver.ResolveOrParameter(x.FieldType, x.Name, parameters);
x.SetValue(obj, fieldValue);
}
}
void InjectProperties(object obj, IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
if (injectTypeInfo.InjectProperties == null)
return;
foreach (var x in injectTypeInfo.InjectProperties)
{
var propValue = resolver.ResolveOrParameter(x.PropertyType, x.Name, parameters);
x.SetValue(obj, propValue);
}
}
void InjectMethods(object obj, IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
if (injectTypeInfo.InjectMethods == null)
return;
foreach (var method in injectTypeInfo.InjectMethods)
{
var parameterInfos = method.ParameterInfos;
var parameterValues = CappedArrayPool<object>.Shared8Limit.Rent(parameterInfos.Length);
try
{
for (var i = 0; i < parameterInfos.Length; i++)
{
var parameterInfo = parameterInfos[i];
parameterValues[i] = resolver.ResolveOrParameter(
parameterInfo.ParameterType,
parameterInfo.Name,
parameters);
}
method.MethodInfo.Invoke(obj, parameterValues);
}
catch (VContainerException ex)
{
throw new VContainerException(ex.InvalidType, $"Failed to resolve {injectTypeInfo.Type} : {ex.Message}");
}
finally
{
CappedArrayPool<object>.Shared8Limit.Return(parameterValues);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 49d591b36bd7b4319a86f326ba19fed0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace VContainer.Internal
{
static class RuntimeTypeCache
{
static readonly ConcurrentDictionary<Type, Type> OpenGenericTypes = new ConcurrentDictionary<Type, Type>();
static readonly ConcurrentDictionary<Type, Type[]> GenericTypeParameters = new ConcurrentDictionary<Type, Type[]>();
static readonly ConcurrentDictionary<Type, Type> ArrayTypes = new ConcurrentDictionary<Type, Type>();
static readonly ConcurrentDictionary<Type, Type> EnumerableTypes = new ConcurrentDictionary<Type, Type>();
static readonly ConcurrentDictionary<Type, Type> ReadOnlyListTypes = new ConcurrentDictionary<Type, Type>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Type OpenGenericTypeOf(Type closedGenericType)
=> OpenGenericTypes.GetOrAdd(closedGenericType, key => key.GetGenericTypeDefinition());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Type[] GenericTypeParametersOf(Type closedGenericType)
=> GenericTypeParameters.GetOrAdd(closedGenericType, key => key.GetGenericArguments());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Type ArrayTypeOf(Type elementType)
=> ArrayTypes.GetOrAdd(elementType, key => key.MakeArrayType());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Type EnumerableTypeOf(Type elementType)
=> EnumerableTypes.GetOrAdd(elementType, key => typeof(IEnumerable<>).MakeGenericType(key));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Type ReadOnlyListTypeOf(Type elementType)
=> ReadOnlyListTypes.GetOrAdd(elementType, key => typeof(IReadOnlyList<>).MakeGenericType(key));
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9be1b596e081421dbb84a84fb2ec17fe
timeCreated: 1637461795

View File

@ -0,0 +1,408 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace VContainer.Internal
{
sealed class InjectConstructorInfo
{
public readonly ConstructorInfo ConstructorInfo;
public readonly ParameterInfo[] ParameterInfos;
public InjectConstructorInfo(ConstructorInfo constructorInfo)
{
ConstructorInfo = constructorInfo;
ParameterInfos = constructorInfo.GetParameters();
}
public InjectConstructorInfo(ConstructorInfo constructorInfo, ParameterInfo[] parameterInfos)
{
ConstructorInfo = constructorInfo;
ParameterInfos = parameterInfos;
}
}
sealed class InjectMethodInfo
{
public readonly MethodInfo MethodInfo;
public readonly ParameterInfo[] ParameterInfos;
public InjectMethodInfo(MethodInfo methodInfo)
{
MethodInfo = methodInfo;
ParameterInfos = methodInfo.GetParameters();
}
}
// sealed class InjectFieldInfo
// {
// public readonly Type FieldType;
// public readonly Action<object, object> Setter;
//
// public InjectFieldInfo(FieldInfo fieldInfo)
// {
// FieldType = fieldInfo.FieldType;
// Setter = fieldInfo.SetValue;
// }
// }
//
// sealed class InjectPropertyInfo
// {
// public readonly Type PropertyType;
// public readonly Action<object, object> Setter;
//
// public InjectPropertyInfo(PropertyInfo propertyInfo)
// {
// PropertyType = propertyInfo.PropertyType;
// Setter = propertyInfo.SetValue;
// }
// }
sealed class InjectTypeInfo
{
public readonly Type Type;
public readonly InjectConstructorInfo InjectConstructor;
public readonly IReadOnlyList<InjectMethodInfo> InjectMethods;
public readonly IReadOnlyList<FieldInfo> InjectFields;
public readonly IReadOnlyList<PropertyInfo> InjectProperties;
public InjectTypeInfo(
Type type,
InjectConstructorInfo injectConstructor,
IReadOnlyList<InjectMethodInfo> injectMethods,
IReadOnlyList<FieldInfo> injectFields,
IReadOnlyList<PropertyInfo> injectProperties)
{
Type = type;
InjectConstructor = injectConstructor;
InjectFields = injectFields;
InjectProperties = injectProperties;
InjectMethods = injectMethods;
}
}
readonly struct DependencyInfo
{
public Type ImplementationType => Dependency.ImplementationType;
public IInstanceProvider Provider => Dependency.Provider;
public readonly Registration Dependency;
readonly Registration owner;
readonly object method; // ctor or method
readonly ParameterInfo param; // param or field or prop
public DependencyInfo(Registration dependency)
{
Dependency = dependency;
owner = null;
method = null;
param = null;
}
public DependencyInfo(Registration dependency, Registration owner, ConstructorInfo ctor, ParameterInfo param)
{
Dependency = dependency;
this.owner = owner;
method = ctor;
this.param = param;
}
public DependencyInfo(Registration dependency, Registration owner, MethodInfo method, ParameterInfo param)
{
Dependency = dependency;
this.owner = owner;
this.method = method;
this.param = param;
}
public DependencyInfo(Registration dependency, Registration owner, FieldInfo field)
{
Dependency = dependency;
this.owner = owner;
method = field;
param = null;
}
public DependencyInfo(Registration dependency, Registration owner, PropertyInfo prop)
{
Dependency = dependency;
this.owner = owner;
method = prop;
param = null;
}
public override string ToString()
{
switch (method)
{
case ConstructorInfo _:
return $"{owner.ImplementationType}..ctor({param.Name})";
case MethodInfo methodInfo:
return $"{owner.ImplementationType.FullName}.{methodInfo.Name}({param.Name})";
case FieldInfo field:
return $"{owner.ImplementationType.FullName}.{field.Name}";
case PropertyInfo prop:
return $"{owner.ImplementationType.FullName}.{prop.Name}";
default:
return "";
}
}
}
static class TypeAnalyzer
{
public static InjectTypeInfo AnalyzeWithCache(Type type) => Cache.GetOrAdd(type, AnalyzeFunc);
static readonly ConcurrentDictionary<Type, InjectTypeInfo> Cache = new ConcurrentDictionary<Type, InjectTypeInfo>();
[ThreadStatic]
static Stack<DependencyInfo> circularDependencyChecker;
static readonly Func<Type, InjectTypeInfo> AnalyzeFunc = Analyze;
public static InjectTypeInfo Analyze(Type type)
{
var injectConstructor = default(InjectConstructorInfo);
var analyzedType = type;
var typeInfo = type.GetTypeInfo();
// Constructor, single [Inject] constructor -> single most parameters constructor
var annotatedConstructorCount = 0;
var maxParameters = -1;
foreach (var constructorInfo in typeInfo.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
if (constructorInfo.IsDefined(typeof(InjectAttribute), false))
{
if (++annotatedConstructorCount > 1)
{
throw new VContainerException(type, $"Type found multiple [Inject] marked constructors, type: {type.Name}");
}
injectConstructor = new InjectConstructorInfo(constructorInfo);
}
else if (annotatedConstructorCount <= 0)
{
var parameterInfos = constructorInfo.GetParameters();
if (parameterInfos.Length > maxParameters)
{
injectConstructor = new InjectConstructorInfo(constructorInfo, parameterInfos);
maxParameters = parameterInfos.Length;
}
}
}
if (injectConstructor == null)
{
var allowNoConstructor = type.IsEnum;
#if UNITY_2018_4_OR_NEWER
// It seems that Unity sometimes strips the constructor of Component at build time.
// In that case, allow null.
allowNoConstructor |= type.IsSubclassOf(typeof(UnityEngine.Component));
#endif
if (!allowNoConstructor)
throw new VContainerException(type, $"Type does not found injectable constructor, type: {type.Name}");
}
var injectMethods = default(List<InjectMethodInfo>);
var injectFields = default(List<FieldInfo>);
var injectProperties = default(List<PropertyInfo>);
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
while (type != null && type != typeof(object))
{
// Methods, [Inject] Only
var methods = type.GetMethods(bindingFlags);
foreach (var methodInfo in methods)
{
if (methodInfo.IsDefined(typeof(InjectAttribute), false))
{
if (injectMethods == null)
{
injectMethods = new List<InjectMethodInfo>();
}
else
{
// Skip if already exists
foreach (var x in injectMethods)
{
if (x.MethodInfo.GetBaseDefinition() == methodInfo.GetBaseDefinition())
goto EndMethod;
}
}
injectMethods.Add(new InjectMethodInfo(methodInfo));
}
}
EndMethod:
// Fields, [Inject] Only
var fields = type.GetFields(bindingFlags);
foreach (var fieldInfo in fields)
{
if (fieldInfo.IsDefined(typeof(InjectAttribute), false))
{
if (injectFields == null)
{
injectFields = new List<FieldInfo>();
}
else
{
if (Contains(injectFields, fieldInfo))
{
var message = $"Duplicate injection found for field: {fieldInfo}";
throw new VContainerException(type, message);
}
if (injectFields.Any(x => x.Name == fieldInfo.Name))
{
continue;
}
}
injectFields.Add(fieldInfo);
}
}
// Properties, [Inject] only
var props = type.GetProperties(bindingFlags);
foreach (var propertyInfo in props)
{
if (propertyInfo.IsDefined(typeof(InjectAttribute), false))
{
if (injectProperties == null)
{
injectProperties = new List<PropertyInfo>();
}
else
{
foreach (var x in injectProperties)
{
if (x.Name == propertyInfo.Name)
goto EndProperty;
}
}
injectProperties.Add(propertyInfo);
}
}
EndProperty:
type = type.BaseType;
}
return new InjectTypeInfo(
analyzedType,
injectConstructor,
injectMethods,
injectFields,
injectProperties);
}
private static bool Contains(List<FieldInfo> fields, FieldInfo field)
{
for (var i = 0; i < fields.Count; i++)
{
var x = fields[i];
if (x.Name == field.Name)
{
return true;
}
}
return false;
}
public static void CheckCircularDependency(IReadOnlyList<Registration> registrations, Registry registry)
{
// ThreadStatic
if (circularDependencyChecker == null)
circularDependencyChecker = new Stack<DependencyInfo>();
for (var i = 0; i < registrations.Count; i++)
{
circularDependencyChecker.Clear();
CheckCircularDependencyRecursive(new DependencyInfo(registrations[i]), registry, circularDependencyChecker);
}
}
static void CheckCircularDependencyRecursive(DependencyInfo current, Registry registry, Stack<DependencyInfo> stack)
{
var i = 0;
foreach (var dependency in stack)
{
if (current.ImplementationType == dependency.ImplementationType)
{
// When instantiated by Func, the abstract type cycle is user-avoidable.
if (current.Dependency.Provider is FuncInstanceProvider)
{
return;
}
stack.Push(current);
var path = string.Join("\n",
stack.Take(i + 1)
.Reverse()
.Select((item, itemIndex) => $" [{itemIndex + 1}] {item} --> {item.ImplementationType.FullName}"));
throw new VContainerException(current.Dependency.ImplementationType,
$"Circular dependency detected!\n{path}");
}
i++;
}
stack.Push(current);
if (Cache.TryGetValue(current.ImplementationType, out var injectTypeInfo))
{
if (injectTypeInfo.InjectConstructor != null)
{
foreach (var x in injectTypeInfo.InjectConstructor.ParameterInfos)
{
if (registry.TryGet(x.ParameterType, out var parameterRegistration))
{
CheckCircularDependencyRecursive(new DependencyInfo(parameterRegistration, current.Dependency, injectTypeInfo.InjectConstructor.ConstructorInfo, x), registry, stack);
}
}
}
if (injectTypeInfo.InjectMethods != null)
{
foreach (var methodInfo in injectTypeInfo.InjectMethods)
{
foreach (var x in methodInfo.ParameterInfos)
{
if (registry.TryGet(x.ParameterType, out var parameterRegistration))
{
CheckCircularDependencyRecursive(new DependencyInfo(parameterRegistration, current.Dependency, methodInfo.MethodInfo, x), registry, stack);
}
}
}
}
if (injectTypeInfo.InjectFields != null)
{
foreach (var x in injectTypeInfo.InjectFields)
{
if (registry.TryGet(x.FieldType, out var fieldRegistration))
{
CheckCircularDependencyRecursive(new DependencyInfo(fieldRegistration, current.Dependency, x), registry, stack);
}
}
}
if (injectTypeInfo.InjectProperties != null)
{
foreach (var x in injectTypeInfo.InjectProperties)
{
if (registry.TryGet(x.PropertyType, out var propertyRegistration))
{
CheckCircularDependencyRecursive(new DependencyInfo(propertyRegistration, current.Dependency, x), registry, stack);
}
}
}
}
stack.Pop();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e1039990f285746d39d3d6656ccdaac3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More