Skip to content

Commit

Permalink
Src gen: More use of raw string literals
Browse files Browse the repository at this point in the history
  • Loading branch information
sveinungf committed Feb 18, 2024
1 parent b92ca5f commit 8a7b8d6
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 142 deletions.
23 changes: 0 additions & 23 deletions SpreadCheetah.SourceGenerator/Helpers/StringBuilderExtensions.cs

This file was deleted.

245 changes: 126 additions & 119 deletions SpreadCheetah.SourceGenerator/WorksheetRowGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,36 +149,40 @@ private static void Execute(ContextClass? contextClass, SourceProductionContext

private static void GenerateHeader(StringBuilder sb)
{
sb.AppendLine("// <auto-generated />");
sb.AppendLine("#nullable enable");
sb.AppendLine("using SpreadCheetah;");
sb.AppendLine("using SpreadCheetah.SourceGeneration;");
sb.AppendLine("using System;");
sb.AppendLine("using System.Buffers;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine("using System.Threading;");
sb.AppendLine("using System.Threading.Tasks;");
sb.AppendLine();
sb.AppendLine("""
// <auto-generated />
#nullable enable
using SpreadCheetah;
using SpreadCheetah.SourceGeneration;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
""");
}

private static void GenerateCode(StringBuilder sb, ContextClass contextClass, SourceProductionContext context)
{
GenerateHeader(sb);

if (contextClass.Namespace is { } ns)
sb.AppendLine($"namespace {ns}");
sb.Append("namespace ").AppendLine(ns);

var accessibility = SyntaxFacts.GetText(contextClass.DeclaredAccessibility);

sb.AppendLine("{");
sb.AppendLine($" {accessibility} partial class {contextClass.Name}");
sb.AppendLine(" {");
sb.AppendLine($" private static {contextClass.Name}? _default;");
sb.AppendLine($" public static {contextClass.Name} Default => _default ??= new {contextClass.Name}();");
sb.AppendLine();
sb.AppendLine($" public {contextClass.Name}()");
sb.AppendLine(" {");
sb.AppendLine(" }");
sb.AppendLine($$"""
{
{{accessibility}} partial class {{contextClass.Name}}
{
private static {{contextClass.Name}}? _default;
public static {{contextClass.Name}} Default => _default ??= new {{contextClass.Name}}();
public {{contextClass.Name}}()
{
}
""");

var rowTypeNames = new HashSet<string>(StringComparer.Ordinal);

Expand All @@ -193,19 +197,21 @@ private static void GenerateCode(StringBuilder sb, ContextClass contextClass, So
++typeIndex;
}

sb.AppendLine(" }");
sb.AppendLine("}");
sb.AppendLine("""
}
}
""");
}

private static void GenerateCodeForType(StringBuilder sb, int typeIndex, RowType rowType,
ContextClass contextClass, SourceProductionContext context)
{
ReportDiagnostics(rowType, rowType.WorksheetRowAttributeLocation, contextClass.Options, context);

sb.AppendLine().AppendLine(FormattableString.Invariant($$"""
private WorksheetRowTypeInfo<{{rowType.FullName}}>? _{{rowType.Name}};
public WorksheetRowTypeInfo<{{rowType.FullName}}> {{rowType.Name}} => _{{rowType.Name}}
"""));
sb.AppendLine().AppendLine($$"""
private WorksheetRowTypeInfo<{{rowType.FullName}}>? _{{rowType.Name}};
public WorksheetRowTypeInfo<{{rowType.FullName}}> {{rowType.Name}} => _{{rowType.Name}}
""");

if (rowType.Properties.Count == 0)
{
Expand All @@ -221,12 +227,12 @@ private static void GenerateCodeForType(StringBuilder sb, int typeIndex, RowType
"""));

GenerateAddHeaderRow(sb, typeIndex, rowType.Properties);
GenerateAddAsRow(sb, 2, rowType);
GenerateAddRangeAsRows(sb, 2, rowType);
GenerateAddAsRowInternal(sb, 2, rowType.FullName, rowType.Properties);
GenerateAddRangeAsRowsInternal(sb, rowType, rowType.Properties);
GenerateAddEnumerableAsRows(sb, 2, rowType);
GenerateAddCellsAsRow(sb, 2, rowType, rowType.Properties);
GenerateAddAsRow(sb, rowType);
GenerateAddRangeAsRows(sb, rowType);
GenerateAddAsRowInternal(sb, rowType);
GenerateAddRangeAsRowsInternal(sb, rowType);
GenerateAddEnumerableAsRows(sb, rowType);
GenerateAddCellsAsRow(sb, rowType);
}

private static void ReportDiagnostics(RowType rowType, LocationInfo? locationInfo, GeneratorOptions? options, SourceProductionContext context)
Expand Down Expand Up @@ -258,12 +264,12 @@ private static void GenerateAddHeaderRow(StringBuilder sb, int typeIndex, IReadO
Debug.Assert(properties.Count > 0);

sb.AppendLine().AppendLine(FormattableString.Invariant($$"""
private static async ValueTask AddHeaderRow{{typeIndex}}Async(SpreadCheetah.Spreadsheet spreadsheet, SpreadCheetah.Styling.StyleId? styleId, CancellationToken token)
{
var cells = ArrayPool<StyledCell>.Shared.Rent({{properties.Count}});
try
private static async ValueTask AddHeaderRow{{typeIndex}}Async(SpreadCheetah.Spreadsheet spreadsheet, SpreadCheetah.Styling.StyleId? styleId, CancellationToken token)
{
"""));
var cells = ArrayPool<StyledCell>.Shared.Rent({{properties.Count}});
try
{
"""));

foreach (var (i, property) in properties.Index())
{
Expand All @@ -273,82 +279,85 @@ private static void GenerateAddHeaderRow(StringBuilder sb, int typeIndex, IReadO
}

sb.AppendLine($$"""
await spreadsheet.AddRowAsync(cells.AsMemory(0, {{properties.Count}}), token).ConfigureAwait(false);
}
finally
{
ArrayPool<StyledCell>.Shared.Return(cells, true);
await spreadsheet.AddRowAsync(cells.AsMemory(0, {{properties.Count}}), token).ConfigureAwait(false);
}
finally
{
ArrayPool<StyledCell>.Shared.Return(cells, true);
}
}
}
""");
""");
}

private static void GenerateAddAsRow(StringBuilder sb, int indent, RowType rowType)
private static void GenerateAddAsRow(StringBuilder sb, RowType rowType)
{
sb.AppendLine()
.AppendIndentation(indent)
.Append("private static ValueTask AddAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet, ")
.Append(rowType.FullNameWithNullableAnnotation)
.AppendLine(" obj, CancellationToken token)");
sb.AppendLine($$"""
sb.AppendLine(indent, "{");
sb.AppendLine(indent, " if (spreadsheet is null)");
sb.AppendLine(indent, " throw new ArgumentNullException(nameof(spreadsheet));");
private static ValueTask AddAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet, {{rowType.FullNameWithNullableAnnotation}} obj, CancellationToken token)
{
if (spreadsheet is null)
throw new ArgumentNullException(nameof(spreadsheet));
""");

if (rowType.IsReferenceType)
{
sb.AppendLine(indent + 1, "if (obj is null)");
sb.AppendLine(indent + 1, " return spreadsheet.AddRowAsync(ReadOnlyMemory<DataCell>.Empty, token);");
sb.AppendLine("""
if (obj is null)
return spreadsheet.AddRowAsync(ReadOnlyMemory<DataCell>.Empty, token);
""");
}

sb.AppendLine(indent, " return AddAsRowInternalAsync(spreadsheet, obj, token);");
sb.AppendLine(indent, "}");
sb.AppendLine("""
return AddAsRowInternalAsync(spreadsheet, obj, token);
}
""");
}

private static void GenerateAddAsRowInternal(StringBuilder sb, int indent, string rowTypeFullname, IReadOnlyCollection<RowTypeProperty> properties)
private static void GenerateAddAsRowInternal(StringBuilder sb, RowType rowType)
{
var properties = rowType.Properties;
Debug.Assert(properties.Count > 0);

sb.AppendLine();
sb.AppendLine(indent, $"private static async ValueTask AddAsRowInternalAsync(SpreadCheetah.Spreadsheet spreadsheet, {rowTypeFullname} obj, CancellationToken token)");
sb.AppendLine(indent, "{");
sb.AppendLine(indent, $" var cells = ArrayPool<DataCell>.Shared.Rent({properties.Count});");
sb.AppendLine(indent, " try");
sb.AppendLine(indent, " {");
sb.AppendLine(indent, " await AddCellsAsRowAsync(spreadsheet, obj, cells, token).ConfigureAwait(false);");
sb.AppendLine(indent, " }");
sb.AppendLine(indent, " finally");
sb.AppendLine(indent, " {");
sb.AppendLine(indent, " ArrayPool<DataCell>.Shared.Return(cells, true);");
sb.AppendLine(indent, " }");
sb.AppendLine(indent, "}");
sb.AppendLine($$"""
private static async ValueTask AddAsRowInternalAsync(SpreadCheetah.Spreadsheet spreadsheet, {{rowType.FullName}} obj, CancellationToken token)
{
var cells = ArrayPool<DataCell>.Shared.Rent({{properties.Count}});
try
{
await AddCellsAsRowAsync(spreadsheet, obj, cells, token).ConfigureAwait(false);
}
finally
{
ArrayPool<DataCell>.Shared.Return(cells, true);
}
}
""");
}

private static void GenerateAddRangeAsRows(StringBuilder sb, int indent, RowType rowType)
private static void GenerateAddRangeAsRows(StringBuilder sb, RowType rowType)
{
sb.AppendLine()
.AppendIndentation(indent)
.Append("private static ValueTask AddRangeAsRowsAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<")
.Append(rowType.FullNameWithNullableAnnotation)
.AppendLine("> objs, CancellationToken token)");

sb.AppendLine(indent, "{");
sb.AppendLine(indent, " if (spreadsheet is null)");
sb.AppendLine(indent, " throw new ArgumentNullException(nameof(spreadsheet));");
sb.AppendLine(indent, " if (objs is null)");
sb.AppendLine(indent, " throw new ArgumentNullException(nameof(objs));");
sb.AppendLine(indent, " return AddRangeAsRowsInternalAsync(spreadsheet, objs, token);");
sb.AppendLine(indent, "}");
sb.AppendLine($$"""
private static ValueTask AddRangeAsRowsAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<{{rowType.FullNameWithNullableAnnotation}}> objs, CancellationToken token)
{
if (spreadsheet is null)
throw new ArgumentNullException(nameof(spreadsheet));
if (objs is null)
throw new ArgumentNullException(nameof(objs));
return AddRangeAsRowsInternalAsync(spreadsheet, objs, token);
}
""");
}

private static void GenerateAddRangeAsRowsInternal(StringBuilder sb, RowType rowType, IReadOnlyCollection<RowTypeProperty> properties)
private static void GenerateAddRangeAsRowsInternal(StringBuilder sb, RowType rowType)
{
var properties = rowType.Properties;
Debug.Assert(properties.Count > 0);

var typeString = rowType.FullNameWithNullableAnnotation;
sb.Append($$"""
private static async ValueTask AddRangeAsRowsInternalAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<{{typeString}}> objs, CancellationToken token)
private static async ValueTask AddRangeAsRowsInternalAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<{{rowType.FullNameWithNullableAnnotation}}> objs, CancellationToken token)
{
var cells = ArrayPool<DataCell>.Shared.Rent({{properties.Count}});
try
Expand All @@ -364,52 +373,50 @@ private static async ValueTask AddRangeAsRowsInternalAsync(SpreadCheetah.Spreads
""");
}

private static void GenerateAddEnumerableAsRows(StringBuilder sb, int indent, RowType rowType)
private static void GenerateAddEnumerableAsRows(StringBuilder sb, RowType rowType)
{
sb.AppendLine()
.AppendIndentation(indent)
.Append("private static async ValueTask AddEnumerableAsRowsAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<")
.Append(rowType.FullNameWithNullableAnnotation)
.AppendLine("> objs, DataCell[] cells, CancellationToken token)");

sb.AppendLine(indent, "{");
sb.AppendLine(indent, " foreach (var obj in objs)");
sb.AppendLine(indent, " {");
sb.AppendLine(indent, " await AddCellsAsRowAsync(spreadsheet, obj, cells, token).ConfigureAwait(false);");
sb.AppendLine(indent, " }");
sb.AppendLine(indent, "}");
sb.AppendLine($$"""
private static async ValueTask AddEnumerableAsRowsAsync(SpreadCheetah.Spreadsheet spreadsheet, IEnumerable<{{rowType.FullNameWithNullableAnnotation}}> objs, DataCell[] cells, CancellationToken token)
{
foreach (var obj in objs)
{
await AddCellsAsRowAsync(spreadsheet, obj, cells, token).ConfigureAwait(false);
}
}
""");
}

private static void GenerateAddCellsAsRow(StringBuilder sb, int indent, RowType rowType, IReadOnlyCollection<RowTypeProperty> properties)
private static void GenerateAddCellsAsRow(StringBuilder sb, RowType rowType)
{
var properties = rowType.Properties;
Debug.Assert(properties.Count > 0);

sb.AppendLine()
.AppendIndentation(indent)
.Append("private static ValueTask AddCellsAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet, ")
.Append(rowType.FullNameWithNullableAnnotation)
.AppendLine(" obj, DataCell[] cells, CancellationToken token)");
sb.AppendLine($$"""
sb.AppendLine(indent, "{");
private static ValueTask AddCellsAsRowAsync(SpreadCheetah.Spreadsheet spreadsheet, {{rowType.FullNameWithNullableAnnotation}} obj, DataCell[] cells, CancellationToken token)
{
""");

if (rowType.IsReferenceType)
{
sb.AppendLine(indent, " if (obj is null)");
sb.AppendLine(indent, " return spreadsheet.AddRowAsync(ReadOnlyMemory<DataCell>.Empty, token);");
sb.AppendLine();
sb.AppendLine("""
if (obj is null)
return spreadsheet.AddRowAsync(ReadOnlyMemory<DataCell>.Empty, token);
""");
}

foreach (var (i, property) in properties.Index())
{
sb.AppendIndentation(indent + 1)
.Append("cells[")
.Append(i)
.Append("] = new DataCell(obj.")
.Append(property.Name)
.AppendLine(");");
sb.AppendLine(FormattableString.Invariant($$"""
cells[{{i}}] = new DataCell(obj.{{property.Name}});
"""));
}

sb.AppendLine(indent, $" return spreadsheet.AddRowAsync(cells.AsMemory(0, {properties.Count}), token);");
sb.AppendLine(indent, "}");
sb.AppendLine($$"""
return spreadsheet.AddRowAsync(cells.AsMemory(0, {{properties.Count}}), token);
}
""");
}
}

0 comments on commit 8a7b8d6

Please sign in to comment.