Add WritePropertyName standlone API on the Utf8JsonWriter. (dotnet/corefx#38864)
authorAhson Khan <ahkha@microsoft.com>
Tue, 25 Jun 2019 22:07:36 +0000 (15:07 -0700)
committermsftbot[bot] <48340428+msftbot[bot]@users.noreply.github.com>
Tue, 25 Jun 2019 22:07:36 +0000 (22:07 +0000)
* Add WritePropertyName standlone API on the Utf8JsonWriter.

* Fix write indented, add more tests, and more debug.asserts.

* Remove _isProperty field and rely on _tokenType ==
JsonTokenType.PropertyName

* Auto-gen the ref.

* Address PR feedback.

Commit migrated from https://github.com/dotnet/corefx/commit/a5b35f5600b615d4f30c64183891c83fd76bf491

31 files changed:
src/libraries/System.Text.Json/ref/System.Text.Json.cs
src/libraries/System.Text.Json/src/Resources/Strings.resx
src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Bytes.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTime.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.DateTimeOffset.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Decimal.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Double.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Float.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Guid.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Helpers.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.Literal.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.SignedNumber.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.String.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteProperties.UnsignedNumber.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Bytes.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Comment.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTime.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.DateTimeOffset.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Decimal.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Double.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Float.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.FormattedNumber.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Guid.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Helpers.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.Literal.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.SignedNumber.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.String.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.WriteValues.UnsignedNumber.cs
src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs
src/libraries/System.Text.Json/tests/Utf8JsonWriterTests.cs

index db2d1dc..2f2d95a 100644 (file)
@@ -387,6 +387,10 @@ namespace System.Text.Json
         public void WriteNumberValue(uint value) { }
         [System.CLSCompliantAttribute(false)]
         public void WriteNumberValue(ulong value) { }
+        public void WritePropertyName(System.ReadOnlySpan<byte> utf8PropertyName) { }
+        public void WritePropertyName(System.ReadOnlySpan<char> propertyName) { }
+        public void WritePropertyName(string propertyName) { }
+        public void WritePropertyName(System.Text.Json.JsonEncodedText propertyName) { }
         public void WriteStartArray() { }
         public void WriteStartArray(System.ReadOnlySpan<byte> utf8PropertyName) { }
         public void WriteStartArray(System.ReadOnlySpan<char> propertyName) { }
index f1130f1..0f3a949 100644 (file)
   <data name="CannotWritePropertyWithinArray" xml:space="preserve">
     <value>Cannot write a JSON property within an array or as the first JSON token. Current token type is '{0}'.</value>
   </data>
+  <data name="CannotWritePropertyAfterProperty" xml:space="preserve">
+    <value>Cannot write a JSON property name following another property name. A JSON value is missing.</value>
+  </data>
   <data name="CannotWriteValueAfterPrimitive" xml:space="preserve">
     <value>Cannot write a JSON value after a single JSON value. Current token type is '{0}'.</value>
   </data>
   <data name="MismatchedObjectArray" xml:space="preserve">
     <value>'{0}' is invalid without a matching open.</value>
   </data>
+  <data name="CannotWriteEndAfterProperty" xml:space="preserve">
+    <value>'{0}' is invalid following a property name.</value>
+  </data>
   <data name="ObjectDepthTooLarge" xml:space="preserve">
     <value>The maximum configured depth of {0} has been exceeded. Cannot read next JSON object.</value>
   </data>
index 0d52361..73279c9 100644 (file)
@@ -472,7 +472,9 @@ namespace System.Text.Json
             {
                 case ExceptionResource.MismatchedObjectArray:
                     Debug.Assert(token == JsonConstants.CloseBracket || token == JsonConstants.CloseBrace);
-                    message = SR.Format(SR.MismatchedObjectArray, (char)token);
+                    message = (tokenType == JsonTokenType.PropertyName) ?
+                        SR.Format(SR.CannotWriteEndAfterProperty, (char)token) :
+                        SR.Format(SR.MismatchedObjectArray, (char)token);
                     break;
                 case ExceptionResource.DepthTooLarge:
                     message = SR.Format(SR.DepthTooLarge, currentDepth & JsonConstants.RemoveFlagsBitMask, JsonConstants.MaxWriterDepth);
@@ -487,7 +489,9 @@ namespace System.Text.Json
                     message = SR.Format(SR.CannotWriteValueWithinObject, tokenType);
                     break;
                 case ExceptionResource.CannotWritePropertyWithinArray:
-                    message = SR.Format(SR.CannotWritePropertyWithinArray, tokenType);
+                    message = (tokenType == JsonTokenType.PropertyName) ?
+                        SR.Format(SR.CannotWritePropertyAfterProperty) :
+                        SR.Format(SR.CannotWritePropertyWithinArray, tokenType);
                     break;
                 case ExceptionResource.CannotWriteValueAfterPrimitive:
                     message = SR.Format(SR.CannotWriteValueAfterPrimitive, tokenType);
index dd4cf73..cf10dcd 100644 (file)
@@ -301,6 +301,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -349,6 +351,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 5164505..b944e4a 100644 (file)
@@ -306,6 +306,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -356,6 +358,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 723bc6b..0e3f907 100644 (file)
@@ -306,6 +306,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -356,6 +358,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index e7feaab..0b27787 100644 (file)
@@ -292,6 +292,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -335,6 +337,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index c4067c4..0fb4ee4 100644 (file)
@@ -296,6 +296,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -339,6 +341,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index f19a26a..2c8898c 100644 (file)
@@ -296,6 +296,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -339,6 +341,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 41fc322..db80b2b 100644 (file)
@@ -300,6 +300,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -347,6 +349,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 8786cc9..27fa38c 100644 (file)
@@ -37,7 +37,7 @@ namespace System.Text.Json
         {
             if (!Options.SkipValidation)
             {
-                if (!_inObject)
+                if (!_inObject || _tokenType == JsonTokenType.PropertyName)
                 {
                     Debug.Assert(_tokenType != JsonTokenType.StartObject);
                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotWritePropertyWithinArray, currentDepth: default, token: default, _tokenType);
@@ -50,7 +50,7 @@ namespace System.Text.Json
         {
             if (!Options.SkipValidation)
             {
-                if (!_inObject)
+                if (!_inObject || _tokenType == JsonTokenType.PropertyName)
                 {
                     Debug.Assert(_tokenType != JsonTokenType.StartObject);
                     ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotWritePropertyWithinArray, currentDepth: default, token: default, _tokenType);
@@ -109,6 +109,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -180,6 +182,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 912bfa4..7034339 100644 (file)
@@ -384,6 +384,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -427,6 +429,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 210be72..3a64538 100644 (file)
@@ -361,6 +361,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -404,6 +406,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 51b3177..cea0c82 100644 (file)
@@ -10,6 +10,353 @@ namespace System.Text.Json
     public sealed partial class Utf8JsonWriter
     {
         /// <summary>
+        /// Writes the pre-encoded property name (as a JSON string) as the first part of a name/value pair of a JSON object.
+        /// </summary>
+        /// <param name="propertyName">The JSON encoded property name of the JSON object to be transcoded and written as UTF-8.</param>
+        /// <remarks>
+        /// The property name should already be escaped when the instance of <see cref="JsonEncodedText"/> was created.
+        /// </remarks>
+        /// <exception cref="InvalidOperationException">
+        /// Thrown if this would result in an invalid JSON to be written (while validation is enabled).
+        /// </exception>
+        public void WritePropertyName(JsonEncodedText propertyName)
+            => WritePropertyNameHelper(propertyName.EncodedUtf8Bytes);
+
+        private void WritePropertyNameHelper(ReadOnlySpan<byte> utf8PropertyName)
+        {
+            Debug.Assert(utf8PropertyName.Length <= JsonConstants.MaxTokenSize);
+
+            WriteStringByOptionsPropertyName(utf8PropertyName);
+
+            _currentDepth &= JsonConstants.RemoveFlagsBitMask;
+            _tokenType = JsonTokenType.PropertyName;
+        }
+
+        /// <summary>
+        /// Writes the property name (as a JSON string) as the first part of a name/value pair of a JSON object.
+        /// </summary>
+        /// <param name="propertyName">The property name of the JSON object to be transcoded and written as UTF-8.</param>
+        /// <remarks>
+        /// The property name is escaped before writing.
+        /// </remarks>
+        /// <exception cref="ArgumentException">
+        /// Thrown when the specified property name is too large.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        /// Thrown if this would result in an invalid JSON to be written (while validation is enabled).
+        /// </exception>
+        public void WritePropertyName(string propertyName)
+            => WritePropertyName(propertyName.AsSpan());
+
+        /// <summary>
+        /// Writes the property name (as a JSON string) as the first part of a name/value pair of a JSON object.
+        /// </summary>
+        /// <param name="propertyName">The property name of the JSON object to be transcoded and written as UTF-8.</param>
+        /// <remarks>
+        /// The property name is escaped before writing.
+        /// </remarks>
+        /// <exception cref="ArgumentException">
+        /// Thrown when the specified property name is too large.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        /// Thrown if this would result in an invalid JSON to be written (while validation is enabled).
+        /// </exception>
+        public void WritePropertyName(ReadOnlySpan<char> propertyName)
+        {
+            JsonWriterHelper.ValidateProperty(propertyName);
+
+            int propertyIdx = JsonWriterHelper.NeedsEscaping(propertyName);
+
+            Debug.Assert(propertyIdx >= -1 && propertyIdx < propertyName.Length && propertyIdx < int.MaxValue / 2);
+
+            if (propertyIdx != -1)
+            {
+                WriteStringEscapeProperty(propertyName, propertyIdx);
+            }
+            else
+            {
+                WriteStringByOptionsPropertyName(propertyName);
+            }
+            _currentDepth &= JsonConstants.RemoveFlagsBitMask;
+            _tokenType = JsonTokenType.PropertyName;
+        }
+
+        private void WriteStringEscapeProperty(ReadOnlySpan<char> propertyName, int firstEscapeIndexProp)
+        {
+            Debug.Assert(int.MaxValue / JsonConstants.MaxExpansionFactorWhileEscaping >= propertyName.Length);
+
+            char[] propertyArray = null;
+
+            if (firstEscapeIndexProp != -1)
+            {
+                int length = JsonWriterHelper.GetMaxEscapedLength(propertyName.Length, firstEscapeIndexProp);
+
+                Span<char> escapedPropertyName;
+                if (length > JsonConstants.StackallocThreshold)
+                {
+                    propertyArray = ArrayPool<char>.Shared.Rent(length);
+                    escapedPropertyName = propertyArray;
+                }
+                else
+                {
+                    // Cannot create a span directly since it gets assigned to parameter and passed down.
+                    unsafe
+                    {
+                        char* ptr = stackalloc char[length];
+                        escapedPropertyName = new Span<char>(ptr, length);
+                    }
+                }
+
+                JsonWriterHelper.EscapeString(propertyName, escapedPropertyName, firstEscapeIndexProp, out int written);
+                propertyName = escapedPropertyName.Slice(0, written);
+            }
+
+            WriteStringByOptionsPropertyName(propertyName);
+
+            if (propertyArray != null)
+            {
+                ArrayPool<char>.Shared.Return(propertyArray);
+            }
+        }
+
+        private void WriteStringByOptionsPropertyName(ReadOnlySpan<char> propertyName)
+        {
+            ValidateWritingProperty();
+            if (Options.Indented)
+            {
+                WriteStringIndentedPropertyName(propertyName);
+            }
+            else
+            {
+                WriteStringMinimizedPropertyName(propertyName);
+            }
+        }
+
+        private void WriteStringMinimizedPropertyName(ReadOnlySpan<char> escapedPropertyName)
+        {
+            Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxTokenSize);
+            Debug.Assert(escapedPropertyName.Length < (int.MaxValue - 4) / JsonConstants.MaxExpansionFactorWhileTranscoding);
+
+            // All ASCII, 2 quotes for property name, and 1 colon => escapedPropertyName.Length + 3
+            // Optionally, 1 list separator, and up to 3x growth when transcoding
+            int maxRequired = (escapedPropertyName.Length * JsonConstants.MaxExpansionFactorWhileTranscoding) + 4;
+
+            if (_memory.Length - BytesPending < maxRequired)
+            {
+                Grow(maxRequired);
+            }
+
+            Span<byte> output = _memory.Span;
+
+            if (_currentDepth < 0)
+            {
+                output[BytesPending++] = JsonConstants.ListSeparator;
+            }
+            output[BytesPending++] = JsonConstants.Quote;
+
+            TranscodeAndWrite(escapedPropertyName, output);
+
+            output[BytesPending++] = JsonConstants.Quote;
+            output[BytesPending++] = JsonConstants.KeyValueSeperator;
+        }
+
+        private void WriteStringIndentedPropertyName(ReadOnlySpan<char> escapedPropertyName)
+        {
+            int indent = Indentation;
+            Debug.Assert(indent <= 2 * JsonConstants.MaxWriterDepth);
+
+            Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxTokenSize);
+            Debug.Assert(escapedPropertyName.Length < (int.MaxValue - 5 - indent - s_newLineLength) / JsonConstants.MaxExpansionFactorWhileTranscoding);
+
+            // All ASCII, 2 quotes for property name, 1 colon, and 1 space => escapedPropertyName.Length + 4
+            // Optionally, 1 list separator, 1-2 bytes for new line, and up to 3x growth when transcoding
+            int maxRequired = indent + (escapedPropertyName.Length * JsonConstants.MaxExpansionFactorWhileTranscoding) + 5 + s_newLineLength;
+
+            if (_memory.Length - BytesPending < maxRequired)
+            {
+                Grow(maxRequired);
+            }
+
+            Span<byte> output = _memory.Span;
+
+            if (_currentDepth < 0)
+            {
+                output[BytesPending++] = JsonConstants.ListSeparator;
+            }
+
+            if (_tokenType != JsonTokenType.None)
+            {
+                WriteNewLine(output);
+            }
+
+            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+            BytesPending += indent;
+
+            output[BytesPending++] = JsonConstants.Quote;
+
+            TranscodeAndWrite(escapedPropertyName, output);
+
+            output[BytesPending++] = JsonConstants.Quote;
+            output[BytesPending++] = JsonConstants.KeyValueSeperator;
+            output[BytesPending++] = JsonConstants.Space;
+        }
+
+        /// <summary>
+        /// Writes the UTF-8 property name (as a JSON string) as the first part of a name/value pair of a JSON object.
+        /// </summary>
+        /// <param name="utf8PropertyName">The UTF-8 encoded property name of the JSON object to be written.</param>
+        /// <remarks>
+        /// The property name is escaped before writing.
+        /// </remarks>
+        /// <exception cref="ArgumentException">
+        /// Thrown when the specified property name is too large.
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        /// Thrown if this would result in an invalid JSON to be written (while validation is enabled).
+        /// </exception>
+        public void WritePropertyName(ReadOnlySpan<byte> utf8PropertyName)
+        {
+            JsonWriterHelper.ValidateProperty(utf8PropertyName);
+
+            int propertyIdx = JsonWriterHelper.NeedsEscaping(utf8PropertyName);
+
+            Debug.Assert(propertyIdx >= -1 && propertyIdx < utf8PropertyName.Length && propertyIdx < int.MaxValue / 2);
+
+            if (propertyIdx != -1)
+            {
+                WriteStringEscapeProperty(utf8PropertyName, propertyIdx);
+            }
+            else
+            {
+                WriteStringByOptionsPropertyName(utf8PropertyName);
+            }
+            _currentDepth &= JsonConstants.RemoveFlagsBitMask;
+            _tokenType = JsonTokenType.PropertyName;
+        }
+
+        private void WriteStringEscapeProperty(ReadOnlySpan<byte> utf8PropertyName, int firstEscapeIndexProp)
+        {
+            Debug.Assert(int.MaxValue / JsonConstants.MaxExpansionFactorWhileEscaping >= utf8PropertyName.Length);
+
+            byte[] propertyArray = null;
+
+            if (firstEscapeIndexProp != -1)
+            {
+                int length = JsonWriterHelper.GetMaxEscapedLength(utf8PropertyName.Length, firstEscapeIndexProp);
+
+                Span<byte> escapedPropertyName;
+                if (length > JsonConstants.StackallocThreshold)
+                {
+                    propertyArray = ArrayPool<byte>.Shared.Rent(length);
+                    escapedPropertyName = propertyArray;
+                }
+                else
+                {
+                    // Cannot create a span directly since it gets assigned to parameter and passed down.
+                    unsafe
+                    {
+                        byte* ptr = stackalloc byte[length];
+                        escapedPropertyName = new Span<byte>(ptr, length);
+                    }
+                }
+
+                JsonWriterHelper.EscapeString(utf8PropertyName, escapedPropertyName, firstEscapeIndexProp, out int written);
+                utf8PropertyName = escapedPropertyName.Slice(0, written);
+            }
+
+            WriteStringByOptionsPropertyName(utf8PropertyName);
+
+            if (propertyArray != null)
+            {
+                ArrayPool<byte>.Shared.Return(propertyArray);
+            }
+        }
+
+        private void WriteStringByOptionsPropertyName(ReadOnlySpan<byte> utf8PropertyName)
+        {
+            ValidateWritingProperty();
+            if (Options.Indented)
+            {
+                WriteStringIndentedPropertyName(utf8PropertyName);
+            }
+            else
+            {
+                WriteStringMinimizedPropertyName(utf8PropertyName);
+            }
+        }
+
+        private void WriteStringMinimizedPropertyName(ReadOnlySpan<byte> escapedPropertyName)
+        {
+            Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxTokenSize);
+            Debug.Assert(escapedPropertyName.Length < int.MaxValue - 4);
+
+            int minRequired = escapedPropertyName.Length + 3; // 2 quotes for property name, and 1 colon
+            int maxRequired = minRequired + 1; // Optionally, 1 list separator
+
+            if (_memory.Length - BytesPending < maxRequired)
+            {
+                Grow(maxRequired);
+            }
+
+            Span<byte> output = _memory.Span;
+
+            if (_currentDepth < 0)
+            {
+                output[BytesPending++] = JsonConstants.ListSeparator;
+            }
+            output[BytesPending++] = JsonConstants.Quote;
+
+            escapedPropertyName.CopyTo(output.Slice(BytesPending));
+            BytesPending += escapedPropertyName.Length;
+
+            output[BytesPending++] = JsonConstants.Quote;
+            output[BytesPending++] = JsonConstants.KeyValueSeperator;
+        }
+
+        private void WriteStringIndentedPropertyName(ReadOnlySpan<byte> escapedPropertyName)
+        {
+            int indent = Indentation;
+            Debug.Assert(indent <= 2 * JsonConstants.MaxWriterDepth);
+
+            Debug.Assert(escapedPropertyName.Length <= JsonConstants.MaxTokenSize);
+            Debug.Assert(escapedPropertyName.Length < int.MaxValue - indent - 5 - s_newLineLength);
+
+            int minRequired = indent + escapedPropertyName.Length + 4; // 2 quotes for property name, 1 colon, and 1 space
+            int maxRequired = minRequired + 1 + s_newLineLength; // Optionally, 1 list separator and 1-2 bytes for new line
+
+            if (_memory.Length - BytesPending < maxRequired)
+            {
+                Grow(maxRequired);
+            }
+
+            Span<byte> output = _memory.Span;
+
+            if (_currentDepth < 0)
+            {
+                output[BytesPending++] = JsonConstants.ListSeparator;
+            }
+
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
+            if (_tokenType != JsonTokenType.None)
+            {
+                WriteNewLine(output);
+            }
+
+            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+            BytesPending += indent;
+
+            output[BytesPending++] = JsonConstants.Quote;
+
+            escapedPropertyName.CopyTo(output.Slice(BytesPending));
+            BytesPending += escapedPropertyName.Length;
+
+            output[BytesPending++] = JsonConstants.Quote;
+            output[BytesPending++] = JsonConstants.KeyValueSeperator;
+            output[BytesPending++] = JsonConstants.Space;
+        }
+
+        /// <summary>
         /// Writes the pre-encoded property name and pre-encoded value (as a JSON string) as part of a name/value pair of a JSON object.
         /// </summary>
         /// <param name="propertyName">The JSON encoded property name of the JSON object to be transcoded and written as UTF-8.</param>
@@ -1072,6 +1419,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -1119,6 +1468,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -1169,6 +1520,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -1218,6 +1571,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index 7a0a2a8..b57ebea 100644 (file)
@@ -369,6 +369,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
@@ -412,6 +414,8 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
+            Debug.Assert(Options.SkipValidation || _tokenType != JsonTokenType.PropertyName);
+
             if (_tokenType != JsonTokenType.None)
             {
                 WriteNewLine(output);
index ef1fdb8..35900c0 100644 (file)
@@ -101,14 +101,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             Base64EncodeAndWrite(bytes, output, encodingLength);
index 4e5178b..baee4d2 100644 (file)
@@ -199,14 +199,16 @@ namespace System.Text.Json
 
             Span<byte> output = _memory.Span;
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Slash;
             output[BytesPending++] = JsonConstants.Asterisk;
 
index b62679a..f9cd8cb 100644 (file)
@@ -84,14 +84,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             Span<byte> tempSpan = stackalloc byte[JsonConstants.MaximumFormatDateTimeOffsetLength];
index 45d9aeb..1c99640 100644 (file)
@@ -85,14 +85,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             Span<byte> tempSpan = stackalloc byte[JsonConstants.MaximumFormatDateTimeOffsetLength];
index 2ad2b1d..412b395 100644 (file)
@@ -76,14 +76,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
             Debug.Assert(result);
             BytesPending += bytesWritten;
index 74315e7..432247f 100644 (file)
@@ -78,14 +78,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
             Debug.Assert(result);
             BytesPending += bytesWritten;
index 47aca25..23fcc73 100644 (file)
@@ -78,14 +78,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
             Debug.Assert(result);
             BytesPending += bytesWritten;
index f5c2458..4c468f3 100644 (file)
@@ -82,14 +82,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             utf8Value.CopyTo(output.Slice(BytesPending));
             BytesPending += utf8Value.Length;
         }
index 59b87f1..0a80cdc 100644 (file)
@@ -81,14 +81,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
index 9c26cb3..9a9e690 100644 (file)
@@ -17,11 +17,15 @@ namespace System.Text.Json
             {
                 if (_inObject)
                 {
-                    Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray);
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotWriteValueWithinObject, currentDepth: default, token: default, _tokenType);
+                    if (_tokenType != JsonTokenType.PropertyName)
+                    {
+                        Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray);
+                        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotWriteValueWithinObject, currentDepth: default, token: default, _tokenType);
+                    }
                 }
                 else
                 {
+                    Debug.Assert(_tokenType != JsonTokenType.PropertyName);
                     if (!_isNotPrimitive && _tokenType != JsonTokenType.None)
                     {
                         ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotWriteValueAfterPrimitive, currentDepth: default, token: default, _tokenType);
index 2a7abf4..2a718f1 100644 (file)
@@ -100,14 +100,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             utf8Value.CopyTo(output.Slice(BytesPending));
             BytesPending += utf8Value.Length;
         }
index 5f772ea..994aa78 100644 (file)
@@ -89,14 +89,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
             Debug.Assert(result);
             BytesPending += bytesWritten;
index 60d3538..797b40d 100644 (file)
@@ -151,14 +151,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             TranscodeAndWrite(escapedValue, output);
@@ -291,14 +293,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = JsonConstants.Quote;
 
             escapedValue.CopyTo(output.Slice(BytesPending));
index 7659709..e961cbd 100644 (file)
@@ -91,14 +91,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             bool result = Utf8Formatter.TryFormat(value, output.Slice(BytesPending), out int bytesWritten);
             Debug.Assert(result);
             BytesPending += bytesWritten;
index 7b44253..0954db1 100644 (file)
@@ -506,11 +506,15 @@ namespace System.Text.Json
         {
             if (_inObject)
             {
-                Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray);
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotStartObjectArrayWithoutProperty, currentDepth: default, token: default, _tokenType);
+                if (_tokenType != JsonTokenType.PropertyName)
+                {
+                    Debug.Assert(_tokenType != JsonTokenType.None && _tokenType != JsonTokenType.StartArray);
+                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.CannotStartObjectArrayWithoutProperty, currentDepth: default, token: default, _tokenType);
+                }
             }
             else
             {
+                Debug.Assert(_tokenType != JsonTokenType.PropertyName);
                 Debug.Assert(_tokenType != JsonTokenType.StartObject);
                 if (_tokenType != JsonTokenType.None && (!_isNotPrimitive || CurrentDepth == 0))
                 {
@@ -539,14 +543,16 @@ namespace System.Text.Json
                 output[BytesPending++] = JsonConstants.ListSeparator;
             }
 
-            if (_tokenType != JsonTokenType.None)
+            if (_tokenType != JsonTokenType.PropertyName)
             {
-                WriteNewLine(output);
+                if (_tokenType != JsonTokenType.None)
+                {
+                    WriteNewLine(output);
+                }
+                JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
+                BytesPending += indent;
             }
 
-            JsonWriterHelper.WriteIndentation(output.Slice(BytesPending), indent);
-            BytesPending += indent;
-
             output[BytesPending++] = token;
         }
 
