コード例 #1
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, int value, StandardFormat standardFormat)
        {
            if (standardFormat.IsDefault)
            {
                if (value <= byte.MaxValue && value >= byte.MinValue)
                {
                    return(TryWrite(ref writer, (byte)value, standardFormat));
                }

                writer.Push((byte)EtfTokenType.Integer);
                BinaryPrimitives.WriteInt32BigEndian(writer.RequestSpan(4), value);
                writer.Advance(4);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
コード例 #2
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, char value)
        {
            ReadOnlySpan <char> chars = stackalloc char[] { value };
            var charBytes             = MemoryMarshal.AsBytes(chars);

            if (Encodings.Utf16.ToUtf8Length(charBytes, out var length) != OperationStatus.Done)
            {
                return(false);
            }
            var data = writer.Pool.Rent(length);

            try
            {
                if (Encodings.Utf16.ToUtf8(charBytes, data, out _, out _) != OperationStatus.Done)
                {
                    return(false);
                }

                writer.Push((byte)'\"');
                if (!TryWriteUtf8Bytes(ref writer, data.AsSpan(0, length)))
                {
                    return(false);
                }
                writer.Push((byte)'\"');
            }
            finally
            {
                writer.Pool.Return(data);
            }
            return(true);
        }
コード例 #3
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, Dictionary <string, T> value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(JsonWriter.TryWriteNull(ref writer));
            }

            writer.Push((byte)'{');
            bool isFirst = true;

            foreach (var pair in value)
            {
                if (!isFirst)
                {
                    writer.Push((byte)',');
                }
                else
                {
                    isFirst = false;
                }
                if (!JsonWriter.TryWrite(ref writer, pair.Key))
                {
                    return(false);
                }
                writer.Push((byte)':');
                if (!_innerConverter.TryWrite(ref writer, pair.Value, propMap))
                {
                    return(false);
                }
            }
            writer.Push((byte)'}');
            return(true);
        }
コード例 #4
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, T[] value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.List);
            writer.Advance(4);

            uint count = 0;

            for (int i = 0; i < value.Length; i++)
            {
                if (!_innerConverter.CanWrite(value[i], propMap))
                {
                    continue;
                }
                if (!_innerConverter.TryWrite(ref writer, value[i], propMap))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;

            writer.Push((byte)EtfTokenType.Nil); // Tail
            return(true);
        }
コード例 #5
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, Utf8Span value)
 {
     writer.Push((byte)'\"');
     if (!TryWriteUtf8Bytes(ref writer, value.Bytes))
     {
         return(false);
     }
     writer.Push((byte)'\"');
     return(true);
 }
コード例 #6
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, DateTimeOffset value, StandardFormat standardFormat)
 {
     writer.Push((byte)'"');
     if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
     {
         return(false);
     }
     writer.Push((byte)'"');
     return(true);
 }
コード例 #7
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, decimal value, StandardFormat standardFormat = default)
 {
     writer.Push((byte)'"');
     if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
     {
         return(false);
     }
     writer.Push((byte)'"');
     return(true);
 }
コード例 #8
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, long value, StandardFormat standardFormat)
        {
            if (standardFormat.IsDefault)
            {
                if (value <= byte.MaxValue && value >= byte.MinValue)
                {
                    return(TryWrite(ref writer, (byte)value, standardFormat));
                }
                if (value <= int.MaxValue && value >= int.MinValue)
                {
                    return(TryWrite(ref writer, (int)value, standardFormat));
                }

                writer.Push((byte)EtfTokenType.SmallBig);
                writer.Push(8);
                if (value >= 0)
                {
                    writer.Push(0);
                    BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), (ulong)value);
                }
                else
                {
                    writer.Push(1);
                    if (value == long.MinValue)
                    {
                        BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), 9223372036854775808);
                    }
                    else
                    {
                        BinaryPrimitives.WriteUInt64LittleEndian(writer.RequestSpan(8), (ulong)-value);
                    }
                }
                writer.Advance(8);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
