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();
        }
Example #2
0
 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);
     }
 }
Example #3
0
 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.
        }
Example #5
0
        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)));
        }
Example #6
0
        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.
        }
Example #7
0
        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);
        }
Example #10
0
        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);
        }
Example #11
0
        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.
        }
Example #13
0
        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;
                    }
                }
        }
Example #15
0
 public ThreadLocalState()
 {
     BufferWriter = PooledByteBufferWriter.CreateEmptyInstanceForCaching();
     Writer       = Utf8JsonWriter.CreateEmptyInstanceForCaching();
 }