Skip to content

Commit

Permalink
Make the EventSource generator incremental et.al. (dotnet#64579)
Browse files Browse the repository at this point in the history
  • Loading branch information
teo-tsirpanis committed Mar 18, 2022
1 parent a19d9fa commit 4d39501
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 280 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,97 +12,86 @@ namespace Generators
{
public partial class EventSourceGenerator
{
private sealed class Emitter
{
private readonly StringBuilder _builder = new StringBuilder(1024);
private readonly GeneratorExecutionContext _context;

public Emitter(GeneratorExecutionContext context) => _context = context;

public void Emit(EventSourceClass[] eventSources, CancellationToken cancellationToken)
{
foreach (EventSourceClass? ec in eventSources)
{
if (cancellationToken.IsCancellationRequested)
{
// stop any additional work
break;
}
/// <summary>Code for a [GeneratedCode] attribute to put on the top-level generated members.</summary>
private static readonly string s_generatedCodeAttribute = $"[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{typeof(EventSourceGenerator).Assembly.GetName().Name}\", \"{typeof(EventSourceGenerator).Assembly.GetName().Version}\")]";

_builder.AppendLine("using System;");
GenType(ec);
private static void EmitSourceFile(SourceProductionContext context, EventSourceClass ec)
{
StringBuilder sb = new StringBuilder(1024);

_context.AddSource($"{ec.ClassName}.g.cs", SourceText.From(_builder.ToString(), Encoding.UTF8));
sb.AppendLine(@"// <auto-generated/>");
sb.AppendLine();
sb.AppendLine("using System;");
GenType(ec, sb);

_builder.Clear();
}
}
context.AddSource($"{ec.ClassName}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}

private void GenType(EventSourceClass ec)
private static void GenType(EventSourceClass ec, StringBuilder sb)
{
if (!string.IsNullOrWhiteSpace(ec.Namespace))
{
if (!string.IsNullOrWhiteSpace(ec.Namespace))
{
_builder.AppendLine($@"
sb.AppendLine($@"
namespace {ec.Namespace}
{{");
}
}

_builder.AppendLine($@"
sb.AppendLine($@"
{s_generatedCodeAttribute}
partial class {ec.ClassName}
{{");
GenerateConstructor(ec);
GenerateConstructor(ec, sb);

GenerateProviderMetadata(ec.SourceName);
GenerateProviderMetadata(ec.SourceName, sb);

_builder.AppendLine($@"
sb.AppendLine($@"
}}");

if (!string.IsNullOrWhiteSpace(ec.Namespace))
{
_builder.AppendLine($@"
if (!string.IsNullOrWhiteSpace(ec.Namespace))
{
sb.AppendLine($@"
}}");
}
}
}

private void GenerateConstructor(EventSourceClass ec)
{
_builder.AppendLine($@"
private static void GenerateConstructor(EventSourceClass ec, StringBuilder sb)
{
sb.AppendLine($@"
private {ec.ClassName}() : base(new Guid({ec.Guid.ToString("x").Replace("{", "").Replace("}", "")}), ""{ec.SourceName}"") {{ }}");
}
}

private void GenerateProviderMetadata(string sourceName)
{
_builder.Append(@"
private static void GenerateProviderMetadata(string sourceName, StringBuilder sb)
{
sb.Append(@"
private protected override ReadOnlySpan<byte> ProviderMetadata => new byte[] { ");

byte[] metadataBytes = MetadataForString(sourceName);
foreach (byte b in metadataBytes)
{
_builder.Append($"0x{b:x}, ");
}

_builder.AppendLine(@"};");
}

// From System.Private.CoreLib
private static byte[] MetadataForString(string name)
byte[] metadataBytes = MetadataForString(sourceName);
foreach (byte b in metadataBytes)
{
CheckName(name);
int metadataSize = Encoding.UTF8.GetByteCount(name) + 3;
byte[]? metadata = new byte[metadataSize];
ushort totalSize = checked((ushort)(metadataSize));
metadata[0] = unchecked((byte)totalSize);
metadata[1] = unchecked((byte)(totalSize >> 8));
Encoding.UTF8.GetBytes(name, 0, name.Length, metadata, 2);
return metadata;
sb.Append($"0x{b:x}, ");
}

private static void CheckName(string? name)
sb.AppendLine(@"};");
}

// From System.Private.CoreLib
private static byte[] MetadataForString(string name)
{
CheckName(name);
int metadataSize = Encoding.UTF8.GetByteCount(name) + 3;
byte[]? metadata = new byte[metadataSize];
ushort totalSize = checked((ushort)(metadataSize));
metadata[0] = unchecked((byte)totalSize);
metadata[1] = unchecked((byte)(totalSize >> 8));
Encoding.UTF8.GetBytes(name, 0, name.Length, metadata, 2);
return metadata;
}

private static void CheckName(string? name)
{
if (name != null && 0 <= name.IndexOf('\0'))
{
if (name != null && 0 <= name.IndexOf('\0'))
{
throw new ArgumentOutOfRangeException(nameof(name));
}
throw new ArgumentOutOfRangeException(nameof(name));
}
}
}
Expand Down
Loading

0 comments on commit 4d39501

Please sign in to comment.