コード例 #9
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, bool value, StandardFormat standardFormat)
 {
     if (standardFormat.IsDefault)
     {
         if (value)
         {
             _trueValue.Span.CopyTo(writer.RequestSpan(6));
             writer.Advance(6);
         }
         else
         {
             _falseValue.Span.CopyTo(writer.RequestSpan(7));
             writer.Advance(7);
         }
     }
     else
     {
         int start = writer.Length;
         writer.Push((byte)EtfTokenType.Binary);
         writer.Advance(4);
         if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
         {
             return(false);
         }
         int length = writer.Length - start - 5;
         writer.Array[start + 1] = (byte)(length >> 24);
         writer.Array[start + 2] = (byte)(length >> 16);
         writer.Array[start + 3] = (byte)(length >> 8);
         writer.Array[start + 4] = (byte)length;
     }
     return(true);
 }
コード例 #10
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, bool value, StandardFormat standardFormat = default)
 {
     if (standardFormat.IsDefault)
     {
         if (!Utf8Writer.TryWrite(ref writer, value, JsonSerializer.BooleanFormat.Symbol))
         {
             return(false);
         }
     }
     else
     {
         writer.Push((byte)'"');
         if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
         {
             return(false);
         }
         writer.Push((byte)'"');
     }
     return(true);
 }
コード例 #11
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, float value, StandardFormat standardFormat = default)
 {
     if (standardFormat.IsDefault && !float.IsInfinity(value) && !float.IsNaN(value))
     {
         if (!Utf8Writer.TryWrite(ref writer, value, JsonSerializer.FloatFormat.Symbol))
         {
             return(false);
         }
     }
     else
     {
         writer.Push((byte)'"');
         if (!Utf8Writer.TryWrite(ref writer, value, !standardFormat.IsDefault ? standardFormat : JsonSerializer.FloatFormat.Symbol))
         {
             return(false);
         }
         writer.Push((byte)'"');
     }
     return(true);
 }
コード例 #12
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, List <T> value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(JsonWriter.TryWriteNull(ref writer));
            }

            writer.Push((byte)'[');
            for (int i = 0; i < value.Count; i++)
            {
                if (i != 0)
                {
                    writer.Push((byte)',');
                }
                if (!_innerConverter.TryWrite(ref writer, value[i], propMap))
                {
                    return(false);
                }
            }
            writer.Push((byte)']');
            return(true);
        }
コード例 #13
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, float value, StandardFormat standardFormat)
        {
            // TODO: Untested, does Discord have any endpoints that accept floats?
            if (standardFormat.IsDefault)
            {
                writer.Push((byte)EtfTokenType.NewFloat);

                // Swap endian
                Span <double> src      = stackalloc double[] { value };
                var           srcBytes = MemoryMarshal.AsBytes(src);
                var           dst      = writer.RequestSpan(8);

                dst[0] = srcBytes[7];
                dst[1] = srcBytes[6];
                dst[2] = srcBytes[5];
                dst[3] = srcBytes[4];
                dst[4] = srcBytes[3];
                dst[5] = srcBytes[2];
                dst[6] = srcBytes[1];
                dst[7] = srcBytes[0];
                writer.Advance(8);
            }
            else
            {
                int start = writer.Length;
                writer.Push((byte)EtfTokenType.Binary);
                writer.Advance(4);
                if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
                {
                    return(false);
                }
                int length = writer.Length - start - 5;
                writer.Array[start + 1] = (byte)(length >> 24);
                writer.Array[start + 2] = (byte)(length >> 16);
                writer.Array[start + 3] = (byte)(length >> 8);
                writer.Array[start + 4] = (byte)length;
            }
            return(true);
        }
コード例 #14
0
 public static bool TryWrite(ref ResizableMemory <byte> writer, byte value, StandardFormat standardFormat)
 {
     if (standardFormat.IsDefault)
     {
         writer.Push((byte)EtfTokenType.SmallInteger);
         writer.Push(value);
     }
     else
     {
         int start = writer.Length;
         writer.Push((byte)EtfTokenType.Binary);
         writer.Advance(4);
         if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
         {
             return(false);
         }
         int length = writer.Length - start - 5;
         writer.Array[start + 1] = (byte)(length >> 24);
         writer.Array[start + 2] = (byte)(length >> 16);
         writer.Array[start + 3] = (byte)(length >> 8);
         writer.Array[start + 4] = (byte)length;
     }
     return(true);
 }
