File: System\Text\Json\Nodes\JsonValueOfElement.cs
Web Access
Project: src\src\libraries\System.Text.Json\src\System.Text.Json.csproj (System.Text.Json)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
 
namespace System.Text.Json.Nodes
{
    /// <summary>
    /// Defines a primitive JSON value that is wrapping a <see cref="JsonElement"/>.
    /// </summary>
    internal sealed class JsonValueOfElement : JsonValue<JsonElement>
    {
        public JsonValueOfElement(JsonElement value, JsonNodeOptions? options) : base(value, options)
        {
            Debug.Assert(value.ValueKind is JsonValueKind.False or JsonValueKind.True or JsonValueKind.Number or JsonValueKind.String);
        }
 
        internal override JsonElement? UnderlyingElement => Value;
        internal override JsonNode DeepCloneCore() => new JsonValueOfElement(Value.Clone(), Options);
        private protected override JsonValueKind GetValueKindCore() => Value.ValueKind;
 
        internal override bool DeepEqualsCore(JsonNode otherNode)
        {
            if (otherNode.UnderlyingElement is JsonElement otherElement)
            {
                return JsonElement.DeepEquals(Value, otherElement);
            }
 
            if (otherNode is JsonValue)
            {
                // Dispatch to the other value in case it knows
                // how to convert JsonElement to its own type.
                return otherNode.DeepEqualsCore(this);
            }
 
            return base.DeepEqualsCore(otherNode);
        }
 
        public override TypeToConvert GetValue<TypeToConvert>()
        {
            if (!TryGetValue(out TypeToConvert? value))
            {
                ThrowHelper.ThrowInvalidOperationException_NodeUnableToConvertElement(Value.ValueKind, typeof(TypeToConvert));
            }
 
            return value;
        }
 
        public override bool TryGetValue<TypeToConvert>([NotNullWhen(true)] out TypeToConvert value)
        {
            bool success;
 
            if (Value is TypeToConvert element)
            {
                value = element;
                return true;
            }
 
            switch (Value.ValueKind)
            {
                case JsonValueKind.Number:
                    if (typeof(TypeToConvert) == typeof(int) || typeof(TypeToConvert) == typeof(int?))
                    {
                        success = Value.TryGetInt32(out int result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(long) || typeof(TypeToConvert) == typeof(long?))
                    {
                        success = Value.TryGetInt64(out long result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(double) || typeof(TypeToConvert) == typeof(double?))
                    {
                        success = Value.TryGetDouble(out double result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(short) || typeof(TypeToConvert) == typeof(short?))
                    {
                        success = Value.TryGetInt16(out short result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(decimal) || typeof(TypeToConvert) == typeof(decimal?))
                    {
                        success = Value.TryGetDecimal(out decimal result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(byte) || typeof(TypeToConvert) == typeof(byte?))
                    {
                        success = Value.TryGetByte(out byte result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(float) || typeof(TypeToConvert) == typeof(float?))
                    {
                        success = Value.TryGetSingle(out float result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(uint) || typeof(TypeToConvert) == typeof(uint?))
                    {
                        success = Value.TryGetUInt32(out uint result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(ushort) || typeof(TypeToConvert) == typeof(ushort?))
                    {
                        success = Value.TryGetUInt16(out ushort result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(ulong) || typeof(TypeToConvert) == typeof(ulong?))
                    {
                        success = Value.TryGetUInt64(out ulong result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(sbyte) || typeof(TypeToConvert) == typeof(sbyte?))
                    {
                        success = Value.TryGetSByte(out sbyte result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
                    break;
 
                case JsonValueKind.String:
                    if (typeof(TypeToConvert) == typeof(string))
                    {
                        string? result = Value.GetString();
                        Debug.Assert(result != null);
                        value = (TypeToConvert)(object)result;
                        return true;
                    }
 
                    if (typeof(TypeToConvert) == typeof(DateTime) || typeof(TypeToConvert) == typeof(DateTime?))
                    {
                        success = Value.TryGetDateTime(out DateTime result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(DateTimeOffset) || typeof(TypeToConvert) == typeof(DateTimeOffset?))
                    {
                        success = Value.TryGetDateTimeOffset(out DateTimeOffset result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(Guid) || typeof(TypeToConvert) == typeof(Guid?))
                    {
                        success = Value.TryGetGuid(out Guid result);
                        value = (TypeToConvert)(object)result;
                        return success;
                    }
 
                    if (typeof(TypeToConvert) == typeof(char) || typeof(TypeToConvert) == typeof(char?))
                    {
                        string? result = Value.GetString();
                        Debug.Assert(result != null);
                        if (result.Length == 1)
                        {
                            value = (TypeToConvert)(object)result[0];
                            return true;
                        }
                    }
                    break;
 
                case JsonValueKind.True:
                case JsonValueKind.False:
                    if (typeof(TypeToConvert) == typeof(bool) || typeof(TypeToConvert) == typeof(bool?))
                    {
                        value = (TypeToConvert)(object)Value.GetBoolean();
                        return true;
                    }
                    break;
            }
 
            value = default!;
            return false;
        }
 
        public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null)
        {
            if (writer is null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(writer));
            }
 
            Value.WriteTo(writer);
        }
    }
}