Skip to content

Commit 0ce3c92

Browse files
authored
Prepare for C# Source Generator (MessagePack-CSharp#1082)
1 parent 36994ea commit 0ce3c92

File tree

1 file changed

+132
-109
lines changed

1 file changed

+132
-109
lines changed

src/MessagePack.GeneratorCore/CodeGenerator.cs

Lines changed: 132 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -73,127 +73,22 @@ public async Task GenerateFileAsync(
7373
if (Path.GetExtension(output) == ".cs")
7474
{
7575
// SingleFile Output
76-
var objectFormatterTemplates = objectInfo
77-
.GroupBy(x => (x.Namespace, x.IsStringKey))
78-
.Select(x =>
79-
{
80-
var (nameSpace, isStringKey) = x.Key;
81-
var objectSerializationInfos = x.ToArray();
82-
var template = isStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate)new FormatterTemplate();
83-
84-
template.Namespace = namespaceDot + "Formatters" + (nameSpace is null ? string.Empty : "." + nameSpace);
85-
template.ObjectSerializationInfos = objectSerializationInfos;
86-
87-
return template;
88-
})
89-
.ToArray();
90-
91-
var enumFormatterTemplates = enumInfo
92-
.GroupBy(x => x.Namespace)
93-
.Select(x => new EnumTemplate()
94-
{
95-
Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
96-
EnumSerializationInfos = x.ToArray(),
97-
})
98-
.ToArray();
99-
100-
var unionFormatterTemplates = unionInfo
101-
.GroupBy(x => x.Namespace)
102-
.Select(x => new UnionTemplate()
103-
{
104-
Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
105-
UnionSerializationInfos = x.ToArray(),
106-
})
107-
.ToArray();
108-
109-
var resolverTemplate = new ResolverTemplate()
110-
{
111-
Namespace = namespaceDot + "Resolvers",
112-
FormatterNamespace = namespaceDot + "Formatters",
113-
ResolverName = resolverName,
114-
RegisterInfos = genericInfo.Where(x => !x.IsOpenGenericType).Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
115-
};
116-
117-
var sb = new StringBuilder();
118-
sb.AppendLine(resolverTemplate.TransformText());
119-
sb.AppendLine();
120-
foreach (var item in enumFormatterTemplates)
121-
{
122-
var text = item.TransformText();
123-
sb.AppendLine(text);
124-
}
125-
126-
sb.AppendLine();
127-
foreach (var item in unionFormatterTemplates)
128-
{
129-
var text = item.TransformText();
130-
sb.AppendLine(text);
131-
}
132-
133-
sb.AppendLine();
134-
foreach (var item in objectFormatterTemplates)
135-
{
136-
var text = item.TransformText();
137-
sb.AppendLine(text);
138-
}
139-
76+
var fullGeneratedProgramText = GenerateSingleFileSync(resolverName, namespaceDot, objectInfo, enumInfo, unionInfo, genericInfo);
14077
if (multioutSymbol == string.Empty)
14178
{
142-
await OutputAsync(output, sb.ToString(), cancellationToken);
79+
await OutputAsync(output, fullGeneratedProgramText, cancellationToken);
14380
}
14481
else
14582
{
14683
var fname = Path.GetFileNameWithoutExtension(output) + "." + MultiSymbolToSafeFilePath(multioutSymbol) + ".cs";
147-
var text = $"#if {multioutSymbol}" + Environment.NewLine + sb.ToString() + Environment.NewLine + "#endif";
84+
var text = $"#if {multioutSymbol}" + Environment.NewLine + fullGeneratedProgramText + Environment.NewLine + "#endif";
14885
await OutputAsync(Path.Combine(Path.GetDirectoryName(output), fname), text, cancellationToken);
14986
}
15087
}
15188
else
15289
{
15390
// Multiple File output
154-
foreach (var x in objectInfo)
155-
{
156-
var template = x.IsStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate)new FormatterTemplate();
157-
template.Namespace = namespaceDot + "Formatters" + (x.Namespace is null ? string.Empty : "." + x.Namespace);
158-
template.ObjectSerializationInfos = new[] { x };
159-
160-
var text = template.TransformText();
161-
await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
162-
}
163-
164-
foreach (var x in enumInfo)
165-
{
166-
var template = new EnumTemplate()
167-
{
168-
Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
169-
EnumSerializationInfos = new[] { x },
170-
};
171-
172-
var text = template.TransformText();
173-
await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
174-
}
175-
176-
foreach (var x in unionInfo)
177-
{
178-
var template = new UnionTemplate()
179-
{
180-
Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
181-
UnionSerializationInfos = new[] { x },
182-
};
183-
184-
var text = template.TransformText();
185-
await OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
186-
}
187-
188-
var resolverTemplate = new ResolverTemplate()
189-
{
190-
Namespace = namespaceDot + "Resolvers",
191-
FormatterNamespace = namespaceDot + "Formatters",
192-
ResolverName = resolverName,
193-
RegisterInfos = genericInfo.Where(x => !x.IsOpenGenericType).Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
194-
};
195-
196-
await OutputToDirAsync(output, resolverTemplate.Namespace, resolverTemplate.ResolverName, multioutSymbol, resolverTemplate.TransformText(), cancellationToken);
91+
await GenerateMultipleFileAsync(output, resolverName, objectInfo, enumInfo, unionInfo, namespaceDot, multioutSymbol, genericInfo);
19792
}
19893

