RegistrationRepository
using Stashbox.Configuration;
using Stashbox.Exceptions;
using Stashbox.Registration.Extensions;
using Stashbox.Registration.SelectionRules;
using Stashbox.Resolution;
using Stashbox.Utils;
using Stashbox.Utils.Data.Immutable;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Stashbox.Registration
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal class RegistrationRepository : IRegistrationRepository
{
private ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> serviceRepository = ImmutableTree<Type, ImmutableBucket<ServiceRegistration>>.Empty;
private readonly ContainerConfiguration containerConfiguration;
private readonly IRegistrationSelectionRule[] filters = new IRegistrationSelectionRule[5] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.NameFilter,
RegistrationSelectionRules.MetadataFilter,
RegistrationSelectionRules.ScopeNameFilter,
RegistrationSelectionRules.ConditionFilter
};
private readonly IRegistrationSelectionRule[] topLevelFilters = new IRegistrationSelectionRule[4] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.NameFilter,
RegistrationSelectionRules.MetadataFilter,
RegistrationSelectionRules.ScopeNameFilter
};
private readonly IRegistrationSelectionRule[] enumerableFilters = new IRegistrationSelectionRule[5] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.EnumerableNameFilter,
RegistrationSelectionRules.ScopeNameFilter,
RegistrationSelectionRules.ConditionFilter,
RegistrationSelectionRules.MetadataFilter
};
public RegistrationRepository(ContainerConfiguration containerConfiguration)
{
this.containerConfiguration = containerConfiguration;
}
public bool AddOrUpdateRegistration(ServiceRegistration registration, Type serviceType)
{
if (registration.Options.IsOn(RegistrationOption.ReplaceExistingRegistrationOnlyIfExists))
return Swap.SwapValue<ServiceRegistration, Type, byte, byte, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>>>(ref serviceRepository, (ServiceRegistration reg, Type type, byte _, byte _, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> repo) => repo.UpdateIfExists(type, true, delegate(ImmutableBucket<ServiceRegistration> regs) {
int num2 = -1;
for (int j = 0; j < regs.Length; j++) {
ServiceRegistration serviceRegistration3 = regs[j];
object obj3 = serviceRegistration3.Name ?? serviceRegistration3.ImplementationType;
object obj4 = reg.Name ?? reg.ImplementationType;
if (obj3.Equals(obj4))
num2 = j;
}
if (num2 != -1) {
ServiceRegistration serviceRegistration4 = regs[num2];
reg.Replaces(serviceRegistration4);
return regs.ReplaceAt(num2, reg);
}
return regs;
}), registration, serviceType, 0, 0);
return Swap.SwapValue(ref serviceRepository, (ServiceRegistration reg, Type type, ImmutableBucket<ServiceRegistration> newRepo, Rules.RegistrationBehavior regBehavior, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, delegate(ImmutableBucket<ServiceRegistration> oldValue, ImmutableBucket<ServiceRegistration> _) {
bool flag = reg.Options.IsOn(RegistrationOption.ReplaceExistingRegistration);
bool flag2 = flag || regBehavior == Rules.RegistrationBehavior.ReplaceExisting;
if (!flag2 && regBehavior == Rules.RegistrationBehavior.PreserveDuplications)
return oldValue.Add(reg);
int num = -1;
for (int i = 0; i < oldValue.Length; i++) {
ServiceRegistration serviceRegistration = oldValue[i];
if (flag || !(serviceRegistration.ImplementationType != reg.ImplementationType)) {
object obj = serviceRegistration.Name ?? serviceRegistration.ImplementationType;
object obj2 = reg.Name ?? reg.ImplementationType;
if (obj.Equals(obj2))
num = i;
}
}
if (num != -1) {
if (!flag2) {
if (regBehavior == Rules.RegistrationBehavior.ThrowException)
throw new ServiceAlreadyRegisteredException(reg.ImplementationType, null);
return oldValue;
}
ServiceRegistration serviceRegistration2 = oldValue[num];
reg.Replaces(serviceRegistration2);
return oldValue.ReplaceAt(num, reg);
}
return oldValue.Add(reg);
}), registration, serviceType, new ImmutableBucket<ServiceRegistration>(registration), containerConfiguration.RegistrationBehavior);
}
public bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType)
{
if (!registration.Options.IsOn(RegistrationOption.ReplaceExistingRegistrationOnlyIfExists))
return Swap.SwapValue<Type, ImmutableBucket<ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, true), serviceType, new ImmutableBucket<ServiceRegistration>(registration), 0, 0);
return Swap.SwapValue<Type, ImmutableBucket<ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> repo) => repo.UpdateIfExists(type, newRepo, true), serviceType, new ImmutableBucket<ServiceRegistration>(registration), 0, 0);
}
public bool ContainsRegistration(Type type, [System.Runtime.CompilerServices.Nullable(2)] object name, bool includeOpenGenerics = true)
{
return serviceRepository.ContainsRegistration(type, name, includeOpenGenerics);
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
1,
0,
1,
1
})]
public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings()
{
return serviceRepository.Walk().SelectMany((ReadOnlyKeyValue<Type, ImmutableBucket<ServiceRegistration>> reg) => from r in reg.Value.Repository
select new KeyValuePair<Type, ServiceRegistration>(reg.Key, r));
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public ServiceRegistration GetRegistrationOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(typeInfo.Type);
if (registrationsForType == null)
return null;
return registrationsForType.SelectOrDefault(typeInfo, resolutionContext, resolutionContext.IsTopRequest ? topLevelFilters : filters);
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
public IEnumerable<ServiceRegistration> GetRegistrationsOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext)
{
IEnumerable<ServiceRegistration> registrationsForType = GetRegistrationsForType(typeInfo.Type);
if (registrationsForType == null)
return null;
IEnumerable<ServiceRegistration> enumerable = registrationsForType.FilterExclusiveOrDefault(typeInfo, resolutionContext, enumerableFilters);
if (enumerable == null)
return null;
return from reg in enumerable
orderby reg.RegistrationOrder
select reg;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
private IEnumerable<ServiceRegistration> GetRegistrationsForType(Type type)
{
IEnumerable<ServiceRegistration> enumerable = serviceRepository.GetOrDefaultByRef(type)?.Repository;
if (!type.IsClosedGenericType())
return enumerable;
ServiceRegistration[] array = serviceRepository.GetOrDefaultByRef(type.GetGenericTypeDefinition())?.Repository;
if (array != null) {
object enumerable2;
if (enumerable != null)
enumerable2 = array.Concat(enumerable);
else {
IEnumerable<ServiceRegistration> enumerable3 = array;
enumerable2 = enumerable3;
}
enumerable = (IEnumerable<ServiceRegistration>)enumerable2;
}
ServiceRegistration[] array2 = serviceRepository.Walk().Where(delegate(ReadOnlyKeyValue<Type, ImmutableBucket<ServiceRegistration>> r) {
if (r.Key.IsGenericType && r.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition() && r.Key != type)
return r.Key.ImplementsWithoutGenericCheck(type);
return false;
}).SelectMany((ReadOnlyKeyValue<Type, ImmutableBucket<ServiceRegistration>> r) => r.Value.Repository)
.ToArray();
if (array2.Length != 0) {
object enumerable4;
if (enumerable != null)
enumerable4 = array2.Concat(enumerable);
else {
IEnumerable<ServiceRegistration> enumerable3 = array2;
enumerable4 = enumerable3;
}
enumerable = (IEnumerable<ServiceRegistration>)enumerable4;
}
return enumerable;
}
}
}