private static async ValueTask <Int32> PerformWriteJSONTTokenAsync( StreamWriterWithResizableBuffer stream, IEncodingInfo encoding, JToken jsonValue ) { ArgumentValidator.ValidateNotNull(nameof(jsonValue), jsonValue); Int32 bytesWritten; var asciiSize = encoding.BytesPerASCIICharacter; Int32 max; (Int32 Offset, Int32 Count)range; switch (jsonValue) { case JArray array: range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)ARRAY_START); bytesWritten = range.Count; max = array.Count; if (max > 0) { for (var i = 0; i < max; ++i) { bytesWritten += await PerformWriteJSONTTokenAsync(stream, encoding, array[i]); if (i < max - 1) { range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)ARRAY_VALUE_DELIM); bytesWritten += range.Count; } } } range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)ARRAY_END); bytesWritten += await stream.FlushAsync(); break; case JObject obj: range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)OBJ_START); bytesWritten = range.Count; max = obj.Count; if (max > 0) { var j = 0; foreach (var kvp in obj) { bytesWritten += WriteJSONString(stream, encoding, kvp.Key); range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)OBJ_KEY_VALUE_DELIM); bytesWritten += range.Count; await stream.FlushAsync(); bytesWritten += await PerformWriteJSONTTokenAsync(stream, encoding, kvp.Value); if (++j < max) { range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)OBJ_VALUE_DELIM); bytesWritten += range.Count; } } } range = stream.ReserveBufferSegment(asciiSize); encoding.WriteASCIIByte(stream.Buffer, ref range.Offset, (Byte)OBJ_END); bytesWritten += await stream.FlushAsync(); break; case JValue value: var val = value.Value; switch (val) { case String str: bytesWritten = WriteJSONString(stream, encoding, str); break; case Boolean boolean: // Write 'true' or 'false' range = stream.ReserveBufferSegment(boolean ? 4 : 5); encoding.WriteString(stream.Buffer, ref range.Offset, boolean ? "true" : "false"); bytesWritten = range.Count; break; case Int64 i64: range = stream.ReserveBufferSegment(encoding.GetTextualIntegerRepresentationSize(i64)); encoding.WriteIntegerTextual(stream.Buffer, ref range.Offset, i64); bytesWritten = range.Count; break; case Double dbl: // Have to allocate string :/ var dblStr = dbl.ToString(System.Globalization.CultureInfo.InvariantCulture); range = stream.ReserveBufferSegment(encoding.Encoding.GetByteCount(dblStr)); encoding.WriteString(stream.Buffer, ref range.Offset, dblStr); bytesWritten = range.Count; break; case null: // Write 'null' range = stream.ReserveBufferSegment(asciiSize * 4); encoding.WriteString(stream.Buffer, ref range.Offset, "null"); bytesWritten = range.Count; break; default: throw new NotSupportedException($"Unsupported primitive value {val}."); } // Remember to flush stream await stream.FlushAsync(); break; default: throw new NotSupportedException($"Unrecognized JToken type: {jsonValue?.GetType()}."); } return(bytesWritten); }
private static Int32 PerformCalculateJTokenTextSize(IEncodingInfo encoding, JToken jsonValue) { ArgumentValidator.ValidateNotNull(nameof(jsonValue), jsonValue); var asciiSize = encoding.BytesPerASCIICharacter; Int32 retVal; switch (jsonValue) { case JArray array: // '['followed by items with ',' in between them followed by ']' retVal = (2 + Math.Max(array.Count - 1, 0)) * asciiSize + array.Aggregate(0, (cur, curToken) => cur + PerformCalculateJTokenTextSize(encoding, curToken)); break; case JObject obj: // '{' followed by items with ',' in between them followed by '}' // Each item has ':' between key and value retVal = (2 + Math.Max(obj.Count - 1, 0)) * asciiSize + Enumerable.Aggregate <KeyValuePair <String, JToken>, Int32>(obj, 0, (cur, curKvp) => cur + asciiSize + CalculateJSONStringValueSize(curKvp.Key, encoding) + PerformCalculateJTokenTextSize(encoding, curKvp.Value)); break; case JValue simple: var val = simple.Value; switch (val) { case String str: retVal = CalculateJSONStringValueSize(str, encoding); break; case Boolean bol: retVal = (bol ? 4 : 5) * asciiSize; break; case Byte b: case SByte sb: case Int16 i16: case UInt16 u16: case Int32 i32: case UInt32 u32: case Int64 i64: retVal = encoding.GetTextualIntegerRepresentationSize((Int64)Convert.ChangeType(val, typeof(Int64))); break; // TODO UInt64 case Single s: case Double d: case Decimal dec: retVal = encoding.Encoding.GetByteCount(((IFormattable)val).ToString(null, System.Globalization.CultureInfo.InvariantCulture.NumberFormat)); break; case null: // Word 'null' has 4 ascii characters retVal = 4 * asciiSize; break; default: throw new NotSupportedException($"Unsupported primitive value {val}."); } break; default: throw new NotSupportedException($"Unrecognized JToken type: {jsonValue?.GetType()}."); } return(retVal); }