Skip to content

Commit d9bab6d

Browse files
committed
[Proto] Forward Attribute Values
1 parent 088b84a commit d9bab6d

File tree

5 files changed

+110
-18
lines changed

5 files changed

+110
-18
lines changed

Lagrange.Proto.Generator/ProtoSourceGenerator.Emitter.TypeInfo.cs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.CodeAnalysis.CSharp;
1+
using Lagrange.Proto.Serialization;
22
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
33
using SK = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
44

@@ -14,6 +14,8 @@ private partial class Emitter
1414

1515
private readonly string _protoTypeInfoNullableFullName = $"global::Lagrange.Proto.Serialization.Metadata.ProtoObjectInfo<{parser.Identifier}>?";
1616

17+
private const string ProtoNumberHandlingFullName = "global::Lagrange.Proto.Serialization.ProtoNumberHandling";
18+
1719
private FieldDeclarationSyntax EmitTypeInfoField()
1820
{
1921
return SF.FieldDeclaration(SF.VariableDeclaration(SF.ParseTypeName(_protoTypeInfoNullableFullName)).AddVariables(SF.VariableDeclarator(SF.Identifier("_typeInfo"))))
@@ -42,22 +44,32 @@ private MethodDeclarationSyntax EmitTypeInfoCreationMethod()
4244
{
4345
var fields = parser.Fields.ToDictionary(
4446
kv => (kv.Key << 3) | (byte)kv.Value.WireType,
45-
kv => SF.ObjectCreationExpression(SF.ParseTypeName($"global::Lagrange.Proto.Serialization.Metadata.ProtoFieldInfo<{kv.Value.TypeSyntax}>"))
46-
.WithArgumentList(SF.ArgumentList(
47-
SF.SeparatedList<ArgumentSyntax>(
48-
[
49-
SF.Argument(SF.LiteralExpression(SK.NumericLiteralExpression, SF.Literal(kv.Key))),
50-
SF.Argument(SF.MemberAccessExpression(SK.SimpleMemberAccessExpression, SF.IdentifierName("global::Lagrange.Proto.Serialization.WireType"), SF.IdentifierName(kv.Value.WireType.ToString()))),
51-
SF.Argument(SF.TypeOfExpression(SF.ParseTypeName(parser.Identifier)))
52-
]
53-
)
54-
))
55-
.WithInitializer(SF.InitializerExpression(SK.ObjectInitializerExpression).AddExpressions(
56-
SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("Get"), EmitTypeInfoGetter(kv.Value.Name)),
57-
SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("Set"), EmitTypeInfoSetter(kv.Value.Name))
47+
kv =>
48+
{
49+
string first = kv.Value.WireType switch
50+
{
51+
WireType.Fixed32 or WireType.Fixed64 => $"{ProtoNumberHandlingFullName}.{kv.Value.WireType}",
52+
_ => $"{ProtoNumberHandlingFullName}.Default"
53+
};
54+
string numberHandling = $"{first}{(kv.Value.IsSigned ? $" | {ProtoNumberHandlingFullName}.Signed" : "")}";
55+
56+
return SF.ObjectCreationExpression(SF.ParseTypeName($"global::Lagrange.Proto.Serialization.Metadata.ProtoFieldInfo<{kv.Value.TypeSyntax}>"))
57+
.WithArgumentList(SF.ArgumentList(
58+
SF.SeparatedList<ArgumentSyntax>(
59+
[
60+
SF.Argument(SF.LiteralExpression(SK.NumericLiteralExpression, SF.Literal(kv.Key))),
61+
SF.Argument(SF.MemberAccessExpression(SK.SimpleMemberAccessExpression, SF.IdentifierName("global::Lagrange.Proto.Serialization.WireType"), SF.IdentifierName(kv.Value.WireType.ToString()))),
62+
SF.Argument(SF.TypeOfExpression(SF.ParseTypeName(parser.Identifier)))
63+
]
5864
)
59-
)
60-
);
65+
))
66+
.WithInitializer(SF.InitializerExpression(SK.ObjectInitializerExpression).AddExpressions(
67+
SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("Get"), EmitTypeInfoGetter(kv.Value.Name)),
68+
SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("Set"), EmitTypeInfoSetter(kv.Value.Name)),
69+
SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("NumberHandling"), SF.IdentifierName(numberHandling))
70+
)
71+
);
72+
});
6173
var dictionaryInitialize = SF.ObjectCreationExpression(SF.ParseTypeName("global::System.Collections.Generic.Dictionary<int, global::Lagrange.Proto.Serialization.Metadata.ProtoFieldInfo>"))
6274
.WithArgumentList(SF.ArgumentList())
6375
.WithInitializer(SF.InitializerExpression(SK.CollectionInitializerExpression).AddExpressions(
@@ -72,10 +84,11 @@ private MethodDeclarationSyntax EmitTypeInfoCreationMethod()
7284

7385
var lambda = SF.ParenthesizedLambdaExpression(SF.ParameterList(), SF.ObjectCreationExpression(SF.ParseTypeName(parser.Identifier)).WithArgumentList(SF.ArgumentList()));
7486
var objectCreatorAssignment = SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("ObjectCreator"), lambda);
87+
var ignoreDefaultAssignment = SF.AssignmentExpression(SK.SimpleAssignmentExpression, SF.IdentifierName("IgnoreDefaultFields"), SF.LiteralExpression(parser.IgnoreDefaultFields ? SK.TrueLiteralExpression : SK.FalseLiteralExpression));
7588

7689
var returnStatement = SF.ReturnStatement(SF.ObjectCreationExpression(SF.ParseTypeName(_protoTypeInfoFullName))
7790
.WithArgumentList(SF.ArgumentList())
78-
.WithInitializer(SF.InitializerExpression(SK.ObjectInitializerExpression).AddExpressions(fieldsAssignment, objectCreatorAssignment))
91+
.WithInitializer(SF.InitializerExpression(SK.ObjectInitializerExpression).AddExpressions(fieldsAssignment, objectCreatorAssignment, ignoreDefaultAssignment))
7992
);
8093

8194
return SF.MethodDeclaration(SF.ParseTypeName(_protoTypeInfoFullName), "CreateTypeInfo")
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Runtime.CompilerServices;
2+
using Lagrange.Proto.Primitives;
3+
4+
namespace Lagrange.Proto.Serialization.Converter;
5+
6+
public unsafe class ProtoEnumConverter<T> : ProtoConverter<T> where T : unmanaged, Enum
7+
{
8+
public override void Write(int field, WireType wireType, ProtoWriter writer, T value)
9+
{
10+
switch (sizeof(T))
11+
{
12+
case sizeof(byte):
13+
{
14+
switch (wireType)
15+
{
16+
case WireType.Fixed32: writer.EncodeFixed32(Unsafe.As<T, byte>(ref value)); break;
17+
case WireType.Fixed64: writer.EncodeFixed64(Unsafe.As<T, byte>(ref value)); break;
18+
case WireType.VarInt: writer.EncodeVarInt(Unsafe.As<T, byte>(ref value)); break;
19+
}
20+
break;
21+
}
22+
case sizeof(short):
23+
{
24+
switch (wireType)
25+
{
26+
case WireType.Fixed32: writer.EncodeFixed32(Unsafe.As<T, short>(ref value)); break;
27+
case WireType.Fixed64: writer.EncodeFixed64(Unsafe.As<T, short>(ref value)); break;
28+
case WireType.VarInt: writer.EncodeVarInt(Unsafe.As<T, short>(ref value)); break;
29+
}
30+
break;
31+
}
32+
case sizeof(int):
33+
{
34+
switch (wireType)
35+
{
36+
case WireType.Fixed32: writer.EncodeFixed32(Unsafe.As<T, int>(ref value)); break;
37+
case WireType.Fixed64: writer.EncodeFixed64(Unsafe.As<T, int>(ref value)); break;
38+
case WireType.VarInt: writer.EncodeVarInt(Unsafe.As<T, int>(ref value)); break;
39+
}
40+
break;
41+
}
42+
case sizeof(long):
43+
{
44+
switch (wireType)
45+
{
46+
case WireType.Fixed32: writer.EncodeFixed32(Unsafe.As<T, long>(ref value)); break;
47+
case WireType.Fixed64: writer.EncodeFixed64(Unsafe.As<T, long>(ref value)); break;
48+
case WireType.VarInt: writer.EncodeVarInt(Unsafe.As<T, long>(ref value)); break;
49+
}
50+
break;
51+
}
52+
default:
53+
{
54+
throw new ArgumentOutOfRangeException(nameof(wireType), wireType, null);
55+
}
56+
}
57+
}
58+
59+
public override T Read(int field, WireType wireType, ref ProtoReader reader)
60+
{
61+
long value = wireType switch
62+
{
63+
WireType.Fixed32 => reader.DecodeFixed32<int>(),
64+
WireType.Fixed64 => reader.DecodeFixed64<long>(),
65+
WireType.VarInt => reader.DecodeVarInt<long>(),
66+
_ => throw new ArgumentOutOfRangeException(nameof(wireType), wireType, null)
67+
};
68+
69+
return Unsafe.As<long, T>(ref value);
70+
}
71+
}

Lagrange.Proto/Serialization/Metadata/ProtoFieldInfo.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public abstract class ProtoFieldInfo(int field, WireType wireType, Type declared
1515

1616
public Type PropertyType { get; } = property;
1717

18+
public ProtoNumberHandling NumberHandling { get; init; } = ProtoNumberHandling.Default;
19+
1820
internal ProtoConverter EffectiveConverter
1921
{
2022
get

Lagrange.Proto/Serialization/Metadata/ProtoObjectInfo.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ public class ProtoObjectInfo<T>
88
public Dictionary<int, ProtoFieldInfo> Fields { get; init; } = new();
99

1010
public Func<T>? ObjectCreator { get; init; }
11+
12+
public bool IgnoreDefaultFields { get; init; }
1113
}

Lagrange.Proto/Serialization/Metadata/ProtoTypeResolver.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static Cache()
100100
}
101101
}
102102