@@ -917,15 +923,15 @@ namespace System.Text.Json
 
         private void ValidateEnd(byte token)
         {
-            if (_bitStack.CurrentDepth <= 0)
-                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, tokenType: default);
+            if (_bitStack.CurrentDepth <= 0 || _tokenType == JsonTokenType.PropertyName)
+                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, _tokenType);
 
             if (token == JsonConstants.CloseBracket)
             {
                 if (_inObject)
                 {
                     Debug.Assert(_tokenType != JsonTokenType.None);
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, tokenType: default);
+                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, _tokenType);
                 }
             }
             else
@@ -934,7 +940,7 @@ namespace System.Text.Json
 
                 if (!_inObject)
                 {
-                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, tokenType: default);
+                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.MismatchedObjectArray, currentDepth: default, token, _tokenType);
                 }
             }
 
index d2375b1..867061c 100644 (file)
@@ -439,7 +439,6 @@ namespace System.Text.Json.Tests
             Assert.Equal(2, stream.Position);
         }
 
-#if !netfx
         [Theory]
         [InlineData(true, true)]
         [InlineData(true, false)]
@@ -469,7 +468,6 @@ namespace System.Text.Json.Tests
             Assert.Equal(0, writeToStream.BytesCommitted);
             Assert.Equal(2, stream.Position);
         }
