Skip to content

Commit

Permalink
Add JsonElement.WriteProperty that takes JsonEncodedText. (dotnet/cor…
Browse files Browse the repository at this point in the history
…efx#38869)

* Add JsonElement.WriteProperty that takes JsonEncodedText.

* Add tests.

* Auto-gen the ref.


Commit migrated from dotnet/corefx@5134166
  • Loading branch information
ahsonkhan authored Jun 26, 2019
1 parent e0f16ab commit 5283837
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 43 deletions.
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/ref/System.Text.Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public readonly partial struct JsonElement
public void WriteProperty(System.ReadOnlySpan<byte> utf8PropertyName, System.Text.Json.Utf8JsonWriter writer) { }
public void WriteProperty(System.ReadOnlySpan<char> propertyName, System.Text.Json.Utf8JsonWriter writer) { }
public void WriteProperty(string propertyName, System.Text.Json.Utf8JsonWriter writer) { }
public void WriteProperty(System.Text.Json.JsonEncodedText propertyName, System.Text.Json.Utf8JsonWriter writer) { }
public void WriteValue(System.Text.Json.Utf8JsonWriter writer) { }
public partial struct ArrayEnumerator : System.Collections.Generic.IEnumerable<System.Text.Json.JsonElement>, System.Collections.Generic.IEnumerator<System.Text.Json.JsonElement>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ internal bool TextEquals(int index, ReadOnlySpan<char> otherText, bool isPropert
int matchIndex = isPropertyName ? index - DbRow.Size : index;

(int lastIdx, string lastString) = _lastIndexAndString;

if (lastIdx == matchIndex)
{
return otherText.SequenceEqual(lastString.AsSpan());
Expand Down Expand Up @@ -312,7 +312,7 @@ internal bool TextEquals(int index, ReadOnlySpan<byte> otherUtf8Text, bool isPro
DbRow row = _parsedData.Get(matchIndex);

CheckExpectedType(
isPropertyName? JsonTokenType.PropertyName : JsonTokenType.String,
isPropertyName ? JsonTokenType.PropertyName : JsonTokenType.String,
row.TokenType);

ReadOnlySpan<byte> data = _utf8Json.Span;
Expand Down Expand Up @@ -796,6 +796,47 @@ internal void WriteElementTo(
Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
}

internal void WriteElementTo(
int index,
Utf8JsonWriter writer,
JsonEncodedText propertyName)
{
CheckNotDisposed();

DbRow row = _parsedData.Get(index);

switch (row.TokenType)
{
case JsonTokenType.StartObject:
writer.WriteStartObject(propertyName);
WriteComplexElement(index, writer);
return;
case JsonTokenType.StartArray:
writer.WriteStartArray(propertyName);
WriteComplexElement(index, writer);
return;
case JsonTokenType.String:
WriteString(propertyName, row, writer);
return;
case JsonTokenType.True:
writer.WriteBoolean(propertyName, value: true);
return;
case JsonTokenType.False:
writer.WriteBoolean(propertyName, value: false);
return;
case JsonTokenType.Null:
writer.WriteNull(propertyName);
return;
case JsonTokenType.Number:
writer.WriteNumber(
propertyName,
_utf8Json.Slice(row.Location, row.SizeOrLength).Span);
return;
}

Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
}

internal void WriteElementTo(
int index,
Utf8JsonWriter writer,
Expand Down Expand Up @@ -914,45 +955,45 @@ private void WriteComplexElement(int index, Utf8JsonWriter writer)
writer.WriteEndArray();
continue;
case JsonTokenType.PropertyName:
{
DbRow propertyValue = _parsedData.Get(i + DbRow.Size);
{
DbRow propertyValue = _parsedData.Get(i + DbRow.Size);

ReadOnlySpan<byte> propertyName =
_utf8Json.Slice(row.Location, row.SizeOrLength).Span;
ReadOnlySpan<byte> propertyName =
_utf8Json.Slice(row.Location, row.SizeOrLength).Span;

// "Move" to the value.
i += DbRow.Size;
// "Move" to the value.
i += DbRow.Size;

switch (propertyValue.TokenType)
{
case JsonTokenType.String:
WriteString(propertyName, propertyValue, writer);
continue;
case JsonTokenType.Number:
writer.WriteNumber(
propertyName,
_utf8Json.Slice(propertyValue.Location, propertyValue.SizeOrLength).Span);
switch (propertyValue.TokenType)
{
case JsonTokenType.String:
WriteString(propertyName, propertyValue, writer);
continue;
case JsonTokenType.True:
writer.WriteBoolean(propertyName, value: true);
continue;
case JsonTokenType.False:
writer.WriteBoolean(propertyName, value: false);
continue;
case JsonTokenType.Null:
writer.WriteNull(propertyName);
continue;
case JsonTokenType.StartObject:
writer.WriteStartObject(propertyName);
continue;
case JsonTokenType.StartArray:
writer.WriteStartArray(propertyName);
continue;
}
case JsonTokenType.Number:
writer.WriteNumber(
propertyName,
_utf8Json.Slice(propertyValue.Location, propertyValue.SizeOrLength).Span);
continue;
case JsonTokenType.True:
writer.WriteBoolean(propertyName, value: true);
continue;
case JsonTokenType.False:
writer.WriteBoolean(propertyName, value: false);
continue;
case JsonTokenType.Null:
writer.WriteNull(propertyName);
continue;
case JsonTokenType.StartObject:
writer.WriteStartObject(propertyName);
continue;
case JsonTokenType.StartArray:
writer.WriteStartArray(propertyName);
continue;
}

Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
break;
}
Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
break;
}
}

Debug.Fail($"Unexpected encounter with JsonTokenType {row.TokenType}");
Expand Down Expand Up @@ -992,6 +1033,22 @@ private static void ClearAndReturn(ArraySegment<byte> rented)
}
}

private void WriteString(JsonEncodedText propertyName, in DbRow row, Utf8JsonWriter writer)
{
ArraySegment<byte> rented = default;

try
{
writer.WriteString(
propertyName,
UnescapeString(row, out rented));
}
finally
{
ClearAndReturn(rented);
}
}

private void WriteString(ReadOnlySpan<byte> propertyName, in DbRow row, Utf8JsonWriter writer)
{
ArraySegment<byte> rented = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,24 @@ public void WriteProperty(ReadOnlySpan<char> propertyName, Utf8JsonWriter writer
_parent.WriteElementTo(_idx, writer, propertyName);
}

/// <summary>
/// Write the element into the provided writer as a named JSON object property.
/// </summary>
/// <param name="propertyName">The pre-encoded name for this value within the JSON object.</param>
/// <param name="writer">The writer.</param>
/// <exception cref="InvalidOperationException">
/// This value's <see cref="Type"/> is <see cref="JsonValueType.Undefined"/>.
/// </exception>
/// <exception cref="ObjectDisposedException">
/// The parent <see cref="JsonDocument"/> has been disposed.
/// </exception>
public void WriteProperty(JsonEncodedText propertyName, Utf8JsonWriter writer)
{
CheckValidInstance();

_parent.WriteElementTo(_idx, writer, propertyName);
}

/// <summary>
/// Write the element into the provided writer as a named JSON object property.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ internal void WriteNumber(ReadOnlySpan<byte> utf8PropertyName, ReadOnlySpan<byte
_tokenType = JsonTokenType.Number;
}

internal void WriteNumber(JsonEncodedText propertyName, ReadOnlySpan<byte> utf8FormattedNumber)
{
JsonWriterHelper.ValidateValue(utf8FormattedNumber);
JsonWriterHelper.ValidateNumber(utf8FormattedNumber);

WriteNumberByOptions(propertyName.EncodedUtf8Bytes, utf8FormattedNumber);

SetFlagToAddListSeparatorBeforeNextItem();
_tokenType = JsonTokenType.Number;
}

private void WriteNumberEscape(ReadOnlySpan<char> propertyName, ReadOnlySpan<byte> value)
{
int propertyIdx = JsonWriterHelper.NeedsEscaping(propertyName);
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/System.Text.Json/tests/JsonDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,12 @@ public static void CheckUseAfterDispose()
Utf8JsonWriter writer = default;
root.WriteProperty(ReadOnlySpan<byte>.Empty, writer);
});

Assert.Throws<ObjectDisposedException>(() =>
{
Utf8JsonWriter writer = default;
root.WriteProperty(JsonEncodedText.Encode(ReadOnlySpan<byte>.Empty), writer);
});
}
}

