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;
using Stashbox.Utils.Data.Immutable;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Stashbox.Registration
{
internal class RegistrationRepository : IRegistrationRepository
{
private ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> serviceRepository = ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>.Empty;
private readonly ContainerConfiguration containerConfiguration;
private readonly IRegistrationSelectionRule[] filters = new IRegistrationSelectionRule[4] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.NameFilter,
RegistrationSelectionRules.ScopeNameFilter,
RegistrationSelectionRules.ConditionFilter
};
private readonly IRegistrationSelectionRule[] topLevelFilters = new IRegistrationSelectionRule[3] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.NameFilter,
RegistrationSelectionRules.ScopeNameFilter
};
private readonly IRegistrationSelectionRule[] enumerableFilters = new IRegistrationSelectionRule[3] {
RegistrationSelectionRules.GenericFilter,
RegistrationSelectionRules.ScopeNameFilter,
RegistrationSelectionRules.ConditionFilter
};
public RegistrationRepository(ContainerConfiguration containerConfiguration)
{
this.containerConfiguration = containerConfiguration;
}
public bool AddOrUpdateRegistration(ServiceRegistration registration, Type serviceType)
{
if (registration.RegistrationContext.ReplaceExistingRegistrationOnlyIfExists)
return Swap.SwapValue<ServiceRegistration, Type, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (ServiceRegistration reg, Type type, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.UpdateIfExists(type, true, (ImmutableBucket<object, ServiceRegistration> regs) => regs.ReplaceIfExists(reg.RegistrationDiscriminator, reg, false, delegate(ServiceRegistration old, ServiceRegistration new) {
new.Replaces(old);
return new;
})), registration, serviceType, 0, 0);
return Swap.SwapValue(ref serviceRepository, (ServiceRegistration reg, Type type, ImmutableBucket<object, ServiceRegistration> newRepo, Rules.RegistrationBehavior regBehavior, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, delegate(ImmutableBucket<object, ServiceRegistration> oldValue, ImmutableBucket<object, ServiceRegistration> _) {
bool allowUpdate = reg.RegistrationContext.ReplaceExistingRegistration || regBehavior == Rules.RegistrationBehavior.ReplaceExisting;
if (!allowUpdate && regBehavior == Rules.RegistrationBehavior.PreserveDuplications)
return oldValue.Add(reg.RegistrationDiscriminator, reg);
return oldValue.AddOrUpdate(reg.RegistrationDiscriminator, reg, false, delegate(ServiceRegistration old, ServiceRegistration new) {
if (!allowUpdate) {
if (regBehavior == Rules.RegistrationBehavior.ThrowException)
throw new ServiceAlreadyRegisteredException(old.ImplementationType, null);
return old;
}
new.Replaces(old);
return new;
});
}), registration, serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), containerConfiguration.RegistrationBehavior);
}
public bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType)
{
if (!registration.RegistrationContext.ReplaceExistingRegistrationOnlyIfExists)
return Swap.SwapValue<Type, ImmutableBucket<object, ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<object, ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.AddOrUpdate(type, newRepo, true, true), serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), 0, 0);
return Swap.SwapValue<Type, ImmutableBucket<object, ServiceRegistration>, byte, byte, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>>>(ref serviceRepository, (Type type, ImmutableBucket<object, ServiceRegistration> newRepo, byte _, byte _, ImmutableTree<Type, ImmutableBucket<object, ServiceRegistration>> repo) => repo.UpdateIfExists(type, newRepo, true), serviceType, new ImmutableBucket<object, ServiceRegistration>(registration.RegistrationDiscriminator, registration), 0, 0);
}
public bool ContainsRegistration(Type type, object name, bool includeOpenGenerics = false)
{
return serviceRepository.ContainsRegistration(type, name, includeOpenGenerics);
}
public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings()
{
return serviceRepository.Walk().SelectMany((KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> reg) => from r in reg.Value
select new KeyValuePair<Type, ServiceRegistration>(reg.Key, r));
}
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);
}
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;
}
private IEnumerable<ServiceRegistration> GetRegistrationsForType(Type type)
{
IEnumerable<ServiceRegistration> enumerable = serviceRepository.GetOrDefaultByRef(type);
if (!type.IsClosedGenericType())
return enumerable;
ImmutableBucket<object, ServiceRegistration> orDefaultByRef = serviceRepository.GetOrDefaultByRef(type.GetGenericTypeDefinition());
if (orDefaultByRef != null) {
object enumerable2;
if (enumerable != null)
enumerable2 = orDefaultByRef.Concat(enumerable);
else {
IEnumerable<ServiceRegistration> enumerable3 = orDefaultByRef;
enumerable2 = enumerable3;
}
enumerable = (IEnumerable<ServiceRegistration>)enumerable2;
}
ServiceRegistration[] array = serviceRepository.Walk().Where(delegate(KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> r) {
if (r.Key.IsGenericType && r.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition() && r.Key != type)
return r.Key.ImplementsWithoutGenericCheck(type);
return false;
}).SelectMany((KeyValue<Type, ImmutableBucket<object, ServiceRegistration>> r) => r.Value)
.ToArray();
if (array.Length != 0) {
object enumerable4;
if (enumerable != null)
enumerable4 = array.Concat(enumerable);
else {
IEnumerable<ServiceRegistration> enumerable3 = array;
enumerable4 = enumerable3;
}
enumerable = (IEnumerable<ServiceRegistration>)enumerable4;
}
return enumerable;
}
}
}