Beispiel #1
0
        public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            ReadOnlySpan <byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

            if (span.SequenceEqual(DecimalZero))
            {
                return(0);
            }

            if (reader.TokenType == JsonTokenType.String)
            {
                if (Utf8Parser.TryParse(span, out int value, out _))
                {
                    return(value);
                }

                throw new FormatException($"Invalid integer format: '{Encoding.UTF8.GetChars(span.ToArray())}' Position: {reader.Position}");
            }

            return(reader.GetInt32());
        }
        private static bool TryReadLength(ReadOnlySpan <byte> buffer, out int index, out int length)
        {
            length = 0;
            // Read until the first ':' to find the length
            index = buffer.IndexOf((byte)FieldDelimiter);

            if (index == -1)
            {
                // Insufficient data
                return(false);
            }

            var lengthSpan = buffer.Slice(0, index);

            if (!Utf8Parser.TryParse(buffer, out length, out var bytesConsumed) || bytesConsumed < lengthSpan.Length)
            {
                throw new FormatException($"Invalid length: '{Encoding.UTF8.GetString(lengthSpan.ToArray())}'");
            }

            return(true);
        }
Beispiel #3
0
    public static PartSysParamRandom ParseRandom(ReadOnlySpan <byte> value)
    {
        if (!Utf8Parser.TryParse(value, out float lower, out var bytesConsumed))
        {
            return(null);
        }

        if (bytesConsumed >= value.Length || value[bytesConsumed] != '?')
        {
            return(null);
        }

        if (!Utf8Parser.TryParse(value.Slice(bytesConsumed + 1), out float upper, out _))
        {
            return(null);
        }

        var variance = upper - lower;

        return(new PartSysParamRandom(lower, variance));
    }
Beispiel #4
0
        public static bool TryParseBoolean(ReadOnlySpan <byte> text, out bool value, out int bytesConsumed, SymbolTable symbolTable = null)
        {
            symbolTable = symbolTable ?? SymbolTable.InvariantUtf8;

            bytesConsumed = 0;
            value         = default;

            if (symbolTable == SymbolTable.InvariantUtf8)
            {
                return(Utf8Parser.TryParse(text, out value, out bytesConsumed));
            }
            if (symbolTable == SymbolTable.InvariantUtf16)
            {
                ReadOnlySpan <char> textChars = text.NonPortableCast <byte, char>();
                bool result = Utf16Parser.TryParseBoolean(textChars, out value, out int charactersConsumed);
                bytesConsumed = charactersConsumed * sizeof(char);
                return(result);
            }

            return(false);
        }
Beispiel #5
0
        public override int?Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

                if (Utf8Parser.TryParse(span, out int number, out var bytesConsumed) && span.Length == bytesConsumed)
                {
                    return(number);
                }

                if (int.TryParse(reader.GetString(), out number))
                {
                    return(number);
                }

                return(null);
            }

            return(reader.GetInt32());
        }
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.Number && typeToConvert == typeof(string))
            {
                return(reader.GetString() ?? "");
            }

            var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

            if (Utf8Parser.TryParse(span, out long number, out var bytesConsumed) && span.Length == bytesConsumed)
            {
                return(number.ToString());
            }

            var data = reader.GetString();

            throw new InvalidOperationException($"'{data}' is not a correct expected value!")
                  {
                      Source = nameof(GitVersionStringConverter)
                  };
        }
