< Summary

Line coverage
23%
Covered lines: 35
Uncovered lines: 111
Coverable lines: 146
Total lines: 238
Line coverage: 23.9%
Branch coverage
25%
Covered branches: 16
Total branches: 64
Branch coverage: 25%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%11100%
Read(...)62.5%8866.66%
Write(...)0%660%
ReadCore(...)37.5%8868.42%
WriteCore(...)100%110%
ReadAsPropertyNameCore(...)100%110%
WriteAsPropertyNameCore(...)100%110%
ReadNumberWithCustomHandling(...)16.66%121223.8%
WriteNumberWithCustomHandling(...)0%440%
GetSchema(...)100%110%
GetSupportedJsonValueTypes(...)100%110%
TryGetFloatingPointConstant(...)0%880%
WriteFloatingPointConstant(...)0%660%
TryParse(...)50%1212100%
Format(...)100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/HalfConverter.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Buffers;
 5using System.Diagnostics;
 6using System.Globalization;
 7using System.Text.Json.Nodes;
 8using System.Text.Json.Schema;
 9
 10namespace System.Text.Json.Serialization.Converters
 11{
 12    internal sealed class HalfConverter : JsonPrimitiveConverter<Half>
 13    {
 14        private const int MaxFormatLength = 20;
 15        private const int MaxUnescapedFormatLength = JsonConstants.MaximumFloatingPointConstantLength * JsonConstants.Ma
 16
 117        public HalfConverter()
 118        {
 119            IsInternalConverterForNumberType = true;
 120        }
 21
 022        internal override bool IsIeeeFloatingPointConverter => true;
 23
 24        public override Half Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
 825        {
 826            if (options?.NumberHandling is not null and not JsonNumberHandling.Strict)
 027            {
 028                return ReadNumberWithCustomHandling(ref reader, options.NumberHandling, options);
 29            }
 30
 831            if (reader.TokenType != JsonTokenType.Number)
 432            {
 433                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(reader.TokenType);
 34            }
 35
 436            return ReadCore(ref reader);
 037        }
 38
 39        public override void Write(Utf8JsonWriter writer, Half value, JsonSerializerOptions options)
 040        {
 041            if (options?.NumberHandling is not null and not JsonNumberHandling.Strict)
 042            {
 043                WriteNumberWithCustomHandling(writer, value, options.NumberHandling);
 044                return;
 45            }
 46
 047            WriteCore(writer, value);
 048        }
 49
 50        private static unsafe Half ReadCore(ref Utf8JsonReader reader)
 451        {
 52            Half result;
 53
 454            byte[]? rentedByteBuffer = null;
 455            int bufferLength = reader.ValueLength;
 56
 457            Span<byte> byteBuffer = bufferLength <= JsonConstants.StackallocByteThreshold
 458                ? stackalloc byte[JsonConstants.StackallocByteThreshold]
 459                : (rentedByteBuffer = ArrayPool<byte>.Shared.Rent(bufferLength));
 60
 461            int written = reader.CopyValue(byteBuffer);
 462            byteBuffer = byteBuffer.Slice(0, written);
 63
 464            bool success = TryParse(byteBuffer, out result);
 465            if (rentedByteBuffer is not null)
 066            {
 067                ArrayPool<byte>.Shared.Return(rentedByteBuffer);
 068            }
 69
 470            if (!success)
 471            {
 472                ThrowHelper.ThrowFormatException(NumericType.Half);
 73            }
 74
 075            Debug.Assert(!Half.IsNaN(result) && !Half.IsInfinity(result));
 076            return result;
 077        }
 78
 79        private static unsafe void WriteCore(Utf8JsonWriter writer, Half value)
 080        {
 081            Span<byte> buffer = stackalloc byte[MaxFormatLength];
 082            Format(buffer, value, out int written);
 083            writer.WriteRawValue(buffer.Slice(0, written));
 084        }
 85
 86        internal override Half ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptio
 087        {
 088            Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
 089            return ReadCore(ref reader);
 090        }
 91
 92        internal override unsafe void WriteAsPropertyNameCore(Utf8JsonWriter writer, Half value, JsonSerializerOptions o
 093        {
 094            Span<byte> buffer = stackalloc byte[MaxFormatLength];
 095            Format(buffer, value, out int written);
 096            writer.WritePropertyName(buffer.Slice(0, written));
 097        }
 98
 99        internal override Half ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, Json
 4100        {
 4101            if (reader.TokenType == JsonTokenType.String)
 0102            {
 0103                if ((JsonNumberHandling.AllowReadingFromString & handling) != 0)
 0104                {
 0105                    if (TryGetFloatingPointConstant(ref reader, out Half value))
 0106                    {
 0107                        return value;
 108                    }
 109
 0110                    return ReadCore(ref reader);
 111                }
 0112                else if ((JsonNumberHandling.AllowNamedFloatingPointLiterals & handling) != 0)
 0113                {
 0114                    if (!TryGetFloatingPointConstant(ref reader, out Half value))
 0115                    {
 0116                        ThrowHelper.ThrowFormatException(NumericType.Half);
 117                    }
 118
 0119                    return value;
 120                }
 0121            }
 122
 4123            if (reader.TokenType != JsonTokenType.Number)
 4124            {
 4125                ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(reader.TokenType);
 126            }
 127
 0128            return ReadCore(ref reader);
 0129        }
 130
 131        internal override unsafe void WriteNumberWithCustomHandling(Utf8JsonWriter writer, Half value, JsonNumberHandlin
 0132        {
 0133            if ((JsonNumberHandling.WriteAsString & handling) != 0)
 0134            {
 135                const byte Quote = JsonConstants.Quote;
 0136                Span<byte> buffer = stackalloc byte[MaxFormatLength + 2];
 0137                buffer[0] = Quote;
 0138                Format(buffer.Slice(1), value, out int written);
 139
 0140                int length = written + 2;
 0141                buffer[length - 1] = Quote;
 0142                writer.WriteRawValue(buffer.Slice(0, length));
 0143            }
 0144            else if ((JsonNumberHandling.AllowNamedFloatingPointLiterals & handling) != 0)
 0145            {
 0146                WriteFloatingPointConstant(writer, value);
 0147            }
 148            else
 0149            {
 0150                WriteCore(writer, value);
 0151            }
 0152        }
 153
 154        internal override JsonSchema? GetSchema(JsonNumberHandling numberHandling) =>
 0155            GetSchemaForNumericType(JsonSchemaType.Number, numberHandling, isIeeeFloatingPoint: true);
 156
 157        internal override JsonValueType GetSupportedJsonValueTypes(JsonNumberHandling numberHandling) =>
 0158            GetSupportedJsonValueTypesForNumericType(numberHandling);
 159
 160        private static unsafe bool TryGetFloatingPointConstant(ref Utf8JsonReader reader, out Half value)
 0161        {
 162            scoped Span<byte> buffer;
 163
 164            // Only checking for length 10 or less for constants
 0165            if (reader.ValueIsEscaped)
 0166            {
 0167                if (reader.ValueLength > MaxUnescapedFormatLength)
 0168                {
 0169                    value = default;
 0170                    return false;
 171                }
 172
 0173                buffer = stackalloc byte[MaxUnescapedFormatLength];
 0174            }
 175            else
 0176            {
 0177                if (reader.ValueLength > JsonConstants.MaximumFloatingPointConstantLength)
 0178                {
 0179                    value = default;
 0180                    return false;
 181                }
 182
 0183                buffer = stackalloc byte[JsonConstants.MaximumFloatingPointConstantLength];
 0184            }
 185
 0186            int written = reader.CopyValue(buffer);
 187
 0188            if (written > JsonConstants.MaximumFloatingPointConstantLength)
 0189            {
 0190                value = default;
 0191                return false;
 192            }
 193
 0194            return JsonReaderHelper.TryGetFloatingPointConstant(buffer.Slice(0, written), out value);
 0195        }
 196
 197        private static void WriteFloatingPointConstant(Utf8JsonWriter writer, Half value)
 0198        {
 0199            if (Half.IsNaN(value))
 0200            {
 0201                writer.WriteNumberValueAsStringUnescaped(JsonConstants.NaNValue);
 0202            }
 0203            else if (Half.IsPositiveInfinity(value))
 0204            {
 0205                writer.WriteNumberValueAsStringUnescaped(JsonConstants.PositiveInfinityValue);
 0206            }
 0207            else if (Half.IsNegativeInfinity(value))
 0208            {
 0209                writer.WriteNumberValueAsStringUnescaped(JsonConstants.NegativeInfinityValue);
 0210            }
 211            else
 0212            {
 0213                WriteCore(writer, value);
 0214            }
 0215        }
 216
 217        private static bool TryParse(ReadOnlySpan<byte> buffer, out Half result)
 4218        {
 4219            bool success = Half.TryParse(buffer, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.Invariant
 220
 221            // Half.TryParse is more lax with floating-point literals than other S.T.Json floating-point types
 222            // e.g: it parses "naN" successfully. Only succeed with the exact match.
 4223            return success &&
 4224                (!Half.IsNaN(result) || buffer.SequenceEqual(JsonConstants.NaNValue)) &&
 4225                (!Half.IsPositiveInfinity(result) || buffer.SequenceEqual(JsonConstants.PositiveInfinityValue)) &&
 4226                (!Half.IsNegativeInfinity(result) || buffer.SequenceEqual(JsonConstants.NegativeInfinityValue));
 4227        }
 228
 229        private static void Format(
 230            Span<byte> destination,
 231            Half value, out int written)
 0232        {
 0233            bool formattedSuccessfully = value.TryFormat(destination, out written, provider: CultureInfo.InvariantCultur
 0234            Debug.Assert(formattedSuccessfully);
 0235        }
 236    }
 237}
 238