Skip to content

Commit 8bc1b9a

Browse files
committed
Use default value from member declaration
1 parent f3abd3d commit 8bc1b9a

5 files changed

Lines changed: 121 additions & 7 deletions

File tree

src/MemoryPack.Generator/Extensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,14 @@ private static IEnumerable<TSource> DistinctByIterator<TSource, TKey>(IEnumerabl
248248
}
249249
}
250250

251-
public static bool TryGetConstructorParameter(this IMethodSymbol constructor, ISymbol member, out string? constructorParameterName)
251+
public static bool TryGetConstructorParameter(this IMethodSymbol constructor, ISymbol member, out IParameterSymbol? constructorParameter)
252252
{
253-
var constructorParameter = GetConstructorParameter(constructor, member.Name);
253+
constructorParameter = GetConstructorParameter(constructor, member.Name);
254254
if (constructorParameter == null && member.Name.StartsWith(UnderScorePrefix))
255255
{
256256
constructorParameter = GetConstructorParameter(constructor, member.Name.Substring(UnderScorePrefix.Length));
257257
}
258258

259-
constructorParameterName = constructorParameter?.Name;
260259
return constructorParameter != null;
261260

262261
static IParameterSymbol? GetConstructorParameter(IMethodSymbol constructor, string name) => constructor.Parameters.FirstOrDefault(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase));

src/MemoryPack.Generator/MemoryPackGenerator.Emitter.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ private string EmitDeserializeBody()
516516
{
517517
{{(IsValueType ? "" : "if (value == null)")}}
518518
{
519-
{{Members.Where(x => x.Symbol != null).Select(x => $" __{x.Name} = default!;").NewLine()}}
519+
{{Members.Where(x => x.Symbol != null).Select(x => $" __{x.Name} = {x.DefaultValueExpression};").NewLine()}}
520520
}
521521
{{(IsValueType ? "#if false" : " else")}}
522522
{
@@ -1366,5 +1366,22 @@ public string EmitReadRefDeserialize(int i, bool requireDeltaCheck)
13661366
return $"{pre}reader.ReadValue(ref __{Name});";
13671367
}
13681368
}
1369+
1370+
string EmitConstantValue(object? constantValue)
1371+
{
1372+
if (constantValue != null)
1373+
{
1374+
return constantValue switch
1375+
{
1376+
string x => $"\"{x}\"",
1377+
char x => $"'{x}'",
1378+
float x => $"{x}f",
1379+
decimal x => $"{x}D",
1380+
bool x => x ? "true" : "false",
1381+
_ => constantValue.ToString()
1382+
};
1383+
}
1384+
return "null";
1385+
}
13691386
}
13701387

src/MemoryPack.Generator/MemoryPackGenerator.Parser.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ partial class MemberMeta
609609
public int Order { get; }
610610
public bool HasExplicitOrder { get; }
611611
public MemberKind Kind { get; }
612+
public string DefaultValueExpression { get; } = "default!";
612613

