Skip to content

Commit

Permalink
Add quirks
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers committed Nov 13, 2023
1 parent 917f408 commit 2eb2462
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ static async Task<RelationalDataReader> InitializeReaderAsync(

tokenType = manager.MoveNext();
}
else if (!UseOldBehavior32235)
else if (!Utf8JsonReaderManager.UseOldBehavior32235)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
Expand Down Expand Up @@ -1048,7 +1048,7 @@ private static void IncludeJsonEntityCollection<TIncludingEntity, TIncludedColle

tokenType = manager.MoveNext();
}
else if (!UseOldBehavior32235)
else if (!Utf8JsonReaderManager.UseOldBehavior32235)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ namespace Microsoft.EntityFrameworkCore.Query;

public partial class RelationalShapedQueryCompilingExpressionVisitor
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static readonly bool UseOldBehavior32235 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32235", out var enabled32235) && enabled32235;

private sealed partial class ShaperProcessingExpressionVisitor : ExpressionVisitor
{
/// <summary>
Expand Down Expand Up @@ -1842,7 +1833,7 @@ void ProcessFixup(IDictionary<string, LambdaExpression> fixupMap)
Switch(
tokenTypeVariable,
Block(
UseOldBehavior32235
Utf8JsonReaderManager.UseOldBehavior32235
? Call(
Field(managerVariable, Utf8JsonReaderManagerCurrentReaderField),
Utf8JsonReaderTrySkipMethod)
Expand Down
88 changes: 56 additions & 32 deletions src/EFCore/Storage/Json/JsonCollectionReaderWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,44 +46,68 @@ public JsonCollectionReaderWriter(JsonValueReaderWriter<TElement> elementReaderW
collection.Clear();
}

if (manager.CurrentReader.TokenType == JsonTokenType.None)
if (Utf8JsonReaderManager.UseOldBehavior32235)
{
manager.MoveNext();
}
while (manager.CurrentReader.TokenType != JsonTokenType.EndArray)
{
manager.MoveNext();

var tokenType = manager.CurrentReader.TokenType;
if (tokenType != JsonTokenType.StartArray)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
switch (manager.CurrentReader.TokenType)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(default);
break;
}
}
}

while (tokenType != JsonTokenType.EndArray)
else
{
manager.MoveNext();
tokenType = manager.CurrentReader.TokenType;
if (manager.CurrentReader.TokenType == JsonTokenType.None)
{
manager.MoveNext();
}

var tokenType = manager.CurrentReader.TokenType;
if (tokenType != JsonTokenType.StartArray)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
}

switch (tokenType)
while (tokenType != JsonTokenType.EndArray)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(default);
break;
case JsonTokenType.Comment:
break;
case JsonTokenType.None: // Explicitly listing all states that we throw for
case JsonTokenType.StartObject:
case JsonTokenType.EndObject:
case JsonTokenType.StartArray:
case JsonTokenType.PropertyName:
default:
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
manager.MoveNext();
tokenType = manager.CurrentReader.TokenType;

switch (tokenType)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(default);
break;
case JsonTokenType.Comment:
case JsonTokenType.EndArray:
break;
case JsonTokenType.None: // Explicitly listing all states that we throw for
case JsonTokenType.StartObject:
case JsonTokenType.EndObject:
case JsonTokenType.StartArray:
case JsonTokenType.PropertyName:
default:
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
}
}
}

Expand Down
88 changes: 56 additions & 32 deletions src/EFCore/Storage/Json/JsonNullableStructCollectionReaderWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,44 +47,68 @@ public JsonNullableStructCollectionReaderWriter(JsonValueReaderWriter<TElement>
collection.Clear();
}

if (manager.CurrentReader.TokenType == JsonTokenType.None)
if (Utf8JsonReaderManager.UseOldBehavior32235)
{
manager.MoveNext();
}
while (manager.CurrentReader.TokenType != JsonTokenType.EndArray)
{
manager.MoveNext();

var tokenType = manager.CurrentReader.TokenType;
if (tokenType != JsonTokenType.StartArray)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
switch (manager.CurrentReader.TokenType)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(null);
break;
}
}
}