Beispiel #7
0
        internal double GetDoubleWithQuotes()
        {
            ReadOnlySpan <byte> span = GetUnescapedSpan();

            if (JsonReaderHelper.TryGetFloatingPointConstant(span, out double value))
            {
                return(value);
            }

            // NETCOREAPP implementation of the TryParse method above permits case-insensitive variants of the
            // float constants "NaN", "Infinity", "-Infinity". This differs from the NETFRAMEWORK implementation.
            // The following logic reconciles the two implementations to enforce consistent behavior.
            if (!(Utf8Parser.TryParse(span, out value, out int bytesConsumed) &&
                  span.Length == bytesConsumed &&
                  JsonHelpers.IsFinite(value)))
            {
                ThrowHelper.ThrowFormatException(NumericType.Double);
            }

            return(value);
        }
        private object ReadNumber(ref Utf8JsonReader reader)
        {
            ReadOnlySpan <byte> buffer = reader.GetRawString();

            if (Utf8Parser.TryParse(buffer, out long lValue, out int bytesConsumed) && bytesConsumed == buffer.Length)
            {
                return(lValue);
            }

            if (Utf8Parser.TryParse(buffer, out ulong ulValue, out bytesConsumed) && bytesConsumed == buffer.Length)
            {
                return(ulValue);
            }

            if (Utf8Parser.TryParse(buffer, out double dblValue, out bytesConsumed) && bytesConsumed == buffer.Length)
            {
                return(dblValue);
            }

            throw new JsonException();
        }
        public override int Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                // try to parse number directly from bytes
                ReadOnlySpan <byte> span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
                if (Utf8Parser.TryParse(span, out int number, out int bytesConsumed) && span.Length == bytesConsumed)
                {
                    return(number);
                }

                // try to parse from a string if the above failed, this covers cases with other escaped/UTF characters
                if (int.TryParse(reader.GetString(), out number))
                {
                    return(number);
                }
            }

            // fallback to default handling
            return(reader.GetInt32());
        }
Beispiel #10
0
        /// <summary>
        /// Tries to convert a memory span that contains the bytes of a UTF-8 string representation of a day on the format YYYY-MM-DD to its <see cref="Day"/> equivalent and returns a value that indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="value">The memory span that contains the bytes of the UTF-8 string value to parse.</param>
        /// <param name="day">Contains the <see cref="Day"/> value equivalent to the value contained in <paramref name="value"/>, if the conversion succeeded, or default if the conversion failed.</param>
        /// <returns>true if the <paramref name="value"/> parameter was converted successfully; otherwise, false.</returns>
        public static bool TryParse(ReadOnlySpan <byte> value, out Day day)
        {
            const byte Separator = (byte)'-';

            if (value.Length == 10 &&
                value[4] == Separator &&
                value[7] == Separator &&
                Utf8Parser.TryParse(value.Slice(0, 4), out uint year) &&
                Utf8Parser.TryParse(value.Slice(5, 2), out uint month) &&
                Utf8Parser.TryParse(value.Slice(8, 2), out uint dayNumber))
            {
                try
                {
                    day = new Day(new Month(new Year((int)year), (int)month), (int)dayNumber);
                    return(true);
                }
                catch { }
            }
            day = default;
            return(false);
        }
Beispiel #11
0
        public unsafe void GuidParsingUtf8(string format)
        {
            var parsedFormat = ParsedFormat.Parse(format);
            var random       = new Random(1000);
            var guidBytes    = new byte[16];

            var expected = guidWithAllNonZeroDigits;

            for (int i = 0; i < 100; i++)
            {
                var expectedString = expected.ToString(format, CultureInfo.InvariantCulture);
                var utf8Bytes      = Text.Encoding.UTF8.GetBytes(expectedString);

                Assert.True(Utf8Parser.TryParseGuid(utf8Bytes, out Guid parsed, out int bytesConsumed, parsedFormat));
                Assert.Equal(expected, parsed);
                Assert.Equal(expectedString.Length, bytesConsumed);

                random.NextBytes(guidBytes);
                expected = new Guid(guidBytes);
            }
        }
