Skip to content

Commit

Permalink
Use RegEx source generators on .NET 7 or later (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
mburumaxwell authored Jun 6, 2024
1 parent 206fe1a commit bc1172e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 14 deletions.
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
</PropertyGroup>

<PropertyGroup>
<WarningsAsErrors>$(WarningsAsErrors),SYSLIB1045</WarningsAsErrors>
<WarningsAsErrors>$(WarningsAsErrors),IL2026,IL2060,IL2091,IL2095,IL3050</WarningsAsErrors>
</PropertyGroup>

Expand Down
43 changes: 36 additions & 7 deletions src/Tingle.EventBus/DependencyInjection/EventBusNamingOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@ namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Specifies options for naming behaviour and requirements.
/// </summary>
public class EventBusNamingOptions
public partial class EventBusNamingOptions
{
private static readonly Regex trimPattern = new("(Event|Consumer|EventConsumer)$", RegexOptions.Compiled);
private static readonly Regex namePattern = new("(?<=[a-z0-9])[A-Z]", RegexOptions.Compiled);
private static readonly Regex replacePatternKebabCase = new("[^a-zA-Z0-9-]", RegexOptions.Compiled);
private static readonly Regex replacePatternSnakeCase = new("[^a-zA-Z0-9_]", RegexOptions.Compiled);
private static readonly Regex replacePatternDotCase = new("[^a-zA-Z0-9\\.]", RegexOptions.Compiled);
private static readonly Regex replacePatternDefault = new("[^a-zA-Z0-9-_\\.]", RegexOptions.Compiled);
private const string TrimPattern = "(Event|Consumer|EventConsumer)$";
private const string NamePattern = "(?<=[a-z0-9])[A-Z]";
private const string ReplacePatternKebabCase = "[^a-zA-Z0-9-]";
private const string ReplacePatternSnakeCase = "[^a-zA-Z0-9_]";
private const string ReplacePatternDotCase = "[^a-zA-Z0-9\\.]";
private const string ReplacePatternDefault = "[^a-zA-Z0-9-_\\.]";

private static readonly Regex trimPattern = GetTrimPattern();
private static readonly Regex namePattern = GetNamePattern();
private static readonly Regex replacePatternKebabCase = GetReplacePatternKebabCase();
private static readonly Regex replacePatternSnakeCase = GetReplacePatternSnakeCase();
private static readonly Regex replacePatternDotCase = GetReplacePatternDotCase();
private static readonly Regex replacePatternDefault = GetReplacePatternDefault();

/// <summary>
/// The scope to use for queues and subscriptions.
Expand Down Expand Up @@ -136,4 +143,26 @@ public string Join(params string[] values)
_ => throw new InvalidOperationException($"'{nameof(NamingConvention)}.{Convention}' does not support joining"),
}).ToLowerInvariant();
}

