private static void GenerateReadMethods(Endianness le, StringBuilder methods, StringBuilder extensions, bool move)
        {
            string CreateBody(string body, MethodData ds, string len, string move)
            {
                var b = body;

                if (!ds.NoLengthParam && !string.IsNullOrWhiteSpace(len) && len != "length")
                {
                    len = $"length = {len};";
                }
                else
                {
                    len = "";
                }
                b = b.Replace("[LEN]", len);
                b = b.Replace("[MOVE]", move);
                return(b);
            }

            if (move && le == Endianness.Default)
            {
                Helper.Method(extensions, true, "void", "Move", "ref this Span<byte> span, int length", "span = span.Slice(length);", "");
                Helper.Method(extensions, true, "void", "Move", "ref this ReadOnlySpan<byte> span, int length", "span = span.Slice(length);", "");
                Helper.Method(methods, true, "void", "Move", "ref Span<byte> span, int length", "span = span.Slice(length);", "");
                Helper.Method(methods, true, "void", "Move", "ref ReadOnlySpan<byte> span, int length", "span = span.Slice(length);", "");
            }

            // Since extension methods causes defensive copying we duplicate the code instead of forming a chain.
            string methodName(string t) => (move ? "Move" : "") + $"Read{t}" + CodeGenBodies.EndiannessToMethodExtension(le);

            foreach (var ds in CodeGenBodies.DataStructures)
            {
                if (!ds.Endian.HasFlag(le))
                {
                    continue;
                }
                if (ds.RW == MethodRW.WriteOnly)
                {
                    continue;
                }

                var outRef = (move ? "ref " : "");
                // For "Move" we need out parameter
                var cParams = $"span";
                // Extra parameters in addition to span
                if (!string.IsNullOrWhiteSpace(ds.ExtraReadParamsDef))
                {
                    cParams += $", {ds.ExtraReadParamsDef}";
                }

                // Method name and skeleton body
                var mn   = methodName(ds.Name);
                var body = ds.GetReadBody(le);

                var moveStr = "";
                if (move && !string.IsNullOrWhiteSpace(ds.Size))
                {
                    moveStr = $"span = span.Slice({ds.Size});";
                }


                var fwdExtraParams = string.IsNullOrWhiteSpace(ds.ExtraReadParams) ? "" : $", {ds.ExtraReadParams}";


                // Without "out var length": Compiler will optimize away assignment
                if (ds.NoLengthParam)
                {
                    // We use "length" as input parameter so we won't add any length logic to it

                    // Create method for ReadOnlySpan<byte>
                    Helper.Method(methods, true, ds.TypeString, mn, $"{outRef}Span<byte> {cParams}", CreateBody(body, ds, "", moveStr), "");
                    // Alias from Span to ReadOnlySpan
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(methods, true, ds.TypeString, mn, $"{outRef}ReadOnlySpan<byte> {cParams}", CreateBody(body, ds, "", moveStr), "");
                    }

                    // Extension method alias for ReadOnlySpan and Span
                    Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this Span<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams});", "");
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this ReadOnlySpan<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams});", "");
                    }
                }
                else
                // With "out var length"
                {
                    // Overloads ignoring "out int length" allowing compiler to optimize it away
                    Helper.Method(methods, true, ds.TypeString, mn, $"{outRef} Span<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out _);", "");
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(methods, true, ds.TypeString, mn, $"{outRef} ReadOnlySpan<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out _);", "");
                    }

                    // Full method
                    Helper.Method(methods, true, ds.TypeString, mn, $"{outRef}Span<byte> {cParams}, out int length", CreateBody(body, ds, ds.Size, moveStr), "");
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(methods, true, ds.TypeString, mn, $"{outRef}ReadOnlySpan<byte> {cParams}, out int length", CreateBody(body, ds, ds.Size, moveStr), "");
                    }

                    // Extension method
                    // Overload for Span<byte>
                    Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this Span<byte>{cParams}, out int length", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out length);", "");
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this ReadOnlySpan<byte>{cParams}, out int length", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out length);", "");
                    }
                    // Overloads ignoring "out int length" allowing compiler to optimize it away
                    Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this Span<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out _);", "");
                    if (ds.TypeString != "Span<byte>")
                    {
                        Helper.Method(extensions, true, ds.TypeString, mn, $"{outRef}this ReadOnlySpan<byte>{cParams}", $"SpanUtils.{mn}({outRef}span{fwdExtraParams}, out _);", "");
                    }
                }
            }
        }
