| File: System\Text\Json\Nodes\JsonValueOfJsonPrimitive.cs | Web Access |
| Project: src\runtime\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.Buffers; using System.Buffers.Text; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Encodings.Web; namespace System.Text.Json.Nodes { internal static class JsonValueOfJsonPrimitive { internal static JsonValue CreatePrimitiveValue(ref Utf8JsonReader reader, JsonNodeOptions options) { switch (reader.TokenType) { case JsonTokenType.False: case JsonTokenType.True: return new JsonValueOfJsonBool(reader.GetBoolean(), options); case JsonTokenType.String: byte[] buffer = new byte[reader.ValueLength]; ReadOnlyMemory<byte> utf8String = buffer.AsMemory(0, reader.CopyString(buffer)); return new JsonValueOfJsonString(utf8String, options); case JsonTokenType.Number: byte[] numberValue = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan.ToArray(); return new JsonValueOfJsonNumber(numberValue, options); default: Debug.Fail("Only primitives allowed."); ThrowHelper.ThrowJsonException(); return null!; // Unreachable, but required for compilation. } } } internal sealed class JsonValueOfJsonString : JsonValue { private readonly ReadOnlyMemory<byte> _value; internal JsonValueOfJsonString(ReadOnlyMemory<byte> utf8String, JsonNodeOptions? options) : base(options) { _value = utf8String; } internal override JsonNode DeepCloneCore() => new JsonValueOfJsonString(_value, Options); private protected override JsonValueKind GetValueKindCore() => JsonValueKind.String; public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) { ArgumentNullException.ThrowIfNull(writer); writer.WriteStringValue(_value.Span); } public override T GetValue<T>() { if (!TryGetValue(out T? value)) { ThrowHelper.ThrowInvalidOperationException_NodeUnableToConvertElement(JsonValueKind.String, typeof(T)); } return value; } public override bool TryGetValue<T>([NotNullWhen(true)] out T? value) where T : default { if (typeof(T) == typeof(JsonElement) || typeof(T) == typeof(JsonElement?) || typeof(T) == typeof(object)) { value = (T)(object)JsonWriterHelper.WriteString(_value.Span, static serialized => JsonElement.Parse(serialized)); return true; } if (typeof(T) == typeof(string)) { string? result = JsonReaderHelper.TranscodeHelper(_value.Span); Debug.Assert(result is not null); value = (T)(object)result; return true; } bool success; if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?)) { success = JsonReaderHelper.TryGetValue(_value.Span, isEscaped: false, out DateTime result); value = (T)(object)result; return success; } if (typeof(T) == typeof(DateTimeOffset) || typeof(T) == typeof(DateTimeOffset?)) { success = JsonReaderHelper.TryGetValue(_value.Span, isEscaped: false, out DateTimeOffset result); value = (T)(object)result; return success; } if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?)) { success = JsonReaderHelper.TryGetValue(_value.Span, isEscaped: false, out Guid result); value = (T)(object)result; return success; } if (typeof(T) == typeof(char) || typeof(T) == typeof(char?)) { string? result = JsonReaderHelper.TranscodeHelper(_value.Span); Debug.Assert(result is not null); if (result.Length == 1) { value = (T)(object)result[0]; return true; } } value = default!; return false; } } internal sealed class JsonValueOfJsonBool : JsonValue { private readonly bool _value; private JsonValueKind ValueKind => _value ? JsonValueKind.True : JsonValueKind.False; internal JsonValueOfJsonBool(bool value, JsonNodeOptions? options) : base(options) { _value = value; } public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) => writer.WriteBooleanValue(_value); internal override JsonNode DeepCloneCore() => new JsonValueOfJsonBool(_value, Options); private protected override JsonValueKind GetValueKindCore() => ValueKind; public override T GetValue<T>() { if (!TryGetValue(out T? value)) { ThrowHelper.ThrowInvalidOperationException_NodeUnableToConvertElement(_value ? JsonValueKind.True : JsonValueKind.False, typeof(T)); } return value; } public override bool TryGetValue<T>([NotNullWhen(true)] out T? value) where T : default { if (typeof(T) == typeof(JsonElement) || typeof(T) == typeof(JsonElement?) || typeof(T) == typeof(object)) { value = (T)(object)JsonElement.Parse(_value ? JsonConstants.TrueValue : JsonConstants.FalseValue); return true; } if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?)) { value = (T)(object)_value; return true; } value = default!; return false; } } internal sealed class JsonValueOfJsonNumber : JsonValue { // This can be optimized to store the decimal point position and the exponent so that // conversion to different numeric types can be done without parsing the string again. // Utf8Parser uses an internal ref struct, Number.NumberBuffer, which is really the // same functionality that we would want here. private readonly byte[] _value; internal JsonValueOfJsonNumber(byte[] number, JsonNodeOptions? options) : base(options) { _value = number; } internal override JsonNode DeepCloneCore() => new JsonValueOfJsonNumber(_value, Options); private protected override JsonValueKind GetValueKindCore() => JsonValueKind.Number; public override T GetValue<T>() { if (!TryGetValue(out T? value)) { ThrowHelper.ThrowInvalidOperationException_NodeUnableToConvertElement(JsonValueKind.Number, typeof(T)); } return value; } public override bool TryGetValue<T>([NotNullWhen(true)] out T? value) where T : default { if (typeof(T) == typeof(JsonElement) || typeof(T) == typeof(JsonElement?) || typeof(T) == typeof(object)) { value = (T)(object)JsonElement.Parse(_value); return true; } bool success; if (typeof(T) == typeof(int) || typeof(T) == typeof(int?)) { success = Utf8Parser.TryParse(_value, out int result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(long) || typeof(T) == typeof(long?)) { success = Utf8Parser.TryParse(_value, out long result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(double) || typeof(T) == typeof(double?)) { success = Utf8Parser.TryParse(_value, out double result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(short) || typeof(T) == typeof(short?)) { success = Utf8Parser.TryParse(_value, out short result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?)) { success = Utf8Parser.TryParse(_value, out decimal result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?)) { success = Utf8Parser.TryParse(_value, out byte result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(float) || typeof(T) == typeof(float?)) { success = Utf8Parser.TryParse(_value, out float result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?)) { success = Utf8Parser.TryParse(_value, out uint result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?)) { success = Utf8Parser.TryParse(_value, out ushort result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?)) { success = Utf8Parser.TryParse(_value, out ulong result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?)) { success = Utf8Parser.TryParse(_value, out sbyte result, out int consumed) && consumed == _value.Length; value = (T)(object)result; return success; } value = default!; return false; } public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) { ArgumentNullException.ThrowIfNull(writer); writer.WriteNumberValue(_value); } } }