コード例 #15
0
        public static bool TryWriteUtf8Bytes(ref ResizableMemory <byte> writer, ReadOnlySpan <byte> value)
        {
            if (value.Length > ushort.MaxValue)
            {
                return(false);
            }

            writer.Push((byte)EtfTokenType.Binary);
            BinaryPrimitives.WriteUInt32BigEndian(writer.RequestSpan(4), (uint)value.Length);
            writer.Advance(4);
            if (!Utf8Writer.TryWriteString(ref writer, value))
            {
                return(false);
            }
            return(true);
        }
コード例 #16
0
        public static bool TryWrite(ref ResizableMemory <byte> writer, DateTimeOffset value, StandardFormat standardFormat)
        {
            int start = writer.Length;

            writer.Push((byte)EtfTokenType.Binary);
            writer.Advance(4);
            if (!Utf8Writer.TryWrite(ref writer, value, standardFormat))
            {
                return(false);
            }
            int length = writer.Length - start - 5;

            writer.Array[start + 1] = (byte)(length >> 24);
            writer.Array[start + 2] = (byte)(length >> 16);
            writer.Array[start + 3] = (byte)(length >> 8);
            writer.Array[start + 4] = (byte)length;
            return(true);
        }
コード例 #17
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, T value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.Map);
            writer.Advance(4);

            uint count      = 0;
            var  properties = _map.Properties;

            for (int i = 0; i < properties.Count; i++)
            {
                var key          = properties[i].Key;
                var innerPropMap = properties[i].Value as PropertyMap <T>;
                if (!innerPropMap.CanWrite(value))
                {
                    continue;
                }

                if (!EtfWriter.TryWriteUtf8Key(ref writer, key.Span))
                {
                    return(false);
                }
                if (!innerPropMap.TryWrite(value, ref writer))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;
            return(true);
        }
コード例 #18
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, T value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(JsonWriter.TryWriteNull(ref writer));
            }

            writer.Push((byte)'{');
            bool isFirst = true;

            var properties = _map.Properties;

            for (int i = 0; i < properties.Count; i++)
            {
                var key          = properties[i].Key;
                var innerPropMap = properties[i].Value as PropertyMap <T>;
                if (!innerPropMap.CanWrite(value))
                {
                    continue;
                }

                if (!isFirst)
                {
                    writer.Push((byte)',');
                }
                else
                {
                    isFirst = false;
                }

                writer.Push((byte)'"');
                if (!JsonWriter.TryWriteUtf8Bytes(ref writer, key.Span))
                {
                    return(false);
                }
                writer.Push((byte)'"');

                writer.Push((byte)':');
                if (!innerPropMap.TryWrite(value, ref writer))
                {
                    return(false);
                }
            }
            writer.Push((byte)'}');
            return(true);
        }
コード例 #19
0
        public override bool TryWrite(ref ResizableMemory <byte> writer, Dictionary <string, T> value, PropertyMap propMap = null)
        {
            if (value == null)
            {
                return(EtfWriter.TryWriteNull(ref writer));
            }

            var start = writer.Length;

            writer.Push((byte)EtfTokenType.Map);
            writer.Advance(4);

            uint count = 0;

            foreach (var pair in value)
            {
                if (!_innerConverter.CanWrite(pair.Value, propMap))
                {
                    continue;
                }

                if (!EtfWriter.TryWriteUtf16Key(ref writer, pair.Key))
                {
                    return(false);
                }
                if (!_innerConverter.TryWrite(ref writer, pair.Value, propMap))
                {
                    return(false);
                }
                count++;
            }

            writer.Array[start + 1] = (byte)(count >> 24);
            writer.Array[start + 2] = (byte)(count >> 16);
            writer.Array[start + 3] = (byte)(count >> 8);
            writer.Array[start + 4] = (byte)count;
            return(true);
        }