-#endif
 
         [Theory]
         [InlineData(true, true)]
@@ -517,7 +515,6 @@ namespace System.Text.Json.Tests
             Assert.Throws<ObjectDisposedException>(() => jsonUtf8.Reset(output));
         }
 
-#if !netfx
         [Theory]
         [InlineData(true, true)]
         [InlineData(true, false)]
@@ -563,7 +560,6 @@ namespace System.Text.Json.Tests
 
             Assert.Throws<ObjectDisposedException>(() => jsonUtf8.Reset(output));
         }
-#endif
 
         [Theory]
         [InlineData(true, true)]
@@ -602,10 +598,7 @@ namespace System.Text.Json.Tests
         {
             const int SyncWriteThreshold = 25_000;
 
-#if !netfx
-            await
-#endif
-                using var jsonUtf8 = new Utf8JsonWriter(stream, options);
+            await using var jsonUtf8 = new Utf8JsonWriter(stream, options);
 
             byte[] utf8String = Encoding.UTF8.GetBytes("some string 1234");
 
@@ -978,6 +971,17 @@ namespace System.Text.Json.Tests
             }
 
             jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            if (skipValidation)
+            {
+                jsonUtf8.WriteStartArray();
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteStartArray());
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
             jsonUtf8.WriteStartArray();
             jsonUtf8.WriteStartArray();
             jsonUtf8.WriteEndArray();