Beispiel #12
0
        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="typeToConvert"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

            if (reader.TokenType == JsonTokenType.String)
            {
                if (Utf8Parser.TryParse(span, out long result1, out int length) && length == span.Length)
                {
                    return(result1);
                }
                if (long.TryParse(reader.GetString(), out long result2))
                {
                    return(result2);
                }
            }
            else
            {
                return(reader.GetInt64());
            }
            return(0L);
        }
        public unsafe void DecimalPositiveTests(string text, int length, decimal expectedValue, int expectedConsumed)
        {
            byte[] byteBuffer            = Text.Encoding.UTF8.GetBytes(text);
            ReadOnlySpan <byte> byteSpan = new ReadOnlySpan <byte>(byteBuffer);

            char[] charBuffer            = text.ToCharArray();
            ReadOnlySpan <char> charSpan = new ReadOnlySpan <char>(charBuffer);

            bool result;

            result = CustomParser.TryParseDecimal(byteSpan, out decimal actualValue, out int actualConsumed, SymbolTable.InvariantUtf8);

            Assert.True(result);
            Assert.Equal(expectedValue, actualValue);
            Assert.Equal(expectedConsumed, actualConsumed);

            result = Utf8Parser.TryParse(byteSpan, out actualValue, out actualConsumed);

            Assert.True(result);
            Assert.Equal(expectedValue, actualValue);
            Assert.Equal(expectedConsumed, actualConsumed);

            ReadOnlySpan <byte> utf16ByteSpan = charSpan.AsBytes();

            result = CustomParser.TryParseDecimal(utf16ByteSpan, out actualValue, out actualConsumed, SymbolTable.InvariantUtf16);
            Assert.True(result);
            Assert.Equal(expectedValue, actualValue);
            Assert.Equal(expectedConsumed, actualConsumed / 2);

            result = Utf16Parser.TryParseDecimal(charSpan, out actualValue);

            Assert.True(result);
            Assert.Equal(expectedValue, actualValue);

            result = Utf16Parser.TryParseDecimal(charSpan, out actualValue, out actualConsumed);

            Assert.True(result);
            Assert.Equal(expectedValue, actualValue);
            Assert.Equal(expectedConsumed, actualConsumed);
        }
Beispiel #14
0
        public override long Read(
            ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                ReadOnlySpan <byte> span =
                    reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

                if (Utf8Parser.TryParse(span, out long number, out int bytesConsumed) &&
                    span.Length == bytesConsumed)
                {
                    return(number);
                }

                if (long.TryParse(reader.GetString(), out number))
                {
                    return(number);
                }
            }

            return(reader.GetInt64());
        }
Beispiel #15
0
            public unsafe (string raw, object value) ParseNumber(bool isDecimal, int start, int end, bool notAllowedConvertUnsignedInteger)
            {
                var len = end - start;

                fixed(char *chars = &Slice(start, len).GetPinnableReference())
                {
                    var bytes = stackalloc byte[len];

                    Encoding.UTF8.GetBytes(chars, len, bytes, len);
                    var buffer = new ReadOnlySpan <byte>(bytes, len);

                    if (isDecimal)
                    {
                        var success = Utf8Parser.TryParse(buffer, out decimal decimalValue, out _);
                        if (!success)
                        {
                            throw new InvalidCastException($"Can not parse value({this[start, len]}) to decimal at (start:{start},end:{end})");
                        }
                        return(this[start, len], decimalValue);
                    }
                    else
                    {
                        var success = Utf8Parser.TryParse(buffer, out ulong ulongValue, out _);
                        if (!success)
                        {
                            throw new InvalidCastException($"Can not parse value({this[start, len]}) to ulong at (start:{start},end:{end})");
                        }
                        if (notAllowedConvertUnsignedInteger)
                        {
                            return(this[start, len], ulongValue);
                        }
                        if (ulongValue <= int.MaxValue)
                        {
                            return(this[start, len], (int)ulongValue);
                        }
                        return(ulongValue <= uint.MaxValue ? (this[start, len], (uint)ulongValue) : (this[start, len], ulongValue));
                    }
                }
            }