while (tokenType != JsonTokenType.EndArray)
else
{
manager.MoveNext();
tokenType = manager.CurrentReader.TokenType;
if (manager.CurrentReader.TokenType == JsonTokenType.None)
{
manager.MoveNext();
}

var tokenType = manager.CurrentReader.TokenType;
if (tokenType != JsonTokenType.StartArray)
{
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
}

switch (tokenType)
while (tokenType != JsonTokenType.EndArray)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(null);
break;
case JsonTokenType.Comment:
break;
case JsonTokenType.None: // Explicitly listing all states that we throw for
case JsonTokenType.StartObject:
case JsonTokenType.EndObject:
case JsonTokenType.StartArray:
case JsonTokenType.PropertyName:
default:
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
manager.MoveNext();
tokenType = manager.CurrentReader.TokenType;

switch (tokenType)
{
case JsonTokenType.String:
case JsonTokenType.Number:
case JsonTokenType.True:
case JsonTokenType.False:
collection.Add(_elementReaderWriter.FromJsonTyped(ref manager));
break;
case JsonTokenType.Null:
collection.Add(null);
break;
case JsonTokenType.EndArray:
case JsonTokenType.Comment:
break;
case JsonTokenType.None: // Explicitly listing all states that we throw for
case JsonTokenType.StartObject:
case JsonTokenType.EndObject:
case JsonTokenType.StartArray:
case JsonTokenType.PropertyName:
default:
throw new InvalidOperationException(
CoreStrings.JsonReaderInvalidTokenType(tokenType.ToString()));
}
}
}

Expand Down
44 changes: 37 additions & 7 deletions src/EFCore/Storage/Json/JsonReaderData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,9 @@ public virtual void CaptureState(ref Utf8JsonReaderManager manager)
/// <returns>The new <see cref="Utf8JsonReader" />, having read my bytes from the stream.</returns>
public virtual Utf8JsonReader ReadBytes(int bytesConsumed, JsonReaderState state)
{
if (_stream == null)
{
_bytesAvailable = 0;
}
else
if (Utf8JsonReaderManager.UseOldBehavior32235)
{
Check.DebugAssert(_stream != null, "Only needed when buffer doesn't contain full JSON document.");

var buffer = _buffer;
var totalConsumed = bytesConsumed + _positionInBuffer;
Expand All @@ -83,10 +80,43 @@ public virtual Utf8JsonReader ReadBytes(int bytesConsumed, JsonReaderState state
}

_buffer = buffer;
_positionInBuffer = 0;
_readerState = state;
}
else
{
if (_stream == null)
{
_bytesAvailable = 0;
}
else
{

_positionInBuffer = 0;
_readerState = state;
var buffer = _buffer;
var totalConsumed = bytesConsumed + _positionInBuffer;
if (_bytesAvailable != 0 && totalConsumed < buffer.Length)
{
var leftover = buffer.AsSpan(totalConsumed);

if (leftover.Length == buffer.Length)
{
Array.Resize(ref buffer, buffer.Length * 2);
}

leftover.CopyTo(buffer);
_bytesAvailable = _stream.Read(buffer.AsSpan(leftover.Length)) + leftover.Length;
}
else
{
_bytesAvailable = _stream.Read(buffer);
}

_buffer = buffer;
}

_positionInBuffer = 0;
_readerState = state;
}

return CreateReader();
}
Expand Down
9 changes: 9 additions & 0 deletions src/EFCore/Storage/Json/Utf8JsonReaderManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ namespace Microsoft.EntityFrameworkCore.Storage.Json;
/// </remarks>
public ref struct Utf8JsonReaderManager
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static readonly bool UseOldBehavior32235 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32235", out var enabled32235) && enabled32235;

/// <summary>
/// Tracks state and underlying stream or buffer of UTF8 bytes.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public class PointType
[InlineData("""{"Prop":[-128,],23]}""")]
[InlineData("""{"Prop":[-128,},23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
public virtual void Throws_for_bad_collection_of_sbyte_JSON_values(string json)
=> Throws_for_bad_JSON_value<Int8CollectionType, List<sbyte>>(
nameof(Int8CollectionType.Int8),
Expand All @@ -81,7 +80,6 @@ protected class Int8CollectionType
[InlineData("""{"Prop":[-128,],23]}""")]
[InlineData("""{"Prop":[-128,},23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
[InlineData("""{"Prop":[-128,,23]}""")]
public virtual void Throws_for_bad_collection_of_nullable_long_JSON_values(string json)
=> Throws_for_bad_JSON_value<NullableInt64CollectionType, List<long?>>(
nameof(NullableInt64CollectionType.Int64),
Expand Down

0 comments on commit 2eb2462

Please sign in to comment.