Expand Down
61 changes: 54 additions & 7 deletions src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -882,18 +882,19 @@ public static void WritePropertyOutsideObject(bool skipValidation)
val.WriteProperty(CharLabel, writer);
val.WriteProperty(CharLabel.AsSpan(), writer);
val.WriteProperty(byteUtf8, writer);
val.WriteProperty(JsonEncodedText.Encode(CharLabel), writer);
}

writer.Flush();

AssertContents(
"\"char\":null,\"char\":null,\"byte\":null," +
"\"char\":false,\"char\":false,\"byte\":false," +
"\"char\":true,\"char\":true,\"byte\":true," +
"\"char\":\"hi\",\"char\":\"hi\",\"byte\":\"hi\"," +
"\"char\":5,\"char\":5,\"byte\":5," +
"\"char\":{},\"char\":{},\"byte\":{}," +
"\"char\":[],\"char\":[],\"byte\":[]",
"\"char\":null,\"char\":null,\"byte\":null,\"char\":null," +
"\"char\":false,\"char\":false,\"byte\":false,\"char\":false," +
"\"char\":true,\"char\":true,\"byte\":true,\"char\":true," +
"\"char\":\"hi\",\"char\":\"hi\",\"byte\":\"hi\",\"char\":\"hi\"," +
"\"char\":5,\"char\":5,\"byte\":5,\"char\":5," +
"\"char\":{},\"char\":{},\"byte\":{},\"char\":{}," +
"\"char\":[],\"char\":[],\"byte\":[],\"char\":[]",
buffer);
}
else
Expand All @@ -911,6 +912,10 @@ public static void WritePropertyOutsideObject(bool skipValidation)
JsonTestHelper.AssertThrows<InvalidOperationException>(
ref writer,
(ref Utf8JsonWriter w) => val.WriteProperty(byteUtf8, w));