Beispiel #16
0
        private unsafe static void PrimitiveParserByteSpanToUInt32_BytesConsumed_VariableLength()
        {
            int textLength = s_UInt32TextArray.Length;

            byte[][] utf8ByteArray = (byte[][])Array.CreateInstance(typeof(byte[]), textLength);
            for (var i = 0; i < textLength; i++)
            {
                utf8ByteArray[i] = Text.Encoding.UTF8.GetBytes(s_UInt32TextArray[i]);
            }
            foreach (var iteration in Benchmark.Iterations)
            {
                using (iteration.StartMeasurement())
                {
                    for (int i = 0; i < TestHelper.LoadIterations; i++)
                    {
                        ReadOnlySpan <byte> utf8ByteSpan = utf8ByteArray[i % textLength];
                        Utf8Parser.TryParse(utf8ByteSpan, out uint value, out int bytesConsumed);
                        TestHelper.DoNotIgnore(value, bytesConsumed);
                    }
                }
            }
        }
Beispiel #17
0
        private static void Utf8Parser_TryParseDouble(ReadOnlySpan <byte> data)
        {
            Span <byte> to = stackalloc byte[1024];

            if (Utf8Parser.TryParse(data, out double d1, out _))
            {
                if (double.IsNaN(d1))
                {
                    return;
                }

                if (!Utf8Formatter.TryFormat(d1, to, out int written))
                {
                    throw new Exception();
                }

                if (!Utf8Parser.TryParse(to.Slice(0, written), out double d2, out _))
                {
                    throw new Exception();
                }
            }
        }
Beispiel #18
0
        public static bool TryGetEscapedGuid(ReadOnlySpan <byte> source, out Guid value)
        {
            Debug.Assert(source.Length <= JsonConstants.MaximumEscapedGuidLength);

            Span <byte> utf8Unescaped = stackalloc byte[JsonConstants.MaximumEscapedGuidLength];

            Unescape(source, utf8Unescaped, out int written);
            Debug.Assert(written > 0);

            utf8Unescaped = utf8Unescaped.Slice(0, written);
            Debug.Assert(!utf8Unescaped.IsEmpty);

            if (utf8Unescaped.Length == JsonConstants.MaximumFormatGuidLength &&
                Utf8Parser.TryParse(utf8Unescaped, out Guid tmp, out _, 'D'))
            {
                value = tmp;
                return(true);
            }

            value = default;
            return(false);
        }
Beispiel #19
0
        private static void ByteSpanToUInt32Hex_VariableLength()
        {
            int textLength = s_UInt32TextArrayHex.Length;

            byte[][] utf8ByteArray = (byte[][])Array.CreateInstance(typeof(byte[]), textLength);
            for (var i = 0; i < textLength; i++)
            {
                utf8ByteArray[i] = Encoding.UTF8.GetBytes(s_UInt32TextArrayHex[i]);
            }
            foreach (BenchmarkIteration iteration in Benchmark.Iterations)
            {
                using (iteration.StartMeasurement())
                {
                    for (int i = 0; i < Benchmark.InnerIterationCount; i++)
                    {
                        ReadOnlySpan <byte> utf8ByteSpan = utf8ByteArray[i % textLength];
                        Utf8Parser.TryParse(utf8ByteSpan, out uint value, out int bytesConsumed, 'X');
                        TestHelpers.DoNotIgnore(value, bytesConsumed);
                    }
                }
            }
        }
        private static bool TryParseTimeSpanField(ReadOnlySpan <byte> corpus, out TimeSpan timeSpan, out int bytesConsumed)
        {
            BackendMetricsTokenizer.TokenType equalsDelimiterToken = BackendMetricsTokenizer.Read(corpus);
            if (equalsDelimiterToken != BackendMetricsTokenizer.TokenType.EqualDelimiter)
            {
                timeSpan      = default;
                bytesConsumed = default;
                return(false);
            }

            corpus = corpus.Slice(1);
            if (!Utf8Parser.TryParse(corpus, out double milliseconds, out bytesConsumed))
            {
                timeSpan = default;
                return(false);
            }

            // Can not use TimeSpan.FromMilliseconds since double has a loss of precision
            timeSpan = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * milliseconds));
            bytesConsumed++;
            return(true);
        }
