private static void WriteCore(Utf8JsonWriter writer, PooledByteBufferWriter output, object value, Type type, JsonSerializerOptions options) { Debug.Assert(type != null || value == null); if (value == null) { writer.WriteNullValue(); } else { // We treat typeof(object) special and allow polymorphic behavior. if (type == typeof(object)) { type = value.GetType(); } WriteStack state = default; state.Current.Initialize(type, options); state.Current.CurrentValue = value; Write(writer, -1, options, ref state); } writer.Flush(); }
private static void WriteCore(PooledByteBufferWriter output, object?value, Type type, JsonSerializerOptions options) { using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { WriteCore(writer, value, type, options); } }
internal static JsonDocument ParseRented(PooledByteBufferWriter utf8Json, JsonDocumentOptions options = default) { return(Parse( utf8Json.WrittenMemory, options.GetReaderOptions(), extraRentedArrayPoolBytes: null, extraPooledByteBufferWriter: utf8Json)); }
private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { if (value == null) { writer.WriteNullValue(); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); return; } if (inputType == null) { inputType = value.GetType(); } WriteStack state = default; state.InitializeRoot(inputType, options, supportContinuation: true); bool isFinalBlock; do { // todo: determine best value here // https://github.com/dotnet/runtime/issues/32356 state.FlushThreshold = (int)(bufferWriter.Capacity * .9); isFinalBlock = WriteCore( writer, value, options, ref state, state.Current.JsonClassInfo !.PolicyProperty !.ConverterBase); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
public static void ReturnWriterAndBuffer(Utf8JsonWriter writer, PooledByteBufferWriter bufferWriter) { Debug.Assert(t_threadLocalState != null); ThreadLocalState state = t_threadLocalState; writer.ResetAllStateForCacheReuse(); bufferWriter.ClearAndReturnBuffers(); int rentedWriters = --state.RentedWriters; Debug.Assert((rentedWriters == 0) == (ReferenceEquals(state.BufferWriter, bufferWriter) && ReferenceEquals(state.Writer, writer))); }
private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { if (value == null) { writer.WriteNullValue(); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); return; } if (inputType == null) { inputType = value.GetType(); } WriteStack state = default; if (options.ReferenceHandling.ShouldWritePreservedReferences()) { state.ReferenceResolver = new DefaultReferenceResolver(writing: true); } state.Current.Initialize(inputType, options); state.Current.CurrentValue = value; bool isFinalBlock; int flushThreshold; do { flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here isFinalBlock = Write(writer, originalWriterDepth: 0, flushThreshold, options, ref state); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
private static async Task WriteAsyncCore <TValue>( Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { // We flush the Stream when the buffer is >=90% of capacity. // This threshold is a compromise between buffer utilization and minimizing cases where the buffer // needs to be expanded\doubled because it is not large enough to write the current property or element. // We check for flush after each object property and array element is written to the buffer. // Once the buffer is expanded to contain the largest single element\property, a 90% thresold // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375. const float FlushThreshold = .9f; if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == typeof(object) && value != null) { inputType = value !.GetType(); } WriteStack state = default; state.Initialize(inputType, options, supportContinuation: true); JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase; bool isFinalBlock; do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } }
private static string WriteCoreString(object value, Type type, JsonSerializerOptions options) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } string result; using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) { WriteCore(output, value, type, options); result = JsonReaderHelper.TranscodeHelper(output.WrittenMemory.Span); } return(result); }
private static byte[] WriteCoreBytes(object value, Type type, JsonSerializerOptions options) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } byte[] result; using (var output = new PooledByteBufferWriter(options.DefaultBufferSize)) { WriteCore(output, value, type, options); result = output.WrittenMemory.ToArray(); } return(result); }
public static Utf8JsonWriter RentWriter(JsonSerializerOptions options, PooledByteBufferWriter bufferWriter) { ThreadLocalState state = t_threadLocalState ??= new(); Utf8JsonWriter writer; if (state.RentedWriters++ == 0) { // First JsonSerializer call in the stack -- initialize & return the cached instance. writer = state.Writer; writer.Reset(bufferWriter, options.GetWriterOptions()); } else { // We're in a recursive JsonSerializer call -- return a fresh instance. writer = new Utf8JsonWriter(bufferWriter, options.GetWriterOptions()); } return(writer); }
private static TValue?ReadNode <TValue>(JsonNode?node, JsonTypeInfo jsonTypeInfo) { JsonSerializerOptions options = jsonTypeInfo.Options; // For performance, share the same buffer across serialization and deserialization. using var output = new PooledByteBufferWriter(options.DefaultBufferSize); using (var writer = new Utf8JsonWriter(output, options.GetWriterOptions())) { if (node is null) { writer.WriteNullValue(); } else { node.WriteTo(writer, options); } } return(ReadFromSpan <TValue>(output.WrittenMemory.Span, jsonTypeInfo)); }
private static async Task WriteAsyncCore <TValue>(Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == typeof(object) && value != null) { inputType = value !.GetType(); } WriteStack state = default; state.Initialize(inputType, options, supportContinuation: true); JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase; bool isFinalBlock; do { // todo: determine best value here // https://github.com/dotnet/runtime/issues/32356 state.FlushThreshold = (int)(bufferWriter.Capacity * .9); isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
private static async Task WriteAsyncCore <TValue>( Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { // We flush the Stream when the buffer is >=90% of capacity. // This threshold is a compromise between buffer utilization and minimizing cases where the buffer // needs to be expanded\doubled because it is not large enough to write the current property or element. // We check for flush after each object property and array element is written to the buffer. // Once the buffer is expanded to contain the largest single element\property, a 90% thresold // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375. const float FlushThreshold = .9f; if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == JsonTypeInfo.ObjectType && value != null) { inputType = value !.GetType(); } WriteStack state = new WriteStack { CancellationToken = cancellationToken }; JsonConverter converterBase = state.Initialize(inputType, options, supportContinuation: true); bool isFinalBlock; try { do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); try { isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); } finally { if (state.PendingAsyncDisposables?.Count > 0) { await state.DisposePendingAsyncDisposables().ConfigureAwait(false); } } await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); if (state.PendingTask is not null) { try { await state.PendingTask.ConfigureAwait(false); } catch { // Exceptions will be propagated elsewhere // TODO https://github.com/dotnet/runtime/issues/22144 } } } while (!isFinalBlock); } catch { await state.DisposePendingDisposablesOnExceptionAsync().ConfigureAwait(false); throw; } } }
private static async Task WriteStreamAsync <TValue>( Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) { JsonSerializerOptions options = jsonTypeInfo.Options; JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { WriteStack state = new WriteStack { CancellationToken = cancellationToken }; JsonConverter converter = state.Initialize(jsonTypeInfo, supportContinuation: true); bool isFinalBlock; try { do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); try { isFinalBlock = WriteCore(converter, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } finally { // Await any pending resumable converter tasks (currently these can only be IAsyncEnumerator.MoveNextAsync() tasks). // Note that pending tasks are always awaited, even if an exception has been thrown or the cancellation token has fired. if (state.PendingTask is not null) { try { await state.PendingTask.ConfigureAwait(false); } catch { // Exceptions should only be propagated by the resuming converter // TODO https://github.com/dotnet/runtime/issues/22144 } } // Dispose any pending async disposables (currently these can only be completed IAsyncEnumerators). if (state.CompletedAsyncDisposables?.Count > 0) { await state.DisposeCompletedAsyncDisposables().ConfigureAwait(false); } } } while (!isFinalBlock); } catch { // On exception, walk the WriteStack for any orphaned disposables and try to dispose them. await state.DisposePendingDisposablesOnExceptionAsync().ConfigureAwait(false); throw; } } }
public ThreadLocalState() { BufferWriter = PooledByteBufferWriter.CreateEmptyInstanceForCaching(); Writer = Utf8JsonWriter.CreateEmptyInstanceForCaching(); }