@@ -1076,6 +1080,81 @@ namespace System.Text.Json.Tests
             {
                 Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteEndArray());
             }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+                jsonUtf8.WritePropertyName(JsonEncodedText.Encode("test name"));
+                jsonUtf8.WritePropertyName("test name".AsSpan());
+                jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("test name"));
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName(JsonEncodedText.Encode("test name")));
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name".AsSpan()));
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("test name")));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartArray();
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            jsonUtf8.WritePropertyName("first name");
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            jsonUtf8.WritePropertyName("first name");
+            if (skipValidation)
+            {
+                jsonUtf8.WriteStartArray("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteStartArray("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            jsonUtf8.WritePropertyName("first name");
+            if (skipValidation)
+            {
+                jsonUtf8.WriteStartObject("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteStartObject("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            jsonUtf8.WritePropertyName("first name");
+            if (skipValidation)
+            {
+                jsonUtf8.WriteEndObject();
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteEndObject());
+            }
         }
 
         [Theory]
@@ -1228,6 +1307,50 @@ namespace System.Text.Json.Tests
             {
                 Assert.Throws<InvalidOperationException>(() => jsonUtf8.WriteEndObject());
             }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteNumberValue(12345);
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteBooleanValue(true);
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteNullValue();
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStringValue("some string");
+            if (skipValidation)
+            {
+                jsonUtf8.WritePropertyName("test name");
+            }
+            else
+            {
+                Assert.Throws<InvalidOperationException>(() => jsonUtf8.WritePropertyName("test name"));
+            }
         }
 
         [Theory]
@@ -1321,6 +1444,58 @@ namespace System.Text.Json.Tests
         [InlineData(true, false)]
         [InlineData(false, true)]
         [InlineData(false, false)]
+        public void WriteSeparateProperties(bool formatted, bool skipValidation)
+        {
+            var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
+            var output = new ArrayBufferWriter<byte>(1024);
+
+            var stringWriter = new StringWriter();
+            var json = new JsonTextWriter(stringWriter)
+            {
+                Formatting = formatted ? Formatting.Indented : Formatting.None,
+            };
+
+            json.WriteStartObject();
+            json.WritePropertyName("foo1");
+            json.WriteValue("bar1");
+            json.WritePropertyName("foo2");
+            json.WriteValue("bar2");
+            json.WritePropertyName("foo3");
+            json.WriteValue("bar3");
+            json.WritePropertyName("foo4");
+            json.WriteValue("bar4");
+            json.WritePropertyName("array");
+            json.WriteStartArray();
+            json.WriteEndArray();
+            json.WriteEnd();
+
+            json.Flush();
+
+            string expectedStr = stringWriter.ToString();
+
+            var jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes("foo1"));
+            jsonUtf8.WriteStringValue("bar1");
+            jsonUtf8.WritePropertyName("foo2");
+            jsonUtf8.WriteStringValue("bar2");
+            jsonUtf8.WritePropertyName(JsonEncodedText.Encode("foo3"));
+            jsonUtf8.WriteStringValue("bar3");
+            jsonUtf8.WritePropertyName("foo4".AsSpan());
+            jsonUtf8.WriteStringValue("bar4");
+            jsonUtf8.WritePropertyName("array");
+            jsonUtf8.WriteStartArray();
+            jsonUtf8.WriteEndArray();
+            jsonUtf8.WriteEndObject();
+            jsonUtf8.Flush();
+            Assert.Equal(expectedStr, Encoding.UTF8.GetString(output.WrittenMemory.ToArray()));
+        }
+
+        [Theory]
+        [InlineData(true, true)]
+        [InlineData(true, false)]
+        [InlineData(false, true)]
+        [InlineData(false, false)]
         public void WritingTooDeep(bool formatted, bool skipValidation)
         {
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
@@ -1414,6 +1589,42 @@ namespace System.Text.Json.Tests
         [InlineData(true, false)]
         [InlineData(false, true)]
         [InlineData(false, false)]
+        public void WritingTooLargePropertyStandalone(bool formatted, bool skipValidation)
+        {
+            byte[] key;
+            char[] keyChars;
+
+            try
+            {
+                key = new byte[1_000_000_000];
+                keyChars = new char[1_000_000_000];
+            }
+            catch (OutOfMemoryException)
+            {
+                return;
+            }
+
+            key.AsSpan().Fill((byte)'a');
+            keyChars.AsSpan().Fill('a');
+
+            var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
+            var output = new ArrayBufferWriter<byte>(1024);
+
+            var jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(keyChars));
+
+            jsonUtf8 = new Utf8JsonWriter(output, options);
+            jsonUtf8.WriteStartObject();
+            Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(key));
+        }
+
+        [ConditionalTheory(nameof(IsX64))]
+        [OuterLoop]
+        [InlineData(true, true)]
+        [InlineData(true, false)]
+        [InlineData(false, true)]
+        [InlineData(false, false)]
         public void WritingTooLargeBase64Bytes(bool formatted, bool skipValidation)
         {
             byte[] value;
@@ -1492,7 +1703,7 @@ namespace System.Text.Json.Tests
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
 
-            for (int i = 0; i < 16; i++)
+            for (int i = 0; i < 32; i++)
             {
                 var output = new ArrayBufferWriter<byte>(32);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -1565,6 +1776,102 @@ namespace System.Text.Json.Tests
                         jsonUtf8.WriteString(utf8PropertyName, encodedValue);
                         jsonUtf8.WriteString(utf8PropertyName, encodedValue);
                         break;
+                    case 16:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 17:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 18:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        break;
+                    case 19:
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 20:
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 21:
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        break;
+                    case 22:
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 23:
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 24:
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        break;
+                    case 25:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 26:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 27:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(utf8Value);
+                        break;
+                    case 28:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 29:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 30:
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 31:
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(utf8PropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -1595,7 +1902,7 @@ namespace System.Text.Json.Tests
             JsonEncodedText encodedPropertyName = JsonEncodedText.Encode(propertyName);
             JsonEncodedText encodedValue = JsonEncodedText.Encode(value);
 
-            for (int i = 0; i < 16; i++)
+            for (int i = 0; i < 32; i++)
             {
                 var output = new ArrayBufferWriter<byte>(32);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -1668,6 +1975,102 @@ namespace System.Text.Json.Tests
                         jsonUtf8.WriteString(propertyNameSpanUtf8, encodedValue);
                         jsonUtf8.WriteString(propertyNameSpanUtf8, encodedValue);
                         break;
+                    case 16:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 17:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        break;
+                    case 18:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        break;
+                    case 19:
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 20:
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        break;
+                    case 21:
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        jsonUtf8.WritePropertyName(propertyNameSpan);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        break;
+                    case 22:
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 23:
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(valueSpan);
+                        break;
+                    case 24:
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        break;
+                    case 25:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 26:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 27:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(valueSpanUtf8);
+                        break;
+                    case 28:
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(encodedPropertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 29:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 30:
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(propertyName.AsSpan());
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 31:
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        jsonUtf8.WritePropertyName(propertyNameSpanUtf8);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -2322,7 +2725,7 @@ namespace System.Text.Json.Tests
             JsonEncodedText encodedKey = JsonEncodedText.Encode(key);
             JsonEncodedText encodedValue = JsonEncodedText.Encode(value);
 
-            for (int i = 0; i < 16; i++)
+            for (int i = 0; i < 32; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -2379,6 +2782,70 @@ namespace System.Text.Json.Tests
                     case 15:
                         jsonUtf8.WriteString(keyUtf8, encodedValue);
                         break;
+                    case 16:
+                        jsonUtf8.WritePropertyName(key);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 17:
+                        jsonUtf8.WritePropertyName(key);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 18:
+                        jsonUtf8.WritePropertyName(key);
+                        jsonUtf8.WriteStringValue(valueUtf8);
+                        break;
+                    case 19:
+                        jsonUtf8.WritePropertyName(key.AsSpan());
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 20:
+                        jsonUtf8.WritePropertyName(key.AsSpan());
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 21:
+                        jsonUtf8.WritePropertyName(key.AsSpan());
+                        jsonUtf8.WriteStringValue(valueUtf8);
+                        break;
+                    case 22:
+                        jsonUtf8.WritePropertyName(keyUtf8);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 23:
+                        jsonUtf8.WritePropertyName(keyUtf8);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 24:
+                        jsonUtf8.WritePropertyName(keyUtf8);
+                        jsonUtf8.WriteStringValue(valueUtf8);
+                        break;
+                    case 25:
+                        jsonUtf8.WritePropertyName(encodedKey);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 26:
+                        jsonUtf8.WritePropertyName(encodedKey);
+                        jsonUtf8.WriteStringValue(value.AsSpan());
+                        break;
+                    case 27:
+                        jsonUtf8.WritePropertyName(encodedKey);
+                        jsonUtf8.WriteStringValue(valueUtf8);
+                        break;
+                    case 28:
+                        jsonUtf8.WritePropertyName(encodedKey);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 29:
+                        jsonUtf8.WritePropertyName(key);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 30:
+                        jsonUtf8.WritePropertyName(key.AsSpan());
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
+                    case 31:
+                        jsonUtf8.WritePropertyName(keyUtf8);
+                        jsonUtf8.WriteStringValue(encodedValue);
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -2416,7 +2883,7 @@ namespace System.Text.Json.Tests
             string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeHtml);
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 6; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -2434,6 +2901,18 @@ namespace System.Text.Json.Tests
                     case 2:
                         jsonUtf8.WriteString(JsonEncodedText.Encode(propertyName), JsonEncodedText.Encode(value));
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 4:
+                        jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes(propertyName));
+                        jsonUtf8.WriteStringValue(Encoding.UTF8.GetBytes(value));
+                        break;
+                    case 5:
+                        jsonUtf8.WritePropertyName(JsonEncodedText.Encode(propertyName));
+                        jsonUtf8.WriteStringValue(JsonEncodedText.Encode(value));
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -2467,7 +2946,7 @@ namespace System.Text.Json.Tests
             string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeNonAscii);
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 6; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -2485,6 +2964,18 @@ namespace System.Text.Json.Tests
                     case 2:
                         jsonUtf8.WriteString(JsonEncodedText.Encode(propertyName), JsonEncodedText.Encode(value));
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 4:
+                        jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes(propertyName));
+                        jsonUtf8.WriteStringValue(Encoding.UTF8.GetBytes(value));
+                        break;
+                    case 5:
+                        jsonUtf8.WritePropertyName(JsonEncodedText.Encode(propertyName));
+                        jsonUtf8.WriteStringValue(JsonEncodedText.Encode(value));
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -2509,7 +3000,7 @@ namespace System.Text.Json.Tests
             string expectedStr = GetEscapedExpectedString(prettyPrint: formatted, propertyName, value, StringEscapeHandling.EscapeNonAscii);
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 6; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -2527,6 +3018,18 @@ namespace System.Text.Json.Tests
                     case 2:
                         jsonUtf8.WriteString(JsonEncodedText.Encode(propertyName), JsonEncodedText.Encode(value));
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName(propertyName);
+                        jsonUtf8.WriteStringValue(value);
+                        break;
+                    case 4:
+                        jsonUtf8.WritePropertyName(Encoding.UTF8.GetBytes(propertyName));
+                        jsonUtf8.WriteStringValue(Encoding.UTF8.GetBytes(value));
+                        break;
+                    case 5:
+                        jsonUtf8.WritePropertyName(JsonEncodedText.Encode(propertyName));
+                        jsonUtf8.WriteStringValue(JsonEncodedText.Encode(value));
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -2552,7 +3055,7 @@ namespace System.Text.Json.Tests
             var invalidUtf8 = new byte[2] { 0xc3, 0x28 };
 
             jsonUtf8.WriteStartObject();
-            for (int i = 0; i < 4; i++)
+            for (int i = 0; i < 6; i++)
             {
                 switch (i)
                 {
@@ -2568,6 +3071,18 @@ namespace System.Text.Json.Tests
                     case 3:
                         jsonUtf8.WriteString(validUtf8, validUtf8);
                         break;
+                    case 4:
+                        Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(invalidUtf8));
+                        break;
+                    case 5:
+                        jsonUtf8.WritePropertyName(validUtf8);
+                        Assert.Throws<ArgumentException>(() => jsonUtf8.WriteStringValue(invalidUtf8));
+                        jsonUtf8.WriteStringValue(validUtf8);
+                        break;
+                    case 6:
+                        jsonUtf8.WritePropertyName(validUtf8);
+                        jsonUtf8.WriteStringValue(validUtf8);
+                        break;
                 }
             }
             jsonUtf8.WriteEndObject();
@@ -2590,7 +3105,7 @@ namespace System.Text.Json.Tests
             var invalidUtf16 = new char[2] { (char)0xD801, 'a' };
 
             jsonUtf8.WriteStartObject();
-            for (int i = 0; i < 4; i++)
+            for (int i = 0; i < 7; i++)
             {
                 switch (i)
                 {
@@ -2606,6 +3121,18 @@ namespace System.Text.Json.Tests
                     case 3:
                         jsonUtf8.WriteString(validUtf16, validUtf16);
                         break;
+                    case 4:
+                        Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(invalidUtf16));
+                        break;
+                    case 5:
+                        jsonUtf8.WritePropertyName(validUtf16);
+                        Assert.Throws<ArgumentException>(() => jsonUtf8.WriteStringValue(invalidUtf16));
+                        jsonUtf8.WriteStringValue(validUtf16);
+                        break;
+                    case 6:
+                        jsonUtf8.WritePropertyName(validUtf16);
+                        jsonUtf8.WriteStringValue(validUtf16);
+                        break;
                 }
             }
             jsonUtf8.WriteEndObject();