Beispiel #21
0
        private static List <int> GetIdsFromMem(ReadOnlyMemory <byte> content)
        {
            byte utfComma = 0x2C;
            var  ids      = new List <int>();
            ReadOnlySpan <byte> localContent = content.Span.Slice(1, content.Length - 2);
            ReadOnlySpan <byte> currentSlice = localContent.Slice(0);
            int position = 0, commaPosition = localContent.IndexOf(utfComma);
            int counter = 0;

            while (commaPosition >= 0)
            {
                if (Utf8Parser.TryParse(currentSlice.Slice(position, commaPosition), out int id, out _))
                {
                    ids.Add(id);
                }
                position      = commaPosition + 1;
                currentSlice  = currentSlice.Slice(position);
                commaPosition = currentSlice.IndexOf(utfComma);
                counter++;
            }
            return(ids);
        }
Beispiel #22
0
        public override byte Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;

                if (Utf8Parser.TryParse(span, out byte number, out var bytesConsumed) && span.Length == bytesConsumed)
                {
                    return(number);
                }

                var jsonValue = reader.GetString();

                jsonValue = jsonValue.Replace("$", string.Empty);

                var value = Convert.ToByte(jsonValue, 16);

                return(value);
            }

            return(reader.GetByte());
        }
Beispiel #23
0
        public static bool TryGetEscapedGuid(ReadOnlySpan <byte> span, out Guid value)
        {
            Debug.Assert(span.Length <= JsonConstants.MaximumEscapedGuidLength);

            int idx = span.IndexOf(JsonConstants.BackSlash);

            Debug.Assert(idx != -1);

            Span <byte> utf8Unescaped = stackalloc byte[span.Length];

            Unescape(span, utf8Unescaped, idx, out int written);
            Debug.Assert(written > 0);

            utf8Unescaped = utf8Unescaped.Slice(0, written);
            Debug.Assert(!utf8Unescaped.IsEmpty);

            if (utf8Unescaped.Length != JsonConstants.MaximumFormatGuidLength)
            {
                value = default;
                return(false);
            }
            return(Utf8Parser.TryParse(utf8Unescaped, out value, out int bytesConsumed, 'D') && utf8Unescaped.Length == bytesConsumed);
        }
        private unsafe bool TryParseSlow(out bool value)
        {
            const int           MaxLength = 5;
            ReadOnlySpan <byte> unread    = UnreadSpan;

            if (unread.Length > MaxLength)
            {
                // Fast path had enough space but couldn't find valid data
                value = default;
                return(false);
            }

            byte *      buffer   = stackalloc byte[MaxLength];
            Span <byte> tempSpan = new Span <byte>(buffer, MaxLength);

            if (Utf8Parser.TryParse(PeekSlow(tempSpan), out value, out int consumed))
            {
                Advance(consumed);
                return(true);
            }

            return(false);
        }
Beispiel #25
0
        internal bool TryGetValue(int index, out double value)
        {
            JsonRow row = _parsedData.Get(index);

            CheckExpectedType(JsonTokenType.Number, row.TokenType);

            ReadOnlySpan <byte> data    = _utf8Json.Span;
            ReadOnlySpan <byte> segment = data.Slice(row.Location, row.Length);

            if (Utf8Parser.TryParse(segment, out double tmp, out int bytesConsumed) &&
                segment.Length == bytesConsumed)
            {
                value = tmp;
                return(true);
            }

#if NET5_0_OR_GREATER
            Unsafe.SkipInit(out value);
#else
            value = default;
#endif
            return(false);
        }
Beispiel #26
0
        public bool TryGet(out ulong value)
        {
            value = 0;

            if (ValueSpan.Length == 0)
            {
                return(true);
            }

            if (ValueSpan.Length > 20) // Guaranteed malformed / overflow
            {
                return(false);
            }

            if (!Utf8Parser.TryParse(ValueSpan, out value, out int bytesConsumed) || bytesConsumed != ValueSpan.Length)
            {
                return(false);
            }

            return(value == 0
                ? ValueSpan.Length == 1 && ValueSpan[0] == '0'
                : ValueSpan[0] != '0' && ValueSpan[0] != '+');
        }
