-
-
Notifications
You must be signed in to change notification settings - Fork 746
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add incremental generator (#1864)
- Loading branch information
1 parent
48d1256
commit 26cfb28
Showing
18 changed files
with
1,314 additions
and
744 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
using System.Collections; | ||
|
||
namespace Refit.Generator; | ||
|
||
internal static class ImmutableEquatableArray | ||
{ | ||
public static ImmutableEquatableArray<T> Empty<T>() | ||
where T : IEquatable<T> => ImmutableEquatableArray<T>.Empty; | ||
|
||
public static ImmutableEquatableArray<T> ToImmutableEquatableArray<T>( | ||
this IEnumerable<T>? values | ||
) | ||
where T : IEquatable<T> => values == null ? Empty<T>() : new(values); | ||
} | ||
|
||
/// <summary> | ||
/// Provides an immutable list implementation which implements sequence equality. | ||
/// </summary> | ||
internal sealed class ImmutableEquatableArray<T> | ||
: IEquatable<ImmutableEquatableArray<T>>, | ||
IReadOnlyList<T> | ||
where T : IEquatable<T> | ||
{ | ||
public static ImmutableEquatableArray<T> Empty { get; } = new(Array.Empty<T>()); | ||
|
||
private readonly T[] _values; | ||
public T this[int index] => _values[index]; | ||
public int Count => _values.Length; | ||
|
||
public ImmutableEquatableArray(T[] values) => _values = values; | ||
|
||
public ImmutableEquatableArray(IEnumerable<T> values) => _values = values.ToArray(); | ||
|
||
public T[] AsArray() => _values; | ||
|
||
public bool Equals(ImmutableEquatableArray<T>? other) => | ||
other != null && ((ReadOnlySpan<T>)_values).SequenceEqual(other._values); | ||
|
||
public override bool Equals(object? obj) => | ||
obj is ImmutableEquatableArray<T> other && Equals(other); | ||
|
||
public override int GetHashCode() | ||
{ | ||
var hash = 0; | ||
foreach (T value in _values) | ||
{ | ||
hash = Combine(hash, value.GetHashCode()); | ||
} | ||
|
||
static int Combine(int h1, int h2) | ||
{ | ||
// RyuJIT optimizes this to use the ROL instruction | ||
// Related GitHub pull request: https://github.com/dotnet/coreclr/pull/1830 | ||
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27); | ||
return ((int)rol5 + h1) ^ h2; | ||
} | ||
|
||
return hash; | ||
} | ||
|
||
public Enumerator GetEnumerator() => new(_values); | ||
|
||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => ((IEnumerable<T>)_values).GetEnumerator(); | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator(); | ||
|
||
public struct Enumerator | ||
{ | ||
private readonly T[] _values; | ||
private int _index; | ||
|
||
internal Enumerator(T[] values) | ||
{ | ||
_values = values; | ||
_index = -1; | ||
} | ||
|
||
public bool MoveNext() | ||
{ | ||
var newIndex = _index + 1; | ||
|
||
if ((uint)newIndex < (uint)_values.Length) | ||
{ | ||
_index = newIndex; | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public readonly T Current => _values[_index]; | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
InterfaceStubGenerator.Shared/IncrementalValuesProviderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#if ROSLYN_4 | ||
using System.Text; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Text; | ||
|
||
namespace Refit.Generator; | ||
|
||
internal static class IncrementalValuesProviderExtensions | ||
{ | ||
/// <summary> | ||
/// Registers an output node into an <see cref="IncrementalGeneratorInitializationContext"/> to output a diagnostic. | ||
/// </summary> | ||
/// <param name="context">The input <see cref="IncrementalGeneratorInitializationContext"/> instance.</param> | ||
/// <param name="diagnostic">The input <see cref="IncrementalValuesProvider{TValues}"/> sequence of diagnostics.</param> | ||
public static void ReportDiagnostics( | ||
this IncrementalGeneratorInitializationContext context, | ||
IncrementalValuesProvider<Diagnostic> diagnostic | ||
) | ||
{ | ||
context.RegisterSourceOutput( | ||
diagnostic, | ||
static (context, diagnostic) => context.ReportDiagnostic(diagnostic) | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Registers an output node into an <see cref="IncrementalGeneratorInitializationContext"/> to output diagnostics. | ||
/// </summary> | ||
/// <param name="context">The input <see cref="IncrementalGeneratorInitializationContext"/> instance.</param> | ||
/// <param name="diagnostics">The input <see cref="IncrementalValuesProvider{TValues}"/> sequence of diagnostics.</param> | ||
public static void ReportDiagnostics( | ||
this IncrementalGeneratorInitializationContext context, | ||
IncrementalValueProvider<ImmutableEquatableArray<Diagnostic>> diagnostics | ||
) | ||
{ | ||
context.RegisterSourceOutput( | ||
diagnostics, | ||
static (context, diagnostics) => | ||
{ | ||
foreach (var diagnostic in diagnostics) | ||
{ | ||
context.ReportDiagnostic(diagnostic); | ||
} | ||
} | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Registers an implementation source output for the provided mappers. | ||
/// </summary> | ||
/// <param name="context">The context, on which the output is registered.</param> | ||
/// <param name="model">The interfaces stubs.</param> | ||
public static void EmitSource( | ||
this IncrementalGeneratorInitializationContext context, | ||
IncrementalValuesProvider<InterfaceModel> model | ||
) | ||
{ | ||
context.RegisterImplementationSourceOutput( | ||
model, | ||
static (spc, model) => | ||
{ | ||
var mapperText = Emitter.EmitInterface(model); | ||
spc.AddSource(model.FileName, SourceText.From(mapperText, Encoding.UTF8)); | ||
} | ||
); | ||
} | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.