| File: Internal\Json\EnumConverter.cs | Web Access |
| Project: src\aspnetcore\src\Grpc\JsonTranscoding\src\Microsoft.AspNetCore.Grpc.JsonTranscoding\Microsoft.AspNetCore.Grpc.JsonTranscoding.csproj (Microsoft.AspNetCore.Grpc.JsonTranscoding) |
// 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.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text.Json; using Google.Protobuf.Reflection; using Type = System.Type; namespace Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json; internal sealed class EnumConverter<TEnum> : SettingsConverterBase<TEnum> where TEnum : Enum { public EnumConverter(JsonContext context) : base(context) { } public override TEnum? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { case JsonTokenType.String: var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(typeToConvert) ?? throw new InvalidOperationException($"Unable to resolve descriptor for {typeToConvert}."); var value = reader.GetString()!; var valueDescriptor = JsonNamingHelpers.GetEnumFieldReadValue(enumDescriptor, value, Context.Settings) ?? throw new InvalidOperationException(@$"Error converting value ""{value}"" to enum type {typeToConvert}."); return ConvertFromInteger(valueDescriptor.Number); case JsonTokenType.Number: return ConvertFromInteger(reader.GetInt32()); case JsonTokenType.Null: return default; default: throw new InvalidOperationException($"Unexpected JSON token: {reader.TokenType}."); } } public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options) { if (Context.Settings.WriteEnumsAsIntegers) { writer.WriteNumberValue(ConvertToInteger(value)); } else { var enumDescriptor = (EnumDescriptor?)Context.DescriptorRegistry.FindDescriptorByType(value.GetType()) ?? throw new InvalidOperationException($"Unable to resolve descriptor for {value.GetType()}."); var name = JsonNamingHelpers.GetEnumFieldWriteName(enumDescriptor, value, Context.Settings); if (name != null) { writer.WriteStringValue(name); } else { writer.WriteNumberValue(ConvertToInteger(value)); } } } private static TEnum ConvertFromInteger(int integer) { if (!TryConvertToEnum(integer, out var value)) { throw new InvalidOperationException($"Integer can't be converted to enum {typeof(TEnum).FullName}."); } return value; } private static int ConvertToInteger(TEnum value) { if (!TryConvertToInteger(value, out var integer)) { throw new InvalidOperationException($"Enum {typeof(TEnum).FullName} can't be converted to integer."); } return integer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertToInteger(TEnum value, out int integer) { if (Unsafe.SizeOf<int>() == Unsafe.SizeOf<TEnum>()) { integer = Unsafe.As<TEnum, int>(ref value); return true; } integer = default; return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryConvertToEnum(int integer, [NotNullWhen(true)] out TEnum? value) { if (Unsafe.SizeOf<int>() == Unsafe.SizeOf<TEnum>()) { value = Unsafe.As<int, TEnum>(ref integer); return true; } value = default; return false; } }