Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ private JsonEncodedText(byte[] utf8Value)
_utf8Value = utf8Value;
}

private JsonEncodedText(string stringValue, byte[] utf8Value)
{
Debug.Assert(stringValue != null);
Debug.Assert(utf8Value != null);

_value = stringValue;
_utf8Value = utf8Value;
}

/// <summary>
/// Encodes the string text value as a JSON string.
/// </summary>
Expand Down Expand Up @@ -125,6 +134,37 @@ private static JsonEncodedText EncodeHelper(ReadOnlySpan<byte> utf8Value, JavaSc
}
}

/// <summary>
/// Internal version that keeps the existing string and byte[] references if there is no escaping required.
/// </summary>
internal static JsonEncodedText Encode(string stringValue, byte[] utf8Value, JavaScriptEncoder? encoder = null)
{
Debug.Assert(stringValue.Equals(JsonHelpers.Utf8GetString(utf8Value)));

if (utf8Value.Length == 0)
{
return new JsonEncodedText(stringValue, utf8Value);
}

JsonWriterHelper.ValidateValue(utf8Value);
return EncodeHelper(stringValue, utf8Value, encoder);
}

private static JsonEncodedText EncodeHelper(string stringValue, byte[] utf8Value, JavaScriptEncoder? encoder)
{
int idx = JsonWriterHelper.NeedsEscaping(utf8Value, encoder);

if (idx != -1)
{
return new JsonEncodedText(GetEscapedString(utf8Value, idx, encoder));
}
else
{
// Encoding is not necessary; use the same stringValue and utf8Value references.
return new JsonEncodedText(stringValue, utf8Value);
}
}

private static byte[] GetEscapedString(ReadOnlySpan<byte> utf8Value, int firstEscapeIndexVal, JavaScriptEncoder? encoder)
{
Debug.Assert(int.MaxValue / JsonConstants.MaxExpansionFactorWhileEscaping >= utf8Value.Length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ internal sealed class LargeObjectWithParameterizedConstructorConverter<T> : Obje
{
protected override bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo)
{
bool success = jsonParameterInfo.ReadJson(ref state, ref reader, out object? arg0);
bool success = jsonParameterInfo.ReadJson(ref state, ref reader, out object? arg);

if (success)
{
((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.Position] = arg0!;
((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.Position] = arg!;
}

return success;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,41 +454,19 @@ private bool TryLookupConstructorParameter(

ReadOnlySpan<byte> unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options);

if (!state.Current.JsonClassInfo.TryGetParameter(unescapedPropertyName, ref state.Current, out jsonParameterInfo))
{
return false;
}

Debug.Assert(jsonParameterInfo != null);
jsonParameterInfo = state.Current.JsonClassInfo.GetParameter(
unescapedPropertyName,
ref state.Current,
out byte[] utf8PropertyName);

// Increment ConstructorParameterIndex so GetProperty() starts with the next parameter the next time this function is called.
// Increment ConstructorParameterIndex so GetParameter() checks the next parameter first when called again.
state.Current.CtorArgumentState!.ParameterIndex++;

// Support JsonException.Path.
Debug.Assert(
jsonParameterInfo.JsonPropertyName == null ||
options.PropertyNameCaseInsensitive ||
unescapedPropertyName.SequenceEqual(jsonParameterInfo.JsonPropertyName));

if (jsonParameterInfo.JsonPropertyName == null)
{
byte[] propertyNameArray = unescapedPropertyName.ToArray();
if (options.PropertyNameCaseInsensitive)
{
// Each payload can have a different name here; remember the value on the temporary stack.
state.Current.JsonPropertyName = propertyNameArray;
}
else
{
//Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName
// so it will match the incoming payload except when case insensitivity is enabled(which is handled above).
jsonParameterInfo.JsonPropertyName = propertyNameArray;
}
}
// For case insensitive and missing property support of JsonPath, remember the value on the temporary stack.
state.Current.JsonPropertyName = utf8PropertyName;

state.Current.CtorArgumentState.JsonParameterInfo = jsonParameterInfo;

return true;
return jsonParameterInfo != null;
}

internal override bool ConstructorIsParameterized => true;
Expand Down
Loading