103+
[UnconditionalSuppressMessage("Trimmer", "IL2055")]
104+
[UnconditionalSuppressMessage("Trimmer", "IL2067")]
103105
[UnconditionalSuppressMessage("Trimmer", "IL3050", Justification = "The generic type definition would always appear in metadata as it is a member in class serialized.")]
104106
private static ProtoConverter<T>? ResolveGenericConverter<T>(Type type)
105107
{
@@ -113,8 +115,10 @@ static Cache()
113115
return null;
114116
}
115117

116-
[UnconditionalSuppressMessage("Trimmer", "IL3050", Justification = "The generic type definition would always appear in metadata as it is a member in class serialized.")]
118+
[UnconditionalSuppressMessage("Trimmer", "IL2055")]
119+
[UnconditionalSuppressMessage("Trimmer", "IL2067")]
117120
[UnconditionalSuppressMessage("Trimmer", "IL2070", Justification = "The interface would always be preserve")]
121+
[UnconditionalSuppressMessage("Trimmer", "IL3050", Justification = "The generic type definition would always appear in metadata as it is a member in class serialized.")]
118122
private static ProtoConverter<T>? ResolveInterfaceConverter<T>(Type type)
119123
{
120124
var interfaces = type.GetInterfaces();

0 commit comments

Comments
 (0)