Beispiel #27
0
        private void load_int()
        {
            ReadOnlySpan <byte> bytes = input.ReadLineBytes(includeLF: true);

            if (bytes.Length == 3 && bytes[2] == (byte)'\n' && bytes[0] == (byte)'0')
            {
                if (bytes[1] == (byte)'0')
                {
                    load_false();
                    return;
                }
                else if (bytes[1] == (byte)'1')
                {
                    load_true();
                    return;
                }
            }

            bytes = bytes.Slice(0, bytes.Length - 1);
            if (bytes.Length > 0 && Utf8Parser.TryParse(bytes, out int intNumber, out int bytesConsumed) && bytesConsumed == bytes.Length)
            {
                stack.add(intNumber);
            }
        public void OnStartLine(HttpMethod method, HttpVersion version, Span <byte> target, Span <byte> path, Span <byte> query, Span <byte> customMethod, bool pathEncoded)
        {
            var requestType = RequestType.NotRecognized;

            if (method == HttpMethod.Get)
            {
                var pathLength = path.Length;
                if (Paths.SingleQuery.Length <= pathLength && path.StartsWith(Paths.SingleQuery))
                {
                    requestType = RequestType.SingleQuery;
                }
                else if (Paths.Json.Length <= pathLength && path.StartsWith(Paths.Json))
                {
                    requestType = RequestType.Json;
                }
                else if (Paths.Fortunes.Length <= pathLength && path.StartsWith(Paths.Fortunes))
                {
                    requestType = RequestType.Fortunes;
                }
                else if (Paths.Plaintext.Length <= pathLength && path.StartsWith(Paths.Plaintext))
                {
                    requestType = RequestType.PlainText;
                }
                else if (Paths.MultipleQueries.Length <= pathLength && path.StartsWith(Paths.MultipleQueries))
                {
                    if (!Utf8Parser.TryParse(path.Slice(Paths.MultipleQueries.Length), out int queries, out _) || queries < 1)
                    {
                        queries = 1;
                    }
                    else if (queries > 500)
                    {
                        queries = 500;
                    }
                    _queries    = queries;
                    requestType = RequestType.MultipleQueries;
                }
            }
Beispiel #29
0
        private void load_int()
        {
            int    len = PickleUtils.readline_into(input, ref byteBuffer, includeLF: true);
            object val;

            if (len == 3 && byteBuffer[2] == (byte)'\n' && byteBuffer[0] == (byte)'0')
            {
                if (byteBuffer[1] == (byte)'0')
                {
                    load_false();
                    return;
                }
                else if (byteBuffer[1] == (byte)'1')
                {
                    load_true();
                    return;
                }
            }

            len--;
            if (len > 0 && Utf8Parser.TryParse(byteBuffer.AsSpan(0, len), out int intNumber, out int bytesConsumed) && bytesConsumed == len)
            {
                val = intNumber;
            }
Beispiel #30
0
        public static IEnumerable <TestData> Load()
        {
            var list = new List <TestData>();

            using (var f = File.OpenRead("test.csv"))
            {
                Span <byte>         initialBuffer = stackalloc byte[512];
                Span <int>          indexBuffer   = stackalloc int[4];
                ReadOnlySpan <byte> delimiter     = stackalloc[] { (byte)',' };

                var reader = new LineReader(f, initialBuffer);

                var line = reader.ReadLine();
                while (true)
                {
                    line = reader.ReadLine();
                    if (line.IsEmpty)
                    {
                        break;
                    }

                    var items = new Splitter(line, indexBuffer, delimiter);
                    list.Add(new TestData
                    {
                        a = GetString(items[0]),
                        b = GetString(items[1]),
                        x = GetDouble(items[2]),
                        y = GetDouble(items[3]),
                    });
                }
            }
            return(list);

            string GetString(ReadOnlySpan <byte> s) => Encoding.UTF8.GetString(s);
            double GetDouble(ReadOnlySpan <byte> s) => Utf8Parser.TryParse(s, out double value, out _) ? value : 0;
        }