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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
// 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); }
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); } }
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); }