613614
MemberMeta(int order)
614615
{
@@ -638,8 +639,12 @@ public MemberMeta(ISymbol symbol, IMethodSymbol? constructor, ReferenceSymbols r
638639

639640
if (constructor != null)
640641
{
641-
this.IsConstructorParameter = constructor.TryGetConstructorParameter(symbol, out var constructorParameterName);
642-
this.ConstructorParameterName = constructorParameterName;
642+
this.IsConstructorParameter = constructor.TryGetConstructorParameter(symbol, out var constructorParameter);
643+
this.ConstructorParameterName = constructorParameter?.Name;
644+
if (constructorParameter?.HasExplicitDefaultValue == true)
645+
{
646+
DefaultValueExpression = EmitConstantValue(constructorParameter.ExplicitDefaultValue);
647+
}
643648
}
644649
else
645650
{
@@ -657,7 +662,10 @@ public MemberMeta(ISymbol symbol, IMethodSymbol? constructor, ReferenceSymbols r
657662
#endif
658663
;
659664
MemberType = f.Type;
660-
665+
if (f.HasConstantValue)
666+
{
667+
DefaultValueExpression = EmitConstantValue(f.ConstantValue);
668+
}
661669
}
662670
else if (symbol is IPropertySymbol p)
663671
{
@@ -670,6 +678,16 @@ public MemberMeta(ISymbol symbol, IMethodSymbol? constructor, ReferenceSymbols r
670678
#endif
671679
&& (p.SetMethod != null && !p.SetMethod.IsInitOnly);
672680
MemberType = p.Type;
681+
682+
// Detect default value
683+
foreach (var syntaxReference in p.DeclaringSyntaxReferences)
684+
{
685+
if (syntaxReference.GetSyntax() is PropertyDeclarationSyntax { Initializer: { } initializer })
686+
{
687+
DefaultValueExpression = initializer.Value.ToString();
688+
break;
689+
}
690+
}
673691
}
674692
else
675693
{
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using MemoryPack.Tests.Models;
2+
3+
namespace MemoryPack.Tests;
4+
5+
public class DefaultValueTest
6+
{
7+
[Fact]
8+
public void FieldDefaultValue()
9+
{
10+
var bin = MemoryPackSerializer.Serialize(new DefaultValuePlaceholder { X = 1 });
11+
var expected = new FieldDefaultValue();
12+
var deserializedValue = MemoryPackSerializer.Deserialize<FieldDefaultValue>(bin)!;
13+
deserializedValue.Y.Should().Be(expected.Y);
14+
deserializedValue.Z.Should().Be(expected.Z);
15+
deserializedValue.S.Should().Be(expected.S);
16+
deserializedValue.B.Should().Be(expected.B);
17+
}
18+
19+
[Fact]
20+
public void PropertyDefaultValue()
21+
{
22+
var bin = MemoryPackSerializer.Serialize(new DefaultValuePlaceholder { X = 1 });
23+
var expected = new PropertyDefaultValue();
24+
var deserializedValue = MemoryPackSerializer.Deserialize<PropertyDefaultValue>(bin)!;
25+
deserializedValue.Y.Should().Be(expected.Y);
26+
deserializedValue.Z.Should().Be(expected.Z);
27+
deserializedValue.S.Should().Be(expected.S);
28+
deserializedValue.B.Should().Be(expected.B);
29+
}
30+
31+
[Fact]
32+
public void CtorParamDefaultValue()
33+
{
34+
var bin = MemoryPackSerializer.Serialize(new DefaultValuePlaceholder { X = 1 });
35+
var expected = new CtorParamDefaultValue(1);
36+
var deserializedValue = MemoryPackSerializer.Deserialize<CtorParamDefaultValue>(bin)!;
37+
deserializedValue.Y.Should().Be(expected.Y);
38+
deserializedValue.Z.Should().Be(expected.Z);
39+
deserializedValue.S.Should().Be(expected.S);
40+
deserializedValue.B.Should().Be(expected.B);
41+
}
42+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace MemoryPack.Tests.Models;
2+
3+
[MemoryPackable]
4+
partial class DefaultValuePlaceholder
5+
{
6+
public int X { get; set; }
7+
}
8+
9+
[MemoryPackable]
10+
partial class FieldDefaultValue
11+
{
12+
public int X;
13+
public int Y = 12345;
14+
public float Z = 678.9f;
15+
public string S = "aaaaaaaaa";
16+
public bool B = true;
17+
}
18+
19+
[MemoryPackable]
20+
partial class PropertyDefaultValue
21+
{
22+
public int X { get; set; }
23+
public int Y { get; set; } = 12345;
24+
public float Z { get; set; } = 678.9f;
25+
public string S { get; set; } = "aaaaaaaaa";
26+
public bool B { get; set; } = true;
27+
}
28+
29+
[MemoryPackable]
30+
[method: MemoryPackConstructor]
31+
partial class CtorParamDefaultValue(int x, int y = 12345, float z = 678.9f, string s = "aaaaaa", bool b = true)
32+
{
33+
public int X = x;
34+
public int Y = y;
35+
public float Z = z;
36+
public string S = s;
37+
public bool B = b;
38+
}

0 commit comments

Comments
 (0)