#if NET7_0_OR_GREATER
[GeneratedRegex(TrimPattern, RegexOptions.Compiled)]
private static partial Regex GetTrimPattern();
[GeneratedRegex(NamePattern, RegexOptions.Compiled)]
private static partial Regex GetNamePattern();
[GeneratedRegex(ReplacePatternKebabCase, RegexOptions.Compiled)]
private static partial Regex GetReplacePatternKebabCase();
[GeneratedRegex(ReplacePatternSnakeCase, RegexOptions.Compiled)]
private static partial Regex GetReplacePatternSnakeCase();
[GeneratedRegex(ReplacePatternDotCase, RegexOptions.Compiled)]
private static partial Regex GetReplacePatternDotCase();
[GeneratedRegex(ReplacePatternDefault, RegexOptions.Compiled)]
private static partial Regex GetReplacePatternDefault();
#else
private static Regex GetTrimPattern() => new(TrimPattern, RegexOptions.Compiled);
private static Regex GetNamePattern() => new(NamePattern, RegexOptions.Compiled);
private static Regex GetReplacePatternKebabCase() => new(ReplacePatternKebabCase, RegexOptions.Compiled);
private static Regex GetReplacePatternSnakeCase() => new(ReplacePatternSnakeCase, RegexOptions.Compiled);
private static Regex GetReplacePatternDotCase() => new(ReplacePatternDotCase, RegexOptions.Compiled);
private static Regex GetReplacePatternDefault() => new(ReplacePatternDefault, RegexOptions.Compiled);
#endif
}
13 changes: 11 additions & 2 deletions src/Tingle.EventBus/Serialization/AbstractEventSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ namespace Tingle.EventBus.Serialization;
/// <summary>
/// Abstract implementation for an event serializer.
/// </summary>
public abstract class AbstractEventSerializer : IEventSerializer
public abstract partial class AbstractEventSerializer : IEventSerializer
{
private const string TrimPattern = "(Serializer|EventSerializer)$";

///
protected static readonly IList<string> JsonContentTypes = new[] { "application/json", "text/json", };

private static readonly Regex trimPattern = new("(Serializer|EventSerializer)$", RegexOptions.Compiled);
private static readonly Regex trimPattern = GetTrimPattern();

/// <summary>
///
Expand Down Expand Up @@ -147,4 +149,11 @@ protected abstract Task SerializeEnvelopeAsync<T>(Stream stream,
EventEnvelope<T> envelope,
CancellationToken cancellationToken = default)
where T : class;

#if NET7_0_OR_GREATER
[GeneratedRegex(TrimPattern, RegexOptions.Compiled)]
private static partial Regex GetTrimPattern();
#else
private static Regex GetTrimPattern() => new(TrimPattern, RegexOptions.Compiled);
#endif
}
15 changes: 12 additions & 3 deletions src/Tingle.EventBus/Transports/EventBusTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ namespace Tingle.EventBus.Transports;
/// Abstract implementation for an event bus transport.
/// </summary>
/// <typeparam name="TOptions">The type used for configuring options of the transport</typeparam>
public abstract class EventBusTransport<TOptions> : IEventBusTransport where TOptions : EventBusTransportOptions, new()
public abstract partial class EventBusTransport<TOptions> : IEventBusTransport where TOptions : EventBusTransportOptions, new()
{
private static readonly Regex CategoryNamePattern = new(@"Transport$", RegexOptions.Compiled);
private const string CategoryNamePattern = "Transport$";

private static readonly Regex categoryNamePattern = GetCategoryNamePattern();
private readonly IServiceScopeFactory scopeFactory;
private readonly IOptionsMonitor<TOptions> optionsMonitor;

Expand All @@ -41,7 +43,7 @@ public EventBusTransport(IServiceScopeFactory scopeFactory,

// Create a well-scoped logger
var categoryName = $"{LogCategoryNames.Transports}.{GetType().Name}";
categoryName = CategoryNamePattern.Replace(categoryName, string.Empty); // remove trailing "Transport"
categoryName = categoryNamePattern.Replace(categoryName, string.Empty); // remove trailing "Transport"
Logger = loggerFactory?.CreateLogger(categoryName) ?? throw new ArgumentNullException(nameof(loggerFactory));
}

Expand Down Expand Up @@ -382,5 +384,12 @@ protected async Task<EventConsumeResult> ConsumeAsync(IServiceScope scope,
return Logger.BeginScope(state);
}

#if NET7_0_OR_GREATER
[GeneratedRegex(CategoryNamePattern, RegexOptions.Compiled)]
private static partial Regex GetCategoryNamePattern();
#else
private static Regex GetCategoryNamePattern() => new(CategoryNamePattern, RegexOptions.Compiled);
#endif

#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ namespace Microsoft.Extensions.DependencyInjection;
/// <param name="configurationProvider">An <see cref="IEventBusConfigurationProvider"/> instance.</param>
/// <param name="configurators">A list of <see cref="IEventBusConfigurator"/> to use when configuring options.</param>
/// <param name="busOptionsAccessor">An <see cref="IOptions{TOptions}"/> for bus configuration.</param>
public abstract class EventBusTransportConfigureOptions<TOptions>(IEventBusConfigurationProvider configurationProvider,
public abstract partial class EventBusTransportConfigureOptions<TOptions>(IEventBusConfigurationProvider configurationProvider,
IEnumerable<IEventBusConfigurator> configurators,
IOptions<EventBusOptions> busOptionsAccessor) : IConfigureNamedOptions<TOptions>,
IPostConfigureOptions<TOptions>,
IValidateOptions<TOptions>
where TOptions : EventBusTransportOptions
{
private const string ReplacePatternSafeEnv = "[^a-zA-Z0-9_]";

// Some hosts do not allow certain characters for ENV vars but we know they all support alphanumeric and underscore
// For example, Azure Container Instances does not allow hyphens in ENV vars while Azure Container Apps does
private static readonly Regex replacePatternSafeEnv = new("[^a-zA-Z0-9_]", RegexOptions.Compiled);
private static readonly Regex replacePatternSafeEnv = GetReplacePatternSafeEnv();

private readonly IEventBusConfigurationProvider configurationProvider = configurationProvider ?? throw new ArgumentNullException(nameof(configurationProvider));
private readonly IEnumerable<IEventBusConfigurator> configurators = configurators ?? throw new ArgumentNullException(nameof(configurators));
Expand Down Expand Up @@ -98,4 +100,11 @@ public virtual ValidateOptionsResult Validate(string? name, TOptions options)

return ValidateOptionsResult.Success;
}

#if NET7_0_OR_GREATER
[GeneratedRegex(ReplacePatternSafeEnv, RegexOptions.Compiled)]
private static partial Regex GetReplacePatternSafeEnv();
#else
private static Regex GetReplacePatternSafeEnv() => new(ReplacePatternSafeEnv, RegexOptions.Compiled);
#endif
}

0 comments on commit bc1172e

Please sign in to comment.