コード例 #20
0
        public static bool TryWriteUtf8Bytes(ref ResizableMemory <byte> writer, ReadOnlySpan <byte> value)
        {
            int i     = 0;
            int start = 0;

            for (; i < value.Length; i++)
            {
                byte b = value[i];

                // Special chars
                switch (b)
                {
                case (byte)'"':
                case (byte)'\\':
                    //case (byte)'/':
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, bytes).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    writer.Push((byte)'\\');
                    writer.Push(b);

                    start = i + 1;
                    continue;
                }


                if (b < 32) // Control codes
                {
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, bytes).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    switch (b)
                    {
                    case (byte)'\b':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'b');
                        break;

                    case (byte)'\f':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'f');
                        break;

                    case (byte)'\n':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'n');
                        break;

                    case (byte)'\r':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'r');
                        break;

                    case (byte)'\t':
                        writer.Push((byte)'\\');
                        writer.Push((byte)'t');
                        break;

                    default:
                        var escape = writer.RequestSpan(6);
                        escape[0] = (byte)'\\';
                        escape[1] = (byte)'u';
                        escape[2] = (byte)'0';
                        escape[3] = (byte)'0';
                        escape[4] = ToHex((byte)(b >> 4));
                        escape[5] = ToHex((byte)(b & 0xF));
                        writer.Advance(6);
                        break;
                    }
                    start = i + 1;
                }
                else if (b >= 192) // Multi-byte chars
                {
                    if (i != start)
                    {
                        int bytes  = i - start;
                        var buffer = writer.RequestSpan(bytes);
                        value.Slice(start, i - start).CopyTo(buffer);
                        writer.Advance(bytes);
                    }
                    int seqStart = i;
                    int length   = 1;
                    for (; length < 4 && i < value.Length - 1 && value[i + 1] >= 128; length++, i++)
                    {
                    }

                    Span <ushort> utf16Value = stackalloc ushort[2];
                    if (Encodings.Utf8.ToUtf16(value.Slice(seqStart, length), MemoryMarshal.AsBytes(utf16Value), out _, out int bytesWritten) != OperationStatus.Done)
                    {
                        return(false);
                    }

                    for (int j = 0; j < bytesWritten / 2; j++)
                    {
                        var buffer2 = writer.RequestSpan(6);
                        buffer2[0] = (byte)'\\';
                        buffer2[1] = (byte)'u';
                        buffer2[2] = ToHex((byte)((utf16Value[j] >> 12) & 0xF));
                        buffer2[3] = ToHex((byte)((utf16Value[j] >> 8) & 0xF));
                        buffer2[4] = ToHex((byte)((utf16Value[j] >> 4) & 0xF));
                        buffer2[5] = ToHex((byte)(utf16Value[j] & 0xF));
                        writer.Advance(6);
                    }

                    start = i + 1;
                }
                else if (b >= 128) // Multi-byte chars out of sequence
                {
                    return(false);
                }
            }
            // Append last part to builder
            if (i != start)
            {
                int bytes  = i - start;
                var buffer = writer.RequestSpan(bytes);
                value.Slice(start, bytes).CopyTo(buffer);
                writer.Advance(bytes);
            }
            return(true);
        }