JsonTestHelper.AssertThrows<InvalidOperationException>(
ref writer,
(ref Utf8JsonWriter w) => val.WriteProperty(JsonEncodedText.Encode(CharLabel), w));
}

writer.Flush();
Expand Down Expand Up @@ -1048,6 +1053,13 @@ private static void WritePropertyValueBothForms(
jsonIn,
expectedIndent,
expectedMinimal);

WritePropertyValue(
indented,
JsonEncodedText.Encode(propertyName.AsSpan()),
jsonIn,
expectedIndent,
expectedMinimal);
}

private static void WritePropertyValue(
Expand Down Expand Up @@ -1156,6 +1168,41 @@ private static void WritePropertyValue(
}
}

private static void WritePropertyValue(
bool indented,
JsonEncodedText propertyName,
string jsonIn,
string expectedIndent,
string expectedMinimal)
{
var buffer = new ArrayBufferWriter<byte>(1024);
using (JsonDocument doc = JsonDocument.Parse($" [ {jsonIn} ]", s_readerOptions))
{
JsonElement target = doc.RootElement[0];

var options = new JsonWriterOptions
{
Indented = indented,
};

var writer = new Utf8JsonWriter(buffer, options);

writer.WriteStartObject();
target.WriteProperty(propertyName, writer);
writer.WriteEndObject();
writer.Flush();

if (indented && s_replaceNewlines)
{
AssertContents(
expectedIndent.Replace(CompiledNewline, Environment.NewLine),
buffer);
}

AssertContents(indented ? expectedIndent : expectedMinimal, buffer);
}
}

private static void AssertContents(string expectedValue, ArrayBufferWriter<byte> buffer)
{
Assert.Equal(
Expand Down

0 comments on commit 5283837

Please sign in to comment.