19994
if (objectInfo.Length == 0 && enumInfo.Length == 0 && genericInfo.Length == 0 && unionInfo.Length == 0)
@@ -205,6 +100,134 @@ public async Task GenerateFileAsync(
205100
logger("Output Generation Complete:" + sw.Elapsed.ToString());
206101
}
207102

103+
/// <summary>
104+
/// Generates the specialized resolver and formatters for the types that require serialization in a given compilation.
105+
/// </summary>
106+
/// <param name="resolverName">The resolver name.</param>
107+
/// <param name="namespaceDot">The namespace for the generated type to be created in.</param>
108+
/// <param name="objectInfo">The ObjectSerializationInfo array which TypeCollector.Collect returns.</param>
109+
/// <param name="enumInfo">The EnumSerializationInfo array which TypeCollector.Collect returns.</param>
110+
/// <param name="unionInfo">The UnionSerializationInfo array which TypeCollector.Collect returns.</param>
111+
/// <param name="genericInfo">The GenericSerializationInfo array which TypeCollector.Collect returns.</param>
112+
public static string GenerateSingleFileSync(string resolverName, string namespaceDot, ObjectSerializationInfo[] objectInfo, EnumSerializationInfo[] enumInfo, UnionSerializationInfo[] unionInfo, GenericSerializationInfo[] genericInfo)
113+
{
114+
var objectFormatterTemplates = objectInfo
115+
.GroupBy(x => (x.Namespace, x.IsStringKey))
116+
.Select(x =>
117+
{
118+
var (nameSpace, isStringKey) = x.Key;
119+
var objectSerializationInfos = x.ToArray();
120+
var template = isStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate)new FormatterTemplate();
121+
122+
template.Namespace = namespaceDot + "Formatters" + (nameSpace is null ? string.Empty : "." + nameSpace);
123+
template.ObjectSerializationInfos = objectSerializationInfos;
124+
125+
return template;
126+
})
127+
.ToArray();
128+
129+
var enumFormatterTemplates = enumInfo
130+
.GroupBy(x => x.Namespace)
131+
.Select(x => new EnumTemplate()
132+
{
133+
Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
134+
EnumSerializationInfos = x.ToArray(),
135+
})
136+
.ToArray();
137+
138+
var unionFormatterTemplates = unionInfo
139+
.GroupBy(x => x.Namespace)
140+
.Select(x => new UnionTemplate()
141+
{
142+
Namespace = namespaceDot + "Formatters" + ((x.Key == null) ? string.Empty : "." + x.Key),
143+
UnionSerializationInfos = x.ToArray(),
144+
})
145+
.ToArray();
146+
147+
var resolverTemplate = new ResolverTemplate()
148+
{
149+
Namespace = namespaceDot + "Resolvers",
150+
FormatterNamespace = namespaceDot + "Formatters",
151+
ResolverName = resolverName,
152+
RegisterInfos = genericInfo.Where(x => !x.IsOpenGenericType).Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
153+
};
154+
155+
var sb = new StringBuilder();
156+
sb.AppendLine(resolverTemplate.TransformText());
157+
sb.AppendLine();
158+
foreach (var item in enumFormatterTemplates)
159+
{
160+
var text = item.TransformText();
161+
sb.AppendLine(text);
162+
}
163+
164+
sb.AppendLine();
165+
foreach (var item in unionFormatterTemplates)
166+
{
167+
var text = item.TransformText();
168+
sb.AppendLine(text);
169+
}
170+
171+
sb.AppendLine();
172+
foreach (var item in objectFormatterTemplates)
173+
{
174+
var text = item.TransformText();
175+
sb.AppendLine(text);
176+
}
177+
178+
return sb.ToString();
179+
}
180+
181+
private Task GenerateMultipleFileAsync(string output, string resolverName, ObjectSerializationInfo[] objectInfo, EnumSerializationInfo[] enumInfo, UnionSerializationInfo[] unionInfo, string namespaceDot, string multioutSymbol, GenericSerializationInfo[] genericInfo)
182+
{
183+
var waitingTasks = new Task[objectInfo.Length + enumInfo.Length + unionInfo.Length + 1];
184+
var waitingIndex = 0;
185+
foreach (var x in objectInfo)
186+
{
187+
var template = x.IsStringKey ? new StringKeyFormatterTemplate() : (IFormatterTemplate)new FormatterTemplate();
188+
template.Namespace = namespaceDot + "Formatters" + (x.Namespace is null ? string.Empty : "." + x.Namespace);
189+
template.ObjectSerializationInfos = new[] { x };
190+
191+
var text = template.TransformText();
192+
waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
193+
}
194+
195+
foreach (var x in enumInfo)
196+
{
197+
var template = new EnumTemplate()
198+
{
199+
Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
200+
EnumSerializationInfos = new[] { x },
201+
};
202+
203+
var text = template.TransformText();
204+
waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
205+
}
206+
207+
foreach (var x in unionInfo)
208+
{
209+
var template = new UnionTemplate()
210+
{
211+
Namespace = namespaceDot + "Formatters" + ((x.Namespace == null) ? string.Empty : "." + x.Namespace),
212+
UnionSerializationInfos = new[] { x },
213+
};
214+
215+
var text = template.TransformText();
216+
waitingTasks[waitingIndex++] = OutputToDirAsync(output, template.Namespace, x.Name + "Formatter", multioutSymbol, text, cancellationToken);
217+
}
218+
219+
var resolverTemplate = new ResolverTemplate()
220+
{
221+
Namespace = namespaceDot + "Resolvers",
222+
FormatterNamespace = namespaceDot + "Formatters",
223+
ResolverName = resolverName,
224+
RegisterInfos = genericInfo.Where(x => !x.IsOpenGenericType).Cast<IResolverRegisterInfo>().Concat(enumInfo).Concat(unionInfo).Concat(objectInfo.Where(x => !x.IsOpenGenericType)).ToArray(),
225+
};
226+
227+
waitingTasks[waitingIndex] = OutputToDirAsync(output, resolverTemplate.Namespace, resolverTemplate.ResolverName, multioutSymbol, resolverTemplate.TransformText(), cancellationToken);
228+
return Task.WhenAll(waitingTasks);
229+
}
230+
208231
private Task OutputToDirAsync(string dir, string ns, string name, string multipleOutSymbol, string text, CancellationToken cancellationToken)
209232
{
210233
if (multipleOutSymbol == string.Empty)

0 commit comments

Comments
 (0)