Skip to content

Commit

Permalink
revise impl of return type detection
Browse files Browse the repository at this point in the history
  • Loading branch information
martinothamar committed Apr 1, 2024
1 parent 68806ef commit ae39563
Show file tree
Hide file tree
Showing 30 changed files with 907 additions and 429 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ namespace Microsoft.Extensions.DependencyInjection
return AddMediator(services, null);
}

internal sealed class Dummy { }

/// <summary>
/// Adds the Mediator implementation and handlers of your application, with specified options.
/// </summary>
Expand Down Expand Up @@ -102,7 +100,10 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAdd(new SD(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService<{{ NotificationPublisherType.FullName }}>(), {{ SingletonServiceLifetime }}));
{{~ end ~}}

services.AddSingleton<Dummy>();
services.Add(new SD(typeof(global::{{ MediatorNamespace }}.IContainerProbe), typeof(global::{{ MediatorNamespace }}.ContainerProbe0), {{ ServiceLifetime }}));
services.Add(new SD(typeof(global::{{ MediatorNamespace }}.IContainerProbe), typeof(global::{{ MediatorNamespace }}.ContainerProbe1), {{ ServiceLifetime }}));

services.Add(new SD(typeof(global::{{ MediatorNamespace }}.ContainerMetadata), typeof(global::{{ MediatorNamespace }}.ContainerMetadata), {{ SingletonServiceLifetime }}));

return services;

Expand Down Expand Up @@ -175,6 +176,30 @@ namespace {{ MediatorNamespace }}
}
{{~ end ~}}

internal interface IContainerProbe { }
internal sealed class ContainerProbe0 : IContainerProbe { }
internal sealed class ContainerProbe1 : IContainerProbe { }

[global::System.CodeDom.Compiler.GeneratedCode("Mediator.SourceGenerator", "{{ GeneratorVersion }}")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.Diagnostics.DebuggerStepThroughAttribute]
internal sealed class ContainerMetadata
{
public readonly bool ServicesUnderlyingTypeIsArray;

public ContainerMetadata(global::System.IServiceProvider sp)
{
{{~ if ServiceLifetimeIsScoped ~}}
using (var scope = sp.CreateScope())
{
ServicesUnderlyingTypeIsArray = scope.ServiceProvider.GetServices<global::{{ MediatorNamespace }}.IContainerProbe>() is global::{{ MediatorNamespace }}.IContainerProbe[];
}
{{~ else ~}}
ServicesUnderlyingTypeIsArray = sp.GetServices<global::{{ MediatorNamespace }}.IContainerProbe>() is global::{{ MediatorNamespace }}.IContainerProbe[];
{{~ end ~}}
}
}

/// <summary>
/// Generated code for Mediator implementation.
/// This type is also registered as a DI service.
Expand All @@ -186,6 +211,8 @@ namespace {{ MediatorNamespace }}
public sealed partial class Mediator : global::Mediator.IMediator, global::Mediator.ISender, global::Mediator.IPublisher
{
private readonly global::System.IServiceProvider _sp;
private readonly global::{{ MediatorNamespace }}.ContainerMetadata _containerMetadata;

{{~ if ServiceLifetimeIsSingleton ~}}
{{ if IsTestRun }}internal{{ else }}private{{ end }} FastLazyValue<DICache> _diCacheLazy;
{{~ else ~}}
Expand All @@ -197,26 +224,18 @@ namespace {{ MediatorNamespace }}
/// </summary>
public static global::Microsoft.Extensions.DependencyInjection.ServiceLifetime ServiceLifetime { get; } = {{ ServiceLifetime }};

private readonly global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> _getServicesLength;

/// <summary>
/// Constructor for DI, should not be used by consumer.
/// </summary>
public Mediator(global::System.IServiceProvider sp)
{
_sp = sp;
_containerMetadata = sp.GetRequiredService<global::{{ MediatorNamespace }}.ContainerMetadata>();
{{~ if ServiceLifetimeIsSingleton ~}}
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp));
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp, _containerMetadata));
{{~ else ~}}
_diCache = new DICache(_sp);
_diCache = new DICache(_sp, _containerMetadata);
{{~ end ~}}