コード例 #21
0
        // TODO: Add tests
        public static bool Skip(ref ReadOnlySpan <byte> remaining, out ReadOnlySpan <byte> skipped)
        {
            skipped = default;

            var stack        = new ResizableMemory <byte>(32);
            var currentToken = JsonTokenType.None;

            int  i       = 0;
            bool success = false;

            for (; i < remaining.Length || currentToken != JsonTokenType.None;)
            {
                // If we skipped an element and returned to the top-most level, stop skipping
                if (success && currentToken == JsonTokenType.None)
                {
                    break;
                }

                byte c = remaining[i];
                switch (c)
                {
                case (byte)' ':     // Whitespace
                case (byte)'\n':
                case (byte)'\r':
                case (byte)'\t':
                    i++;
                    continue;

                case (byte)'{':
                    i++;
                    stack.Push((byte)currentToken);
                    currentToken = JsonTokenType.StartObject;
                    break;

                case (byte)'}':
                    if (currentToken != JsonTokenType.StartObject)
                    {
                        return(false);
                    }
                    i++;
                    currentToken = (JsonTokenType)stack.Pop();
                    success      = true;
                    break;

                case (byte)'[':
                    i++;
                    stack.Push((byte)currentToken);
                    currentToken = JsonTokenType.StartArray;
                    break;

                case (byte)']':
                    if (currentToken != JsonTokenType.StartArray)
                    {
                        return(false);
                    }
                    i++;
                    currentToken = (JsonTokenType)stack.Pop();
                    success      = true;
                    break;

                case (byte)',':
                    if (currentToken != JsonTokenType.StartObject && currentToken != JsonTokenType.StartArray)
                    {
                        return(false);
                    }
                    i++;
                    break;

                case (byte)':':
                    if (currentToken != JsonTokenType.StartObject)
                    {
                        return(false);
                    }
                    i++;
                    break;

                case (byte)'n':
                    i      += 4; // ull
                    success = true;
                    break;

                case (byte)'t':
                    i      += 4; // rue
                    success = true;
                    break;

                case (byte)'f':
                    i      += 5; // alse
                    success = true;
                    break;

                case (byte)'"':
                    i++;
                    bool incomplete = true;
                    while (i < remaining.Length)
                    {
                        switch (remaining[i])
                        {
                        case (byte)'\\':
                            i += 2;         // Skip next char
                            continue;

                        case (byte)'"':
                            i++;
                            incomplete = false;
                            break;

                        default:
                            i++;
                            continue;
                        }
                        break;
                    }
                    if (incomplete)
                    {
                        return(false);
                    }
                    success = true;
                    break;

                case (byte)'-':
                case (byte)'0':
                case (byte)'1':
                case (byte)'2':
                case (byte)'3':
                case (byte)'4':
                case (byte)'5':
                case (byte)'6':
                case (byte)'7':
                case (byte)'8':
                case (byte)'9':
                    i++;
                    while (i < remaining.Length)
                    {
                        switch (remaining[i])
                        {
                        case (byte)'+':
                        case (byte)'-':
                        case (byte)'.':
                        case (byte)'0':
                        case (byte)'1':
                        case (byte)'2':
                        case (byte)'3':
                        case (byte)'4':
                        case (byte)'5':
                        case (byte)'6':
                        case (byte)'7':
                        case (byte)'8':
                        case (byte)'9':
                        case (byte)'e':
                        case (byte)'E':
                            i++;
                            continue;

                        default:         // Crossed into next token
                            break;
                        }
                        break;
                    }
                    success = true;
                    break;

                default:
                    return(false);
                }
            }

            // Incomplete object/array
            if (currentToken != JsonTokenType.None)
            {
                return(false);
            }
            skipped   = remaining.Slice(0, i);
            remaining = remaining.Slice(i);
            return(true);
        }
コード例 #22
0
        public static bool TryRead <T>(JsonSerializer serializer, ref ReadOnlySpan <byte> remaining, out ResizableMemory <T> result,
                                       PropertyMap propMap, ValueConverter <T> innerConverter, ArrayPool <T> pool)
        {
            result = default;

            switch (JsonReader.GetTokenType(ref remaining))
            {
            case JsonTokenType.StartArray:
                break;

            case JsonTokenType.Null:
                remaining = remaining.Slice(4);
                result    = default;
                return(true);

            default:
                return(false);
            }
            remaining = remaining.Slice(1);

            if (JsonReader.GetTokenType(ref remaining) == JsonTokenType.EndArray)
            {
                result    = new ResizableMemory <T>(0, pool);
                remaining = remaining.Slice(1);
                return(true);
            }

            result = new ResizableMemory <T>(8, pool);
            for (int i = 0; ; i++)
            {
                switch (JsonReader.GetTokenType(ref remaining))
                {
                case JsonTokenType.None:
                    return(false);

                case JsonTokenType.EndArray:
                    remaining = remaining.Slice(1);
                    return(true);

                case JsonTokenType.ListSeparator:
                    if (i == 0)
                    {
                        return(false);
                    }
                    remaining = remaining.Slice(1);
                    break;

                default:
                    if (i != 0)
                    {
                        return(false);
                    }
                    break;
                }

                var restore = remaining;
                if (!innerConverter.TryRead(ref remaining, out var item, propMap))
                {
                    if (propMap?.IgnoreErrors == true)
                    {
                        remaining = restore;
                        if (!JsonReader.Skip(ref remaining, out _))
                        {
                            return(false);
                        }
                        serializer.RaiseFailedProperty(propMap, i);
                    }
                    else
                    {
                        return(false);
                    }
                }
                result.Push(item);
            }
        }
コード例 #23
0
 public override void Write <T>(T value, ref ResizableMemory <byte> writer, ValueConverter <T> converter = null)
 {
     writer.Push(131); // Version
     base.Write(value, ref writer, converter);
 }