private static void WriteCore(ArrayBufferWriter <byte> output, object value, Type type, JsonSerializerOptions options)
        {
            Debug.Assert(type != null || value == null);

            var writerState = new JsonWriterState(options.GetWriterOptions());
            var writer      = new Utf8JsonWriter(output, writerState);

            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(ref writer, -1, options, ref state);
            }

            writer.Flush(isFinalBlock: true);
        }
        private static async Task WriteAsyncCore(object value, Type type, Stream utf8Json, JsonSerializerOptions options, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                options = JsonSerializerOptions.s_defaultOptions;
            }

            JsonWriterOptions writerOptions = options.GetWriterOptions();

            using (var bufferWriter = new PooledBufferWriter <byte>(options.DefaultBufferSize))
                using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions))
                {
                    if (value == null)
                    {
                        writer.WriteNullValue();
                        writer.Flush();

#if BUILDING_INBOX_LIBRARY
                        await utf8Json.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false);
#else
                        // todo: stackalloc or pool here?
                        await utf8Json.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false);
#endif
                        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();

#if BUILDING_INBOX_LIBRARY
                        await utf8Json.WriteAsync(bufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false);
#else
                        // todo: use pool here to avod extra alloc?
                        await utf8Json.WriteAsync(bufferWriter.WrittenMemory.ToArray(), 0, bufferWriter.WrittenMemory.Length, cancellationToken).ConfigureAwait(false);
#endif
                        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(object value, Type type, Stream utf8Json, 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.
        }