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();
        }
예제 #2
0
        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));
        }
예제 #3
0
        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);
                        }
                    }
                }
            }
        }
예제 #4
0
 /// <summary>
 /// Creates the instance and assigns it to state.Current.ReturnValue.
 /// </summary>
 internal virtual void CreateInstanceForReferenceResolver(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options)
 {
 }
예제 #5
0
 public abstract void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state);
예제 #6
0
        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);
        }
예제 #7
0
 public abstract void ReadEnumerable(JsonTokenType tokenType, ref ReadStack state, ref Utf8JsonReader reader);
예제 #8
0
        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);
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #13
0
        // 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;
        }
예제 #14
0
        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);
                }
            }
        }
예제 #16
0
        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);
            }
        }
예제 #17
0
        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);
        }
예제 #18
0
        // 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);
        }
예제 #19
0
 // 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);
 }
예제 #20
0
 internal override void ApplyNullValue(JsonSerializerOptions options, ref ReadStack state)
 {
     Debug.Assert(state.Current.JsonPropertyInfo != null);
     state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, null, options);
 }
예제 #21
0
 internal abstract bool TryReadAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state, out object?value);
예제 #22
0
        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;
        }
예제 #23
0
 /// <summary>
 /// Loosely-typed ReadCore() that forwards to strongly-typed ReadCore().
 /// </summary>
 internal abstract object?ReadCoreAsObject(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state);
예제 #24
0
        // 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;
        }
예제 #25
0
 public abstract void ReadEnumerable(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);
예제 #26
0
        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);
        }
예제 #27
0
        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);
                    }
                }
            }
        }
예제 #29
0
        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);
        }
예제 #30
0
 internal abstract void Read(JsonTokenType tokenType, JsonSerializerOptions options, ref ReadStack state, ref Utf8JsonReader reader);