global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> fastGetLength = s => ((object[])s).Length;
global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> slowGetLength = s => s.Count();

var dummy = sp.GetServices<global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy>();
_getServicesLength = dummy.GetType() == typeof(global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy[])
? fastGetLength : slowGetLength;
}

{{~ if ServiceLifetimeIsSingleton ~}}
Expand Down Expand Up @@ -360,7 +379,7 @@ namespace {{ MediatorNamespace }}
}
{{~ end ~}}

public DICache(global::System.IServiceProvider sp)
public DICache(global::System.IServiceProvider sp, global::{{ MediatorNamespace }}.ContainerMetadata containerMetadata)
{
_sp = sp;

Expand All @@ -371,7 +390,19 @@ namespace {{ MediatorNamespace }}
{{~ end ~}}

{{~ for message in NotificationMessages ~}}
Handlers_For_{{ message.IdentifierFullName }} = sp.GetServices<global::Mediator.INotificationHandler<{{ message.FullName }}>>().ToArray();
var handlers_For_{{ message.IdentifierFullName }} = sp.GetServices<global::Mediator.INotificationHandler<{{ message.FullName }}>>();
if (containerMetadata.ServicesUnderlyingTypeIsArray)
{
global::System.Diagnostics.Debug.Assert(handlers_For_{{ message.IdentifierFullName }} is global::Mediator.INotificationHandler<{{ message.FullName }}>[]);
Handlers_For_{{ message.IdentifierFullName }} = global::System.Runtime.CompilerServices.Unsafe.As<global::Mediator.INotificationHandler<{{ message.FullName }}>[]>(
handlers_For_{{ message.IdentifierFullName }}
);
}
else
{
global::System.Diagnostics.Debug.Assert(handlers_For_{{ message.IdentifierFullName }} is not global::Mediator.INotificationHandler<{{ message.FullName }}>[]);
Handlers_For_{{ message.IdentifierFullName }} = handlers_For_{{ message.IdentifierFullName }}.ToArray();
}
{{~ end ~}}

{{~ end ~}}
Expand Down Expand Up @@ -890,15 +921,27 @@ namespace {{ MediatorNamespace }}
}
var publisher = _diCacheLazy.Value.InternalNotificationPublisherImpl;
return publisher.Publish(
new global::Mediator.NotificationHandlers<{{ message.FullName }}>(handlers),
new global::Mediator.NotificationHandlers<{{ message.FullName }}>(handlers, isArray: true),
notification,
cancellationToken
);

