private static void HandleStartObject(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.Skip()) { state.Push(); state.Current.Drain = true; return; } if (state.Current.IsProcessingEnumerable) { Type objType = state.Current.GetElementType(); state.Push(); state.Current.Initialize(objType, options); } else if (state.Current.JsonPropertyInfo != null) { if (state.Current.IsDictionary) { // Verify that the Dictionary can be deserialized by having <string> as first generic argument. Type[] args = state.Current.JsonClassInfo.Type.GetGenericArguments(); if (args.Length == 0 || args[0].UnderlyingSystemType != typeof(string)) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.PropertyPath); } if (state.Current.ReturnValue == null) { // The Dictionary created below will be returned to corresponding Parse() etc method. // Ensure any nested array creates a new frame. state.Current.EnumerableCreated = true; } else { ClassType classType = state.Current.JsonClassInfo.ElementClassInfo.ClassType; // Verify that the second parameter is not a value. if (state.Current.JsonClassInfo.ElementClassInfo.ClassType == ClassType.Value) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.PropertyPath); } // A nested object, dictionary or enumerable. JsonClassInfo classInfoTemp = state.Current.JsonClassInfo; state.Push(); state.Current.JsonClassInfo = classInfoTemp.ElementClassInfo; state.Current.InitializeJsonPropertyInfo(); } } else { // Nested object. Type objType = state.Current.JsonPropertyInfo.RuntimePropertyType; state.Push(); state.Current.Initialize(objType, options); } } JsonClassInfo classInfo = state.Current.JsonClassInfo; state.Current.ReturnValue = classInfo.CreateObject(); }
internal static bool SingleValueReadWithReadAhead(ClassType classType, ref Utf8JsonReader reader, ref ReadStack state) { bool readAhead = (state.ReadAhead && (classType & (ClassType.Value | ClassType.NewValue)) != 0); if (!readAhead) { return(reader.Read()); } return(DoSingleValueReadWithReadAhead(ref reader, ref state)); }
private static void HandleStartArray( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; bool skip = jsonPropertyInfo != null && !jsonPropertyInfo.ShouldDeserialize; if (skip || state.Current.Skip()) { // The array is not being applied to the object. state.Push(); state.Current.Drain = true; return; } if (jsonPropertyInfo == null || state.Current.JsonClassInfo.ClassType == ClassType.Unknown) { jsonPropertyInfo = state.Current.JsonClassInfo.CreatePolymorphicProperty(jsonPropertyInfo, typeof(object), options); } Type arrayType = jsonPropertyInfo.RuntimePropertyType; if (!typeof(IEnumerable).IsAssignableFrom(arrayType) || (arrayType.IsArray && arrayType.GetArrayRank() > 1)) { ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(arrayType, reader, state); } Debug.Assert(state.Current.IsPropertyEnumerable()); if (state.Current.IsPropertyEnumerable()) { if (state.Current.EnumerableCreated) { // A nested json array so push a new stack frame. Type elementType = state.Current.JsonClassInfo.ElementClassInfo.GetPolicyProperty().RuntimePropertyType; state.Push(); state.Current.Initialize(elementType, options); state.Current.PopStackOnEndArray = true; } else { state.Current.EnumerableCreated = true; } jsonPropertyInfo = state.Current.JsonPropertyInfo; // If current property is already set (from a constructor, for example) leave as-is if (jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue, options) == null) { // Create the enumerable. object value = ReadStackFrame.CreateEnumerableValue(ref reader, ref state, options); if (value != null) { if (state.Current.ReturnValue != null) { state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value, options); } else { // Primitive arrays being returned without object state.Current.SetReturnValue(value, options); } } } } }
/// <summary> /// Creates the instance and assigns it to state.Current.ReturnValue. /// </summary> internal virtual void CreateInstanceForReferenceResolver(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { }
public abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state);
internal override sealed bool TryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state, out object?value) { bool success = TryRead(ref reader, TypeToConvert, options, ref state, out T typedValue); value = typedValue; return(success); }
public abstract void ReadEnumerable(JsonTokenType tokenType, ref ReadStack state, ref Utf8JsonReader reader);
private static bool HandleEndArray( JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { bool lastFrame = state.IsLastFrame; if (state.Current.Drain) { // The array is not being applied to the object. state.Pop(); return(lastFrame); } IEnumerable value = ReadStackFrame.GetEnumerableValue(state.Current); bool setPropertyDirectly; bool popStackOnEnd = state.Current.PopStackOnEnd; if (state.Current.TempEnumerableValues != null) { JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter; Debug.Assert(converter != null); value = converter.CreateFromList(ref state, (IList)value, options); setPropertyDirectly = true; } else if (!popStackOnEnd) { Debug.Assert(state.Current.IsPropertyEnumerable); // We added the items to the list property already. state.Current.ResetProperty(); return(false); } else { setPropertyDirectly = false; } if (popStackOnEnd) { state.Pop(); } if (lastFrame) { if (state.Current.ReturnValue == null) { // Returning a converted list or object. state.Current.Reset(); state.Current.ReturnValue = value; return(true); } else if (state.Current.IsEnumerable || state.Current.IsDictionary) { // Returning a non-converted list. return(true); } // else there must be an outer object, so we'll return false here. } ApplyObjectToEnumerable(value, options, ref state, ref reader, setPropertyDirectly: setPropertyDirectly); if (!popStackOnEnd) { Debug.Assert(state.Current.IsPropertyEnumerable); state.Current.ResetProperty(); } return(false); }
internal override void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { if (ValueConverter != null) { if (ValueConverter.TryRead(s_underlyingType, ref reader, out TProperty value)) { ReadStackFrame.SetReturnValue(value, options, ref state.Current); return; } } ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); }
public override void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { if (ValueConverter == null || !ValueConverter.TryRead(typeof(TProperty), ref reader, out TProperty value)) { ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); return; } // Converting to TProperty? here lets us share a common ApplyValue() with ApplyNullValue(). TProperty?nullableValue = new TProperty?(value); JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current); }
public override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state) { TProperty?nullableValue = null; JsonSerializer.ApplyValueToEnumerable(ref nullableValue, options, ref state.Current); }
/// <summary> /// Initializes the state for polymorphic cases and returns the appropriate derived converter. /// </summary> internal JsonConverter?ResolvePolymorphicConverter(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(!IsValueType); Debug.Assert(CanHaveMetadata); Debug.Assert(state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type)); Debug.Assert(state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted); Debug.Assert(jsonTypeInfo.PolymorphicTypeResolver?.UsesTypeDiscriminators == true); JsonConverter?polymorphicConverter = null; switch (state.Current.PolymorphicSerializationState) { case PolymorphicSerializationState.None: Debug.Assert(!state.IsContinuation); Debug.Assert(state.PolymorphicTypeDiscriminator != null); PolymorphicTypeResolver resolver = jsonTypeInfo.PolymorphicTypeResolver; if (resolver.TryGetDerivedJsonTypeInfo(state.PolymorphicTypeDiscriminator, out JsonTypeInfo? resolvedType)) { Debug.Assert(TypeToConvert.IsAssignableFrom(resolvedType.Type)); polymorphicConverter = state.InitializePolymorphicReEntry(resolvedType); if (!polymorphicConverter.CanHaveMetadata) { ThrowHelper.ThrowNotSupportedException_DerivedConverterDoesNotSupportMetadata(resolvedType.Type); } } else { state.Current.PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryNotFound; } state.PolymorphicTypeDiscriminator = null; break; case PolymorphicSerializationState.PolymorphicReEntrySuspended: polymorphicConverter = state.ResumePolymorphicReEntry(); Debug.Assert(TypeToConvert.IsAssignableFrom(polymorphicConverter.TypeToConvert)); break; case PolymorphicSerializationState.PolymorphicReEntryNotFound: Debug.Assert(state.Current.PolymorphicJsonTypeInfo is null); break; default: Debug.Fail("Unexpected PolymorphicSerializationState."); break; } return(polymorphicConverter); }
// todo: for readability, refactor this method to split by ClassType(Enumerable, Object, or Value) like Write() private static void ReadCore( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { while (reader.Read()) { JsonTokenType tokenType = reader.TokenType; if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); if (HandleValue(tokenType, options, ref reader, ref state)) { return; } } else if (tokenType == JsonTokenType.PropertyName) { if (!state.Current.Drain) { Debug.Assert(state.Current.ReturnValue != default); Debug.Assert(state.Current.JsonClassInfo != default); ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(propertyName, state.Current.PropertyIndex); if (state.Current.JsonPropertyInfo == null) { state.Current.JsonPropertyInfo = s_missingProperty; } state.Current.PropertyIndex++; } } else if (tokenType == JsonTokenType.StartObject) { HandleStartObject(options, ref state); } else if (tokenType == JsonTokenType.EndObject) { if (HandleEndObject(options, ref state)) { return; } } else if (tokenType == JsonTokenType.StartArray) { HandleStartArray(options, ref reader, ref state); } else if (tokenType == JsonTokenType.EndArray) { if (HandleEndArray(options, ref state)) { return; } } else if (tokenType == JsonTokenType.Null) { if (HandleNull(ref reader, ref state, options)) { return; } } } return; }
internal static bool SingleValueReadWithReadAhead(bool requiresReadAhead, ref Utf8JsonReader reader, ref ReadStack state) { bool readAhead = requiresReadAhead && state.ReadAhead; if (!readAhead) { return(reader.Read()); } return(DoSingleValueReadWithReadAhead(ref reader, ref state)); }
private static void HandleEndDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.IsDictionaryProperty) { // We added the items to the dictionary already. state.Current.ResetProperty(); } else if (state.Current.IsImmutableDictionaryProperty) { Debug.Assert(state.Current.TempDictionaryValues != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, CreateImmutableDictionaryFromTempValues(ref state, options)); state.Current.ResetProperty(); } else { object value; if (state.Current.TempDictionaryValues != null) { value = CreateImmutableDictionaryFromTempValues(ref state, options); } else { value = state.Current.ReturnValue; } if (state.IsLastFrame) { // Set the return value directly since this will be returned to the user. state.Current.Reset(); state.Current.ReturnValue = value; } else { state.Pop(); ApplyObjectToEnumerable(value, ref state, ref reader); } } }
internal override void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { if (ElementClassInfo != null) { // Forward the setter to the value-based JsonPropertyInfo. JsonPropertyInfo propertyInfo = ElementClassInfo.GetPolicyProperty(); propertyInfo.ReadEnumerable(tokenType, options, ref state, ref reader); } else if (ShouldDeserialize) { if (ValueConverter != null) { if (ValueConverter.TryRead(RuntimePropertyType, ref reader, out TRuntimeProperty value)) { if (state.Current.ReturnValue == null) { state.Current.ReturnValue = value; } else { // Null values were already handled. Debug.Assert(value != null); Set((TClass)state.Current.ReturnValue, value); } return; } } ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); } }
internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNull] out T value) { if (ClassType == ClassType.Value) { // A value converter should never be within a continuation. Debug.Assert(!state.IsContinuation); // For perf and converter simplicity, handle null here instead of forwarding to the converter. if (reader.TokenType == JsonTokenType.Null && !HandleNull) { if (!CanBeNull) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); } value = default; return(true); } #if !DEBUG // For performance, only perform validation on internal converters on debug builds. if (IsInternalConverter) { value = Read(ref reader, typeToConvert, options); } else #endif { JsonTokenType originalPropertyTokenType = reader.TokenType; int originalPropertyDepth = reader.CurrentDepth; long originalPropertyBytesConsumed = reader.BytesConsumed; value = Read(ref reader, typeToConvert, options); VerifyRead( originalPropertyTokenType, originalPropertyDepth, originalPropertyBytesConsumed, isValueConverter: true, ref reader); } if (CanBePolymorphic && options.ReferenceHandler != null) { // Edge case where we want to lookup for a reference when parsing into typeof(object) // instead of return `value` as a JsonElement. Debug.Assert(TypeToConvert == typeof(object)); Debug.Assert(value is JsonElement); if (JsonSerializer.TryGetReferenceFromJsonElement(ref state, (JsonElement)(object)value, out object?referenceValue)) { value = (T)referenceValue; } } return(true); } bool success; // Remember if we were a continuation here since Push() may affect IsContinuation. bool wasContinuation = state.IsContinuation; state.Push(); #if !DEBUG // For performance, only perform validation on internal converters on debug builds. if (IsInternalConverter) { if (reader.TokenType == JsonTokenType.Null && !HandleNull && !wasContinuation) { if (!CanBeNull) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); } // For perf and converter simplicity, handle null here instead of forwarding to the converter. value = default; success = true; } else { success = OnTryRead(ref reader, typeToConvert, options, ref state, out value); } } else #endif { if (!wasContinuation) { // For perf and converter simplicity, handle null here instead of forwarding to the converter. if (reader.TokenType == JsonTokenType.Null && !HandleNull) { if (!CanBeNull) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); } value = default; state.Pop(true); return(true); } Debug.Assert(state.Current.OriginalTokenType == JsonTokenType.None); state.Current.OriginalTokenType = reader.TokenType; Debug.Assert(state.Current.OriginalDepth == 0); state.Current.OriginalDepth = reader.CurrentDepth; } success = OnTryRead(ref reader, typeToConvert, options, ref state, out value); if (success) { if (state.IsContinuation) { // The resumable converter did not forward to the next converter that previously returned false. ThrowHelper.ThrowJsonException_SerializationConverterRead(this); } VerifyRead( state.Current.OriginalTokenType, state.Current.OriginalDepth, bytesConsumed: 0, isValueConverter: false, ref reader); // No need to clear state.Current.* since a stack pop will occur. } } state.Pop(success); return(success); }
// If this method is changed, also change JsonPropertyInfoNullable.ReadEnumerable and JsonSerializer.ApplyObjectToEnumerable internal override void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader) { if (ValueConverter == null || !ValueConverter.TryRead(RuntimePropertyType, ref reader, out TRuntimeProperty value)) { ThrowHelper.ThrowJsonReaderException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state); return; } JsonSerializer.ApplyValueToEnumerable(ref value, options, ref state.Current); }
// Provide a default implementation for value converters. internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNull] out T value) { value = Read(ref reader, typeToConvert, options); return(true); }
internal override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state) { Debug.Assert(state.Current.JsonPropertyInfo != null); state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null, options); }
internal abstract bool TryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state, out object?value);
private static void ReadCore( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { try { while (reader.Read()) { JsonTokenType tokenType = reader.TokenType; if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); if (HandleValue(tokenType, options, ref reader, ref state)) { continue; } } else if (tokenType == JsonTokenType.PropertyName) { HandlePropertyName(options, ref reader, ref state); } else if (tokenType == JsonTokenType.StartObject) { if (state.Current.SkipProperty) { state.Push(); state.Current.Drain = true; } else if (state.Current.IsProcessingValue) { if (HandleValue(tokenType, options, ref reader, ref state)) { continue; } } else if (state.Current.IsProcessingDictionary) { HandleStartDictionary(options, ref reader, ref state); } else { HandleStartObject(options, ref reader, ref state); } } else if (tokenType == JsonTokenType.EndObject) { if (state.Current.Drain) { state.Pop(); } else if (state.Current.IsProcessingDictionary) { HandleEndDictionary(options, ref reader, ref state); } else { HandleEndObject(options, ref reader, ref state); } } else if (tokenType == JsonTokenType.StartArray) { if (!state.Current.IsProcessingValue) { HandleStartArray(options, ref reader, ref state); } else if (HandleValue(tokenType, options, ref reader, ref state)) { continue; } } else if (tokenType == JsonTokenType.EndArray) { if (HandleEndArray(options, ref reader, ref state)) { continue; } } else if (tokenType == JsonTokenType.Null) { if (HandleNull(ref reader, ref state, options)) { continue; } } } } catch (JsonReaderException e) { // Re-throw with Path information. ThrowHelper.ReThrowWithPath(e, state.PropertyPath); } return; }
/// <summary> /// Loosely-typed ReadCore() that forwards to strongly-typed ReadCore(). /// </summary> internal abstract object?ReadCoreAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state);
// todo: for readability, refactor this method to split by ClassType(Enumerable, Object, or Value) like Write() private static void ReadCore( JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { while (reader.Read()) { JsonTokenType tokenType = reader.TokenType; if (JsonHelpers.IsInRangeInclusive(tokenType, JsonTokenType.String, JsonTokenType.False)) { Debug.Assert(tokenType == JsonTokenType.String || tokenType == JsonTokenType.Number || tokenType == JsonTokenType.True || tokenType == JsonTokenType.False); if (HandleValue(tokenType, options, ref reader, ref state)) { return; } } else if (tokenType == JsonTokenType.PropertyName) { if (!state.Current.Drain) { Debug.Assert(state.Current.ReturnValue != default); Debug.Assert(state.Current.JsonClassInfo != default); if (state.Current.IsDictionary) { string keyName = reader.GetString(); if (options.DictionaryKeyPolicy != null) { keyName = options.DictionaryKeyPolicy.ConvertName(keyName); } state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetPolicyProperty(); state.Current.KeyName = keyName; } else { ReadOnlySpan <byte> propertyName = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; if (reader._stringHasEscaping) { int idx = propertyName.IndexOf(JsonConstants.BackSlash); Debug.Assert(idx != -1); propertyName = GetUnescapedString(propertyName, idx); } state.Current.JsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(options, propertyName, ref state.Current); if (state.Current.JsonPropertyInfo == null) { state.Current.JsonPropertyInfo = s_missingProperty; } state.Current.PropertyIndex++; } } } else if (tokenType == JsonTokenType.StartObject) { HandleStartObject(options, ref reader, ref state); } else if (tokenType == JsonTokenType.EndObject) { if (HandleEndObject(options, ref state)) { return; } } else if (tokenType == JsonTokenType.StartArray) { HandleStartArray(options, ref reader, ref state); } else if (tokenType == JsonTokenType.EndArray) { if (HandleEndArray(options, ref state)) { return; } } else if (tokenType == JsonTokenType.Null) { if (HandleNull(ref reader, ref state, options)) { return; } } } return; }
public abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
private static async ValueTask <TValue> ReadAsync <TValue>( Stream utf8Json, Type returnType, JsonSerializerOptions options = null, CancellationToken cancellationToken = default) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } ReadStack state = default; state.Current.Initialize(returnType, options); var readerState = new JsonReaderState(options.GetReaderOptions()); // todo: switch to ArrayBuffer implementation to handle and simplify the allocs? byte[] buffer = ArrayPool <byte> .Shared.Rent(options.DefaultBufferSize); int bytesInBuffer = 0; long totalBytesRead = 0; int clearMax = 0; try { while (true) { // Read from the stream until either our buffer is filled or we hit EOF. // Calling ReadCore is relatively expensive, so we minimize the number of times // we need to call it. bool isFinalBlock = false; while (true) { int bytesRead = await utf8Json.ReadAsync( #if BUILDING_INBOX_LIBRARY buffer.AsMemory(bytesInBuffer), #else buffer, bytesInBuffer, buffer.Length - bytesInBuffer, #endif cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { isFinalBlock = true; break; } totalBytesRead += bytesRead; bytesInBuffer += bytesRead; if (bytesInBuffer == buffer.Length) { break; } } if (bytesInBuffer > clearMax) { clearMax = bytesInBuffer; } // Process the data available ReadCore( ref readerState, isFinalBlock, new Span <byte>(buffer, 0, bytesInBuffer), options, ref state); Debug.Assert(readerState.BytesConsumed <= bytesInBuffer); int bytesConsumed = (int)readerState.BytesConsumed; bytesInBuffer -= bytesConsumed; if (isFinalBlock) { break; } // Check if we need to shift or expand the buffer because there wasn't enough data to complete deserialization. if ((uint)bytesInBuffer > ((uint)buffer.Length / 2)) { // We have less than half the buffer available, double the buffer size. byte[] dest = ArrayPool <byte> .Shared.Rent((buffer.Length < (int.MaxValue / 2))?buffer.Length * 2 : int.MaxValue); // Copy the unprocessed data to the new buffer while shifting the processed bytes. Buffer.BlockCopy(buffer, bytesConsumed, dest, 0, bytesInBuffer); new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); clearMax = bytesInBuffer; buffer = dest; } else if (bytesInBuffer != 0) { // Shift the processed bytes to the beginning of buffer to make more room. Buffer.BlockCopy(buffer, bytesConsumed, buffer, 0, bytesInBuffer); } } } finally { // Clear only what we used and return the buffer to the pool new Span <byte>(buffer, 0, clearMax).Clear(); ArrayPool <byte> .Shared.Return(buffer); } if (bytesInBuffer != 0) { throw new JsonReaderException( SR.Format(SR.DeserializeDataRemaining, totalBytesRead, bytesInBuffer), readerState); } return((TValue)state.Current.ReturnValue); }
internal static bool DoSingleValueReadWithReadAhead(ref Utf8JsonReader reader, ref ReadStack state) { // When we're reading ahead we always have to save the state as we don't know if the next token // is an opening object or an array brace. JsonReaderState initialReaderState = reader.CurrentState; long initialReaderBytesConsumed = reader.BytesConsumed; if (!reader.Read()) { return(false); } // Perform the actual read-ahead. JsonTokenType tokenType = reader.TokenType; if (tokenType == JsonTokenType.StartObject || tokenType == JsonTokenType.StartArray) { // Attempt to skip to make sure we have all the data we need. bool complete = reader.TrySkip(); // We need to restore the state in all cases as we need to be positioned back before // the current token to either attempt to skip again or to actually read the value. reader = new Utf8JsonReader(reader.OriginalSpan.Slice(checked ((int)initialReaderBytesConsumed)), isFinalBlock: reader.IsFinalBlock, state: initialReaderState); Debug.Assert(reader.BytesConsumed == 0); state.BytesConsumed += initialReaderBytesConsumed; if (!complete) { // Couldn't read to the end of the object, exit out to get more data in the buffer. return(false); } // Success, requeue the reader to the start token. reader.ReadWithVerify(); Debug.Assert(tokenType == reader.TokenType); } return(true); }
private static void HandleStartDictionary(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { Debug.Assert(!state.Current.IsProcessingEnumerable); JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo; if (jsonPropertyInfo == null) { jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options); } Debug.Assert(jsonPropertyInfo != null); // A nested object or dictionary so push new frame. if (state.Current.PropertyInitialized) { state.Push(); state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo; state.Current.InitializeJsonPropertyInfo(); state.Current.PropertyInitialized = true; ClassType classType = state.Current.JsonClassInfo.ClassType; if (classType == ClassType.Value && jsonPropertyInfo.ElementClassInfo.Type != typeof(object) && jsonPropertyInfo.ElementClassInfo.Type != typeof(JsonElement)) { ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type, reader, state.JsonPath); } JsonClassInfo classInfo = state.Current.JsonClassInfo; if (state.Current.IsProcessingImmutableDictionary) { state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateObject(); } else { state.Current.ReturnValue = classInfo.CreateObject(); } return; } state.Current.PropertyInitialized = true; if (state.Current.IsProcessingImmutableDictionary) { JsonClassInfo dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType); state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateObject(); } // Else if current property is already set (from a constructor, for example), leave as-is. else if (jsonPropertyInfo.GetValueAsObject(state.Current.ReturnValue) == null) { // Create the dictionary. JsonClassInfo dictionaryClassInfo = jsonPropertyInfo.RuntimeClassInfo; IDictionary value = (IDictionary)dictionaryClassInfo.CreateObject(); if (value != null) { if (state.Current.ReturnValue != null) { state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value); } else { // A dictionary is being returned directly, or a nested dictionary. state.Current.SetReturnValue(value); } } } }
private static bool HandleEndArray( JsonSerializerOptions options, ref ReadStack state) { bool lastFrame = state.IsLastFrame; if (state.Current.Drain) { // The array is not being applied to the object. state.Pop(); return(lastFrame); } IEnumerable value = ReadStackFrame.GetEnumerableValue(state.Current); if (value == null) { // We added the items to the list property already. state.Current.ResetProperty(); return(false); } bool setPropertyDirectly; if (state.Current.TempEnumerableValues != null) { JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter; Debug.Assert(converter != null); Type elementType = state.Current.GetElementType(); value = converter.CreateFromList(elementType, (IList)value); setPropertyDirectly = true; } else { setPropertyDirectly = false; } bool valueReturning = state.Current.PopStackOnEndArray; if (state.Current.PopStackOnEndArray) { state.Pop(); } if (lastFrame) { if (state.Current.ReturnValue == null) { // Returning a converted list or object. state.Current.Reset(); state.Current.ReturnValue = value; return(true); } else if (state.Current.IsEnumerable()) { // Returning a non-converted list. return(true); } // else there must be an outer object, so we'll return false here. } ReadStackFrame.SetReturnValue(value, options, ref state.Current, setPropertyDirectly: setPropertyDirectly); if (!valueReturning) { state.Current.ResetProperty(); } return(false); }
internal abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);