@@ -2943,7 +3470,7 @@ namespace System.Text.Json.Tests
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
 
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 4; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -2961,6 +3488,10 @@ namespace System.Text.Json.Tests
                     case 2:
                         jsonUtf8.WriteBoolean(Encoding.UTF8.GetBytes(keyString), value);
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName(keyString);
+                        jsonUtf8.WriteBooleanValue(value);
+                        break;
                 }
 
                 jsonUtf8.WriteStartArray("temp");
@@ -2996,7 +3527,7 @@ namespace System.Text.Json.Tests
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
 
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 4; i++)
             {
                 var output = new ArrayBufferWriter<byte>(16);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -3017,6 +3548,12 @@ namespace System.Text.Json.Tests
                         jsonUtf8.WriteNull(Encoding.UTF8.GetBytes(keyString));
                         jsonUtf8.WriteNull(Encoding.UTF8.GetBytes(keyString));
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName(keyString);
+                        jsonUtf8.WriteNullValue();
+                        jsonUtf8.WritePropertyName(keyString);
+                        jsonUtf8.WriteNullValue();
+                        break;
                 }
 
                 jsonUtf8.WriteStartArray("temp");
@@ -3062,7 +3599,7 @@ namespace System.Text.Json.Tests
 
             var options = new JsonWriterOptions { Indented = formatted, SkipValidation = skipValidation };
 
