private object DeserializeObject(object resultValue, InputObjectType type, Path path) { if (resultValue is IReadOnlyDictionary <string, object?> map) { var fieldValues = new object?[type.Fields.Count]; var consumed = 0; for (var i = 0; i < type.Fields.Count; i++) { InputField field = type.Fields[i]; if (map.TryGetValue(field.Name.Value, out var fieldValue)) { Path fieldPath = path.Append(field.Name); if (fieldValue is null && field.Type.Kind == TypeKind.NonNull) { throw NonNullInputViolation(type, fieldPath, field); } var value = Deserialize(fieldValue, field.Type, fieldPath, field); value = FormatValue(field, value); value = ConvertValue(field.RuntimeType, value); if (field.IsOptional) { value = new Optional(value, true); } fieldValues[i] = value; consumed++; } else { fieldValues[i] = CreateDefaultValue(field, path.Append(field.Name), 0); } } if (consumed < map.Count) { var invalidFieldNames = new List <string>(); foreach (string key in map.Keys) { if (!type.Fields.ContainsField(key)) { invalidFieldNames.Add(key); } } throw InvalidInputFieldNames(type, invalidFieldNames, path); } return(type.CreateInstance(fieldValues)); } if (type.RuntimeType != typeof(object) && type.RuntimeType.IsInstanceOfType(resultValue)) { return(resultValue); } if (resultValue is ObjectValueNode node) { return(ParseObject(node, type, path, 0, true)); } throw ParseInputObject_InvalidObjectKind(type, resultValue.GetType(), path); }
private object ParseObject( IValueNode resultValue, InputObjectType type, Path path, int stack, bool defaults) { if (resultValue.Kind == SyntaxKind.ObjectValue) { bool[]? processedBuffer = null; Span <bool> processed = stack <= 256 && type.Fields.Count <= 32 ? stackalloc bool[type.Fields.Count] : processedBuffer = ArrayPool <bool> .Shared.Rent(type.Fields.Count); var processedCount = 0; if (processedBuffer is null) { stack += type.Fields.Count; } var fieldValues = new object?[type.Fields.Count]; List <string>?invalidFieldNames = null; try { IReadOnlyList <ObjectFieldNode> fields = ((ObjectValueNode)resultValue).Fields; for (var i = 0; i < fields.Count; i++) { ObjectFieldNode fieldValue = fields[i]; if (type.Fields.TryGetField(fieldValue.Name.Value, out InputField? field)) { IValueNode literal = fieldValue.Value; Path fieldPath = path.Append(field.Name); if (literal.Kind == SyntaxKind.NullValue && field.Type.Kind == TypeKind.NonNull) { throw NonNullInputViolation(type, fieldPath, field); } var value = ParseLiteralInternal( literal, field.Type, fieldPath, stack, defaults, field); value = FormatValue(field, value); value = ConvertValue(field.RuntimeType, value); if (field.IsOptional) { value = new Optional(value, true); } fieldValues[field.Index] = value; processed[field.Index] = true; processedCount++; } else { invalidFieldNames ??= new List <string>(); invalidFieldNames.Add(fieldValue.Name.Value); } } if (invalidFieldNames?.Count > 0) { throw InvalidInputFieldNames(type, invalidFieldNames, path); } if (processedCount < type.Fields.Count) { for (var i = 0; i < type.Fields.Count; i++) { if (!processed[i]) { InputField field = type.Fields[i]; Path fieldPath = path.Append(field.Name); fieldValues[i] = CreateDefaultValue(field, fieldPath, stack); } } } } finally { if (processedBuffer is not null) { ArrayPool <bool> .Shared.Return(processedBuffer); } } return(type.CreateInstance(fieldValues)); } throw ParseInputObject_InvalidSyntaxKind(type, resultValue.Kind, path); }