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); } }
private static void WriteCore(PooledByteBufferWriter output, object value, Type type, JsonSerializerOptions options) { Debug.Assert(type != null || value == null); using var writer = new Utf8JsonWriter(output, options.GetWriterOptions()); 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(); }
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 async Task WriteAsyncCore(Stream utf8Json, object value, Type type, 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 (type == null) { type = value.GetType(); } WriteStack state = default; state.Current.Initialize(type, options); state.Current.CurrentValue = value; bool isFinalBlock; int flushThreshold; do { flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here isFinalBlock = Write(writer, 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 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 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; } } }