{{~ else ~}}
var isArray = _containerMetadata.ServicesUnderlyingTypeIsArray;
if (isArray)
{
global::System.Diagnostics.Debug.Assert(handlers is global::Mediator.INotificationHandler<{{ message.FullName }}>[]);
if (global::System.Runtime.CompilerServices.Unsafe.As<global::Mediator.INotificationHandler<{{ message.FullName }}>[]>(handlers).Length == 0)
{
return default;
}
}
else
{
global::System.Diagnostics.Debug.Assert(handlers is not global::Mediator.INotificationHandler<{{ message.FullName }}>[]);
}
var publisher = _diCache.InternalNotificationPublisherImpl;
return publisher.Publish(
new global::Mediator.NotificationHandlers<{{ message.FullName }}>(handlers),
new global::Mediator.NotificationHandlers<{{ message.FullName }}>(handlers, isArray),
notification,
cancellationToken
);
Expand Down
8 changes: 4 additions & 4 deletions src/Mediator/INotificationPublisher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,14 @@ internal readonly bool IsArray([MaybeNullWhen(false)] out INotificationHandler<T

/// <summary>
/// Constructs a new instance of <see cref="NotificationHandlers{TNotification}"/>.
/// Should _NOT_ be used by user code, only by the generated code in the Mediator implementation.
/// Do _NOT_ invoke this manually, is only supposed to be used by the source generator.
/// </summary>
/// <param name="handlers"></param>
public NotificationHandlers(IEnumerable<INotificationHandler<TNotification>> handlers)
/// <param name="isArray"></param>
public NotificationHandlers(IEnumerable<INotificationHandler<TNotification>> handlers, bool isArray)
{
_handlers = handlers;
if (handlers is INotificationHandler<TNotification>[])
_isArray = true;
_isArray = isArray;
}

public readonly bool IsSingleHandler([MaybeNullWhen(false)] out INotificationHandler<TNotification> handler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ public static IServiceCollection AddMediator(this IServiceCollection services)
return AddMediator(services, null);
}

internal sealed class Dummy { }

/// <summary>
/// Adds the Mediator implementation and handlers of your application, with specified options.
/// </summary>
Expand Down Expand Up @@ -68,7 +66,10 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g
services.Add(new SD(typeof(global::Mediator.TaskWhenAllPublisher), typeof(global::Mediator.TaskWhenAllPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));
services.TryAdd(new SD(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService<global::Mediator.TaskWhenAllPublisher>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

services.AddSingleton<Dummy>();
services.Add(new SD(typeof(global::Mediator.IContainerProbe), typeof(global::Mediator.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));
services.Add(new SD(typeof(global::Mediator.IContainerProbe), typeof(global::Mediator.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

services.Add(new SD(typeof(global::Mediator.ContainerMetadata), typeof(global::Mediator.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

return services;

Expand Down Expand Up @@ -415,6 +416,23 @@ public StreamQueryStructHandlerWrapper(
_rootHandler(request, cancellationToken);
}

internal interface IContainerProbe { }
internal sealed class ContainerProbe0 : IContainerProbe { }
internal sealed class ContainerProbe1 : IContainerProbe { }

[global::System.CodeDom.Compiler.GeneratedCode("Mediator.SourceGenerator", "3.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.Diagnostics.DebuggerStepThroughAttribute]
internal sealed class ContainerMetadata
{
public readonly bool ServicesUnderlyingTypeIsArray;

public ContainerMetadata(global::System.IServiceProvider sp)
{
ServicesUnderlyingTypeIsArray = sp.GetServices<global::Mediator.IContainerProbe>() is global::Mediator.IContainerProbe[];
}
}

/// <summary>
/// Generated code for Mediator implementation.
/// This type is also registered as a DI service.
Expand All @@ -426,29 +444,23 @@ public StreamQueryStructHandlerWrapper(
public sealed partial class Mediator : global::Mediator.IMediator, global::Mediator.ISender, global::Mediator.IPublisher
{
private readonly global::System.IServiceProvider _sp;
private readonly global::Mediator.ContainerMetadata _containerMetadata;

private FastLazyValue<DICache> _diCacheLazy;

/// <summary>
/// The lifetime of Mediator-related service registrations in DI container.
/// </summary>
public static global::Microsoft.Extensions.DependencyInjection.ServiceLifetime ServiceLifetime { get; } = global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton;

private readonly global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> _getServicesLength;

/// <summary>
/// Constructor for DI, should not be used by consumer.
/// </summary>
public Mediator(global::System.IServiceProvider sp)
{
_sp = sp;
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp));

global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> fastGetLength = s => ((object[])s).Length;
global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> slowGetLength = s => s.Count();

var dummy = sp.GetServices<global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy>();
_getServicesLength = dummy.GetType() == typeof(global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy[])
? fastGetLength : slowGetLength;
_containerMetadata = sp.GetRequiredService<global::Mediator.ContainerMetadata>();
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp, _containerMetadata));
}

private struct FastLazyValue<T>
Expand Down Expand Up @@ -519,7 +531,7 @@ private readonly struct DICache

public readonly global::Mediator.TaskWhenAllPublisher InternalNotificationPublisherImpl;

public DICache(global::System.IServiceProvider sp)
public DICache(global::System.IServiceProvider sp, global::Mediator.ContainerMetadata containerMetadata)
{
_sp = sp;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ public static IServiceCollection AddMediator(this IServiceCollection services)
return AddMediator(services, null);
}

internal sealed class Dummy { }

/// <summary>
/// Adds the Mediator implementation and handlers of your application, with specified options.
/// </summary>
Expand Down Expand Up @@ -68,7 +66,10 @@ public static IServiceCollection AddMediator(this IServiceCollection services, g
services.Add(new SD(typeof(global::Mediator.ForeachAwaitPublisher), typeof(global::Mediator.ForeachAwaitPublisher), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));
services.TryAdd(new SD(typeof(global::Mediator.INotificationPublisher), sp => sp.GetRequiredService<global::Mediator.ForeachAwaitPublisher>(), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

services.AddSingleton<Dummy>();
services.Add(new SD(typeof(global::Mediator.IContainerProbe), typeof(global::Mediator.ContainerProbe0), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));
services.Add(new SD(typeof(global::Mediator.IContainerProbe), typeof(global::Mediator.ContainerProbe1), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

services.Add(new SD(typeof(global::Mediator.ContainerMetadata), typeof(global::Mediator.ContainerMetadata), global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton));

return services;

Expand Down Expand Up @@ -415,6 +416,23 @@ public StreamQueryStructHandlerWrapper(
_rootHandler(request, cancellationToken);
}

internal interface IContainerProbe { }
internal sealed class ContainerProbe0 : IContainerProbe { }
internal sealed class ContainerProbe1 : IContainerProbe { }

[global::System.CodeDom.Compiler.GeneratedCode("Mediator.SourceGenerator", "3.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.Diagnostics.DebuggerStepThroughAttribute]
internal sealed class ContainerMetadata
{
public readonly bool ServicesUnderlyingTypeIsArray;

public ContainerMetadata(global::System.IServiceProvider sp)
{
ServicesUnderlyingTypeIsArray = sp.GetServices<global::Mediator.IContainerProbe>() is global::Mediator.IContainerProbe[];
}
}

/// <summary>
/// Generated code for Mediator implementation.
/// This type is also registered as a DI service.
Expand All @@ -426,29 +444,23 @@ public StreamQueryStructHandlerWrapper(
public sealed partial class Mediator : global::Mediator.IMediator, global::Mediator.ISender, global::Mediator.IPublisher
{
private readonly global::System.IServiceProvider _sp;
private readonly global::Mediator.ContainerMetadata _containerMetadata;

private FastLazyValue<DICache> _diCacheLazy;

/// <summary>
/// The lifetime of Mediator-related service registrations in DI container.
/// </summary>
public static global::Microsoft.Extensions.DependencyInjection.ServiceLifetime ServiceLifetime { get; } = global::Microsoft.Extensions.DependencyInjection.ServiceLifetime.Singleton;

private readonly global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> _getServicesLength;

/// <summary>
/// Constructor for DI, should not be used by consumer.
/// </summary>
public Mediator(global::System.IServiceProvider sp)
{
_sp = sp;
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp));

global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> fastGetLength = s => ((object[])s).Length;
global::System.Func<global::System.Collections.Generic.IEnumerable<object>, int> slowGetLength = s => s.Count();

var dummy = sp.GetServices<global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy>();
_getServicesLength = dummy.GetType() == typeof(global::Microsoft.Extensions.DependencyInjection.MediatorDependencyInjectionExtensions.Dummy[])
? fastGetLength : slowGetLength;
_containerMetadata = sp.GetRequiredService<global::Mediator.ContainerMetadata>();
_diCacheLazy = new FastLazyValue<DICache>(() => new DICache(_sp, _containerMetadata));
}

private struct FastLazyValue<T>
Expand Down Expand Up @@ -519,7 +531,7 @@ private readonly struct DICache

public readonly global::Mediator.ForeachAwaitPublisher InternalNotificationPublisherImpl;

public DICache(global::System.IServiceProvider sp)
public DICache(global::System.IServiceProvider sp, global::Mediator.ContainerMetadata containerMetadata)
{
_sp = sp;

Expand Down
Loading

0 comments on commit ae39563

Please sign in to comment.