Exemple #2
0
        private static void GenReadBody(Endianness le, MethodData ds, StringBuilder sb, bool isMemoryStreamer,
                                        bool isReadOnly)
        {
            if (ds.RW == MethodRW.WriteOnly)
            {
                return;
            }

            if (isReadOnly && ds.Name == "Span")
            {
                return;
            }

            var           memory = isMemoryStreamer ? "Memory." : "";
            List <string> pDef   = new();
            List <string> p      = new();

            var checkWriteOk = "";

            // Special case for returning span, then we need to read Span only
            if (ds.Name == "Span")
            {
                if (!isMemoryStreamer)
                {
                    memory = "";
                }
                else
                {
                    memory       = "Memory.";
                    checkWriteOk = @"
            if (!CanWrite)
                throw new ReadOnlyException(""Span is read-only, use ReadReadOnlySpan."");";
                }
            }

            var name = "Read" + ds.Name + CodeGenBodies.EndiannessToMethodExtension(le);


            if (!string.IsNullOrWhiteSpace(ds.ExtraReadParamsDef))
            {
                pDef.Add(ds.ExtraReadParamsDef);
            }
            if (!string.IsNullOrWhiteSpace(ds.ExtraReadParams))
            {
                p.Add(ds.ExtraReadParams);
            }
            var retType = ds.TypeString;

            if (isMemoryStreamer && ds.Endian == Endianness.Default &&
                ds.TypeString == typeof(byte).Name && ds.Name == typeof(byte).Name)
            {
                retType = "override int";
            }
            if (!ds.NoLengthParam)
            {
                var pC = new List <string>(p);
                pC.Add("out _");
                Helper.Method(sb, false, retType, $"{name}", Sj(pDef), $"{name}({Sj(pC)});", "");
                pDef.Add("out int length");
                p.Add("out length");
            }

            Helper.Method(sb, false, ds.TypeString, $"{name}", Sj(pDef), @$ "{checkWriteOk}
            var ret = SpanUtils.{name}({memory}Span.Slice(_position), {Sj(p)});
        private static void GenerateWriteMethods(Endianness le, StringBuilder methods, StringBuilder extensions, bool move)
        {
            string CreateBody(string body, MethodData ds, string len, string move)
            {
                var b = body;

                if (!ds.NoLengthParam && !string.IsNullOrWhiteSpace(len) && len != "length")
                {
                    len = $"length = {len};";
                }
                else
                {
                    len = "";
                }
                b = b.Replace("[LEN]", len);
                b = b.Replace("[MOVE]", move);
                return(b);
            }

            // Since extension methods causes defensive copying we duplicate the code instead of forming a chain.
            string methodName(string t) => (move ? "Move" : "") + $"Write{t}" + CodeGenBodies.EndiannessToMethodExtension(le);

            foreach (var ds in CodeGenBodies.DataStructures)
            {
                if (!ds.Endian.HasFlag(le))
                {
                    continue;
                }
                // We skip aliases
                if (ds.IsAlias || ds.RW == MethodRW.ReadOnly)
                {
                    continue;
                }


                var outRef = (move ? "ref " : "");
                // For "Move" we need out parameter
                var cParams = $"span, {ds.TypeString} value";

                // Method name and skeleton body
                var mn   = methodName(ds.WriteName);
                var body = ds.GetWriteBody(le);

                var moveStr = "";
                if (move && !string.IsNullOrWhiteSpace(ds.Size))
                {
                    moveStr = $"span = span.Slice({ds.Size});";
                }


                {
                    // Overloads ignoring "out int length" allowing compiler to optimize it away
                    Helper.Method(methods, true, "void", mn, $"{outRef}Span<byte>{cParams}", $"SpanUtils.{mn}({outRef}span, value, out _);", "");

                    // Full method
                    Helper.Method(methods, true, "void", mn, $"{outRef}Span<byte>{cParams}, out int length", CreateBody(body, ds, ds.Size, moveStr), "");

                    // Extension method
                    // Overload for Span<byte>
                    Helper.Method(extensions, true, "void", mn, $"{outRef}this Span<byte>{cParams}, out int length", $"SpanUtils.{mn}({outRef}span, value, out length);", "");
                    // Overloads ignoring "out int length" allowing compiler to optimize it away
                    Helper.Method(extensions, true, "void", mn, $"{outRef}this Span<byte>{cParams}", $"SpanUtils.{mn}({outRef}span, value, out _);", "");
                }
            }
        }