From 78f9d9e9c17e36321495d8beb6a213463ab0dfe2 Mon Sep 17 00:00:00 2001 From: Linwenxuan Date: Tue, 26 Mar 2024 20:00:32 +0800 Subject: [PATCH] [Proto] Implemented Simplest Generator --- .../ProtoSourceGenerator.Emitter.cs | 100 +++++++++++++++++- KonataNT.Proto/Serialization/ProtoReader.cs | 7 ++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/KonataNT.Proto.Generator/ProtoSourceGenerator.Emitter.cs b/KonataNT.Proto.Generator/ProtoSourceGenerator.Emitter.cs index c1f1bd7..1b59ec4 100644 --- a/KonataNT.Proto.Generator/ProtoSourceGenerator.Emitter.cs +++ b/KonataNT.Proto.Generator/ProtoSourceGenerator.Emitter.cs @@ -44,6 +44,7 @@ private static void Generate(TypeDeclarationSyntax syntax, Compilation compilati #pragma warning disable CA1050 // Declare types in namespaces. using System; +using System.Text; using KonataNT.Proto; using KonataNT.Proto.Serialization; "); @@ -138,7 +139,104 @@ private static void EmitDeserializer(TypeDeclarationSyntax syntax, ContextVisito sb.AppendLine($" public static IProto Deserialize(byte[] buffer)"); sb.AppendLine(" {"); - sb.AppendLine($" return new {className}();"); + sb.AppendLine($" var {className} = new {className}();"); + sb.AppendLine(); + sb.AppendLine(" var reader = new ProtoReader(buffer.AsSpan());"); + sb.AppendLine(" while (!reader.EndOfStream)"); + sb.AppendLine(" {"); + sb.AppendLine(" uint tag = reader.ReadTag();"); + sb.AppendLine(" switch (tag)"); + sb.AppendLine(" {"); + + foreach (var meta in context.List) + { + EmitMemberDeserialize(sb, meta, className, meta.Name); + } + + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine($" return {className};"); sb.AppendLine(" }"); } + + private static void EmitMemberDeserialize(StringBuilder sb, ProtoMemberMeta meta, string className, string name) + { + string type = meta.Type.ToString().Replace("?", ""); + + sb.AppendLine($" case {meta.Tag}:"); + sb.AppendLine(" {"); + if (meta.IsEnumerable) + { + sb.AppendLine($" if ({name} == null) {name} = new {meta.Type}();"); + switch (meta.WireType) + { + case WireType.LengthDelimited: + sb.AppendLine($" var {name}Length = reader.ReadVarInt();"); + sb.AppendLine($" var {name}Buffer = reader.ReadRawBytes({name}Length);"); + if (meta.IsNested) + { + sb.AppendLine($" {name}.Add(({type}){type}.Deserialize({name}Buffer));"); + } + else if (meta.Type.ToString() == "string" || meta.Type.ToString() == "string?") + { + sb.AppendLine($" {name}.Add(Encoding.UTF8.GetString({name}Buffer));"); + } + else + { + sb.AppendLine($" {name}.Add({name}Buffer;)"); + } + break; + case WireType.VarInt: + if (type == "bool") + { + sb.AppendLine($" var result = reader.ReadVarInt();"); + sb.AppendLine($" {name}.Add(result != 0);"); + } + else + { + sb.AppendLine($" {className}.{name} = reader.ReadVarInt<{type}>();"); + } + break; + default: + throw new NotImplementedException(); + } + } + else + { + switch (meta.WireType) + { + case WireType.LengthDelimited: + sb.AppendLine($" var {name}Length = reader.ReadVarInt();"); + sb.AppendLine($" var {name}Buffer = reader.ReadRawBytes({name}Length);"); + if (meta.IsNested) + { + sb.AppendLine($" {className}.{name} = ({type}){type}.Deserialize({name}Buffer);"); + } + else if (meta.Type.ToString() == "string" || meta.Type.ToString() == "string?") + { + sb.AppendLine($" {className}.{name} = Encoding.UTF8.GetString({name}Buffer);"); + } + else + { + sb.AppendLine($" {className}.{name} = {name}Buffer;"); + } + break; + case WireType.VarInt: + if (type == "bool") + { + sb.AppendLine($" var result = reader.ReadVarInt();"); + sb.AppendLine($" {className}.{name} = result != 0;"); + } + else + { + sb.AppendLine($" {className}.{name} = reader.ReadVarInt<{type}>();"); + } + break; + default: + throw new NotImplementedException(); + } + } + sb.AppendLine(" break;"); + sb.AppendLine(" }"); + } } \ No newline at end of file diff --git a/KonataNT.Proto/Serialization/ProtoReader.cs b/KonataNT.Proto/Serialization/ProtoReader.cs index 6ada7c1..6af1201 100644 --- a/KonataNT.Proto/Serialization/ProtoReader.cs +++ b/KonataNT.Proto/Serialization/ProtoReader.cs @@ -11,6 +11,8 @@ public ref struct ProtoReader private readonly ReadOnlySpan _span; private uint _position; + + public bool EndOfStream => _position == Length; private readonly ref byte First => ref MemoryMarshal.GetReference(_span); @@ -135,6 +137,11 @@ public byte[] ReadRawBytes(uint length) return ReadRawBytesSpan(length).ToArray(); } + public uint ReadTag() + { + return ReadVarInt() >> 3; + } + [DoesNotReturn] public static void ThrowMalformedMessage() {