-            for (int i = 0; i < 3; i++)
+            for (int i = 0; i < 4; i++)
             {
                 var output = new ArrayBufferWriter<byte>(1024);
                 var jsonUtf8 = new Utf8JsonWriter(output, options);
@@ -3080,6 +3617,10 @@ namespace System.Text.Json.Tests
                     case 2:
                         jsonUtf8.WriteNumber(Encoding.UTF8.GetBytes("message"), value);
                         break;
+                    case 3:
+                        jsonUtf8.WritePropertyName("message");
+                        jsonUtf8.WriteNumberValue(value);
+                        break;
                 }
 
                 jsonUtf8.WriteEndObject();
@@ -4207,6 +4748,7 @@ namespace System.Text.Json.Tests
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteNumber(bytesTooLarge, (ulong)12345678901));
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteBoolean(bytesTooLarge, true));
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteNull(bytesTooLarge));
+            Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(bytesTooLarge));
 
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteStartObject(charsTooLarge));
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteString(charsTooLarge, chars));
@@ -4225,6 +4767,7 @@ namespace System.Text.Json.Tests
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteNumber(charsTooLarge, (ulong)12345678901));
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteBoolean(charsTooLarge, true));
             Assert.Throws<ArgumentException>(() => jsonUtf8.WriteNull(charsTooLarge));
+            Assert.Throws<ArgumentException>(() => jsonUtf8.WritePropertyName(charsTooLarge));
 
             jsonUtf8.Flush();
             Assert.Equal(1, jsonUtf8.BytesCommitted);