未验证 提交 e2c04e07 编写于 作者: D David Cantú 提交者: GitHub

JSON: Add support for Int128, UInt128 and Half (#88962)

* JSON: Add support for Int128, UInt128 and Half and add Number support for Utf8JsonReader.CopyString(...)

* Remove parsing limits on Read and move Number support of CopyString to an internal helper

* Fix AllowNamedFloatingPointLiterals on Write for Half

* Specify InvariantCulture on TryParse and TryFormat
Fix handling of floating-point literals on HalfConverter
Remove CopyString tests related to Number support

* Add test for invalid number input format

* Fix net6.0 build error about missing Half.TryParse overload

* Move rentedCharBuffer logic to TryParse helper

* Address feedback

* Disable test for OSX
上级 2f843a8f
......@@ -135,6 +135,15 @@ public KnownTypeSymbols(Compilation compilation)
public INamedTypeSymbol? TimeOnlyType => GetOrResolveType("System.TimeOnly", ref _TimeOnlyType);
private Option<INamedTypeSymbol?> _TimeOnlyType;
public INamedTypeSymbol? Int128Type => GetOrResolveType("System.Int128", ref _Int128Type);
private Option<INamedTypeSymbol?> _Int128Type;
public INamedTypeSymbol? UInt128Type => GetOrResolveType("System.UInt128", ref _UInt128Type);
private Option<INamedTypeSymbol?> _UInt128Type;
public INamedTypeSymbol? HalfType => GetOrResolveType("System.Half", ref _HalfType);
private Option<INamedTypeSymbol?> _HalfType;
public IArrayTypeSymbol? ByteArrayType => _ByteArrayType.HasValue
? _ByteArrayType.Value
: (_ByteArrayType = new(Compilation.CreateArrayTypeSymbol(Compilation.GetSpecialType(SpecialType.System_Byte), rank: 1))).Value;
......
......@@ -1699,6 +1699,9 @@ private static HashSet<ITypeSymbol> CreateBuiltInSupportTypeSet(KnownTypeSymbols
AddTypeIfNotNull(knownSymbols.DateTimeOffsetType);
AddTypeIfNotNull(knownSymbols.DateOnlyType);
AddTypeIfNotNull(knownSymbols.TimeOnlyType);
AddTypeIfNotNull(knownSymbols.Int128Type);
AddTypeIfNotNull(knownSymbols.UInt128Type);
AddTypeIfNotNull(knownSymbols.HalfType);
AddTypeIfNotNull(knownSymbols.GuidType);
AddTypeIfNotNull(knownSymbols.UriType);
AddTypeIfNotNull(knownSymbols.VersionType);
......
......@@ -9,6 +9,13 @@ namespace System.Text.Json.Serialization.Metadata
public static partial class JsonMetadataServices
{
public static System.Text.Json.Serialization.JsonConverter<System.DateOnly> DateOnlyConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Half> HalfConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.TimeOnly> TimeOnlyConverter { get { throw null; } }
#if NET7_0_OR_GREATER
public static System.Text.Json.Serialization.JsonConverter<System.Int128> Int128Converter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<System.UInt128> UInt128Converter { get { throw null; } }
#endif
}
}
......@@ -690,4 +690,13 @@
<data name="ObjectCreationHandlingPropertyCannotAllowReferenceHandling" xml:space="preserve">
<value>JsonObjectCreationHandling.Populate is incompatible with reference handling.</value>
</data>
<data name="FormatInt128" xml:space="preserve">
<value>Either the JSON value is not in a supported format, or is out of bounds for an Int128.</value>
</data>
<data name="FormatUInt128" xml:space="preserve">
<value>Either the JSON value is not in a supported format, or is out of bounds for an UInt128.</value>
</data>
<data name="FormatHalf" xml:space="preserve">
<value>Either the JSON value is not in a supported format, or is out of bounds for a Half.</value>
</data>
</root>
......@@ -346,11 +346,17 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and $([MSBuild]::VersionGreaterThanOrEquals('$(TargetFrameworkVersion)', '7.0'))">
<Compile Include="System\Text\Json\Serialization\Converters\Value\Int128Converter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\UInt128Converter.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<Compile Include="System.Text.Json.Typeforwards.netcoreapp.cs" />
<Compile Include="System\Text\Json\Serialization\JsonSerializerOptionsUpdateHandler.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\DateOnlyConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\TimeOnlyConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\HalfConverter.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
......
......@@ -145,6 +145,39 @@ public static bool TryGetEscapedGuid(ReadOnlySpan<byte> source, out Guid value)
return false;
}
#if NETCOREAPP
public static bool TryGetFloatingPointConstant(ReadOnlySpan<byte> span, out Half value)
{
if (span.Length == 3)
{
if (span.SequenceEqual(JsonConstants.NaNValue))
{
value = Half.NaN;
return true;
}
}
else if (span.Length == 8)
{
if (span.SequenceEqual(JsonConstants.PositiveInfinityValue))
{
value = Half.PositiveInfinity;
return true;
}
}
else if (span.Length == 9)
{
if (span.SequenceEqual(JsonConstants.NegativeInfinityValue))
{
value = Half.NegativeInfinity;
return true;
}
}
value = default;
return false;
}
#endif
public static bool TryGetFloatingPointConstant(ReadOnlySpan<byte> span, out float value)
{
if (span.Length == 3)
......
......@@ -73,6 +73,14 @@ namespace System.Text.Json
ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
}
return CopyValue(utf8Destination);
}
internal readonly int CopyValue(Span<byte> utf8Destination)
{
Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters.");
int bytesWritten;
if (ValueIsEscaped)
......@@ -129,6 +137,14 @@ namespace System.Text.Json
ThrowHelper.ThrowInvalidOperationException_ExpectedString(_tokenType);
}
return CopyValue(destination);
}
internal readonly int CopyValue(Span<char> destination)
{
Debug.Assert(_tokenType is JsonTokenType.String or JsonTokenType.PropertyName or JsonTokenType.Number);
Debug.Assert(_tokenType != JsonTokenType.Number || !ValueIsEscaped, "Numbers can't contain escape characters.");
scoped ReadOnlySpan<byte> unescapedSource;
byte[]? rentedBuffer = null;
int valueLength;
......
......@@ -12,6 +12,11 @@ internal sealed class CharConverter : JsonPrimitiveConverter<char>
public override char Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType is not (JsonTokenType.String or JsonTokenType.PropertyName))
{
ThrowHelper.ThrowInvalidOperationException_ExpectedString(reader.TokenType);
}
if (!JsonHelpers.IsInRangeInclusive(reader.ValueLength, 1, MaxEscapedCharacterLength))
{
ThrowHelper.ThrowInvalidOperationException_ExpectedChar(reader.TokenType);
......
// 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.Diagnostics;
using System.Globalization;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class HalfConverter : JsonPrimitiveConverter<Half>
{
private const int MaxFormatLength = 20;
public HalfConverter()
{
IsInternalConverterForNumberType = true;
}
public override Half Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
{
ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(reader.TokenType);
}
return ReadCore(ref reader);
}
public override void Write(Utf8JsonWriter writer, Half value, JsonSerializerOptions options)
{
WriteCore(writer, value);
}
private static Half ReadCore(ref Utf8JsonReader reader)
{
Half result;
byte[]? rentedByteBuffer = null;
int bufferLength = reader.ValueLength;
Span<byte> byteBuffer = bufferLength <= JsonConstants.StackallocByteThreshold
? stackalloc byte[JsonConstants.StackallocByteThreshold]
: (rentedByteBuffer = ArrayPool<byte>.Shared.Rent(bufferLength));
int written = reader.CopyValue(byteBuffer);
byteBuffer = byteBuffer.Slice(0, written);
bool success = TryParse(byteBuffer, out result);
if (rentedByteBuffer != null)
{
ArrayPool<byte>.Shared.Return(rentedByteBuffer);
}
if (!success)
{
ThrowHelper.ThrowFormatException(NumericType.Half);
}
Debug.Assert(!Half.IsNaN(result) && !Half.IsInfinity(result));
return result;
}
private static void WriteCore(Utf8JsonWriter writer, Half value)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WriteRawValue(buffer.Slice(0, written));
}
internal override Half ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
return ReadCore(ref reader);
}
internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, Half value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WritePropertyName(buffer.Slice(0, written));
}
internal override Half ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
if ((JsonNumberHandling.AllowReadingFromString & handling) != 0)
{
if (TryGetFloatingPointConstant(ref reader, out Half value))
{
return value;
}
return ReadCore(ref reader);
}
else if ((JsonNumberHandling.AllowNamedFloatingPointLiterals & handling) != 0)
{
if (!TryGetFloatingPointConstant(ref reader, out Half value))
{
ThrowHelper.ThrowFormatException(NumericType.Half);
}
return value;
}
}
return Read(ref reader, Type, options);
}
internal override void WriteNumberWithCustomHandling(Utf8JsonWriter writer, Half value, JsonNumberHandling handling)
{
if ((JsonNumberHandling.WriteAsString & handling) != 0)
{
#if NET8_0_OR_GREATER
const byte Quote = JsonConstants.Quote;
Span<byte> buffer = stackalloc byte[MaxFormatLength + 2];
#else
const char Quote = (char)JsonConstants.Quote;
Span<char> buffer = stackalloc char[MaxFormatLength + 2];
#endif
buffer[0] = Quote;
Format(buffer.Slice(1), value, out int written);
int length = written + 2;
buffer[length - 1] = Quote;
writer.WriteRawValue(buffer.Slice(0, length));
}
else if ((JsonNumberHandling.AllowNamedFloatingPointLiterals & handling) != 0)
{
WriteFloatingPointConstant(writer, value);
}
else
{
WriteCore(writer, value);
}
}
private static bool TryGetFloatingPointConstant(ref Utf8JsonReader reader, out Half value)
{
Span<byte> buffer = stackalloc byte[MaxFormatLength];
int written = reader.CopyValue(buffer);
return JsonReaderHelper.TryGetFloatingPointConstant(buffer.Slice(0, written), out value);
}
private static void WriteFloatingPointConstant(Utf8JsonWriter writer, Half value)
{
if (Half.IsNaN(value))
{
writer.WriteNumberValueAsStringUnescaped(JsonConstants.NaNValue);
}
else if (Half.IsPositiveInfinity(value))
{
writer.WriteNumberValueAsStringUnescaped(JsonConstants.PositiveInfinityValue);
}
else if (Half.IsNegativeInfinity(value))
{
writer.WriteNumberValueAsStringUnescaped(JsonConstants.NegativeInfinityValue);
}
else
{
WriteCore(writer, value);
}
}
private static bool TryParse(ReadOnlySpan<byte> buffer, out Half result)
{
#if NET8_0_OR_GREATER
bool success = Half.TryParse(buffer, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result);
#else
// Half.TryFormat/TryParse(ROS<byte>) are not available on .NET 7
// we need to use Half.TryFormat/TryParse(ROS<char>) in that case.
char[]? rentedCharBuffer = null;
Span<char> charBuffer = buffer.Length <= JsonConstants.StackallocCharThreshold
? stackalloc char[JsonConstants.StackallocCharThreshold]
: (rentedCharBuffer = ArrayPool<char>.Shared.Rent(buffer.Length));
int written = JsonReaderHelper.TranscodeHelper(buffer, charBuffer);
bool success = Half.TryParse(charBuffer, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result);
if (rentedCharBuffer != null)
{
ArrayPool<char>.Shared.Return(rentedCharBuffer);
}
#endif
// Half.TryParse is more lax with floating-point literals than other S.T.Json floating-point types
// e.g: it parses "naN" successfully. Only succeed with the exact match.
return success &&
(!Half.IsNaN(result) || buffer.SequenceEqual(JsonConstants.NaNValue)) &&
(!Half.IsPositiveInfinity(result) || buffer.SequenceEqual(JsonConstants.PositiveInfinityValue)) &&
(!Half.IsNegativeInfinity(result) || buffer.SequenceEqual(JsonConstants.NegativeInfinityValue));
}
private static void Format(
#if NET8_0_OR_GREATER
Span<byte> destination,
#else
Span<char> destination,
#endif
Half value, out int written)
{
bool formattedSuccessfully = value.TryFormat(destination, out written, provider: CultureInfo.InvariantCulture);
Debug.Assert(formattedSuccessfully);
}
}
}
// 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.Diagnostics;
using System.Globalization;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class Int128Converter : JsonPrimitiveConverter<Int128>
{
private const int MaxFormatLength = 40;
public Int128Converter()
{
IsInternalConverterForNumberType = true;
}
public override Int128 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
{
ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(reader.TokenType);
}
return ReadCore(ref reader);
}
public override void Write(Utf8JsonWriter writer, Int128 value, JsonSerializerOptions options)
{
WriteCore(writer, value);
}
private static Int128 ReadCore(ref Utf8JsonReader reader)
{
int bufferLength = reader.ValueLength;
#if NET8_0_OR_GREATER
byte[]? rentedBuffer = null;
Span<byte> buffer = bufferLength <= JsonConstants.StackallocByteThreshold
? stackalloc byte[JsonConstants.StackallocByteThreshold]
: (rentedBuffer = ArrayPool<byte>.Shared.Rent(bufferLength));
#else
char[]? rentedBuffer = null;
Span<char> buffer = bufferLength <= JsonConstants.StackallocCharThreshold
? stackalloc char[JsonConstants.StackallocCharThreshold]
: (rentedBuffer = ArrayPool<char>.Shared.Rent(bufferLength));
#endif
int written = reader.CopyValue(buffer);
if (!TryParse(buffer.Slice(0, written), out Int128 result))
{
ThrowHelper.ThrowFormatException(NumericType.Int128);
}
if (rentedBuffer != null)
{
#if NET8_0_OR_GREATER
ArrayPool<byte>.Shared.Return(rentedBuffer);
#else
ArrayPool<char>.Shared.Return(rentedBuffer);
#endif
}
return result;
}
private static void WriteCore(Utf8JsonWriter writer, Int128 value)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WriteRawValue(buffer.Slice(0, written));
}
internal override Int128 ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
return ReadCore(ref reader);
}
internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, Int128 value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WritePropertyName(buffer);
}
internal override Int128 ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String &&
(JsonNumberHandling.AllowReadingFromString & handling) != 0)
{
return ReadCore(ref reader);
}
return Read(ref reader, Type, options);
}
internal override void WriteNumberWithCustomHandling(Utf8JsonWriter writer, Int128 value, JsonNumberHandling handling)
{
if ((JsonNumberHandling.WriteAsString & handling) != 0)
{
#if NET8_0_OR_GREATER
const byte Quote = JsonConstants.Quote;
Span<byte> buffer = stackalloc byte[MaxFormatLength + 2];
#else
const char Quote = (char)JsonConstants.Quote;
Span<char> buffer = stackalloc char[MaxFormatLength + 2];
#endif
buffer[0] = Quote;
Format(buffer.Slice(1), value, out int written);
int length = written + 2;
buffer[length - 1] = Quote;
writer.WriteRawValue(buffer.Slice(0, length));
}
else
{
WriteCore(writer, value);
}
}
// Int128.TryParse(ROS<byte>) is not available on .NET 7, only Int128.TryParse(ROS<char>).
private static bool TryParse(
#if NET8_0_OR_GREATER
ReadOnlySpan<byte> buffer,
#else
ReadOnlySpan<char> buffer,
#endif
out Int128 result)
{
return Int128.TryParse(buffer, CultureInfo.InvariantCulture, out result);
}
private static void Format(
#if NET8_0_OR_GREATER
Span<byte> destination,
#else
Span<char> destination,
#endif
Int128 value, out int written)
{
bool formattedSuccessfully = value.TryFormat(destination, out written, provider: CultureInfo.InvariantCulture);
Debug.Assert(formattedSuccessfully);
}
}
}
// 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.Diagnostics;
using System.Globalization;
namespace System.Text.Json.Serialization.Converters
{
internal sealed class UInt128Converter : JsonPrimitiveConverter<UInt128>
{
private const int MaxFormatLength = 39;
public UInt128Converter()
{
IsInternalConverterForNumberType = true;
}
public override UInt128 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
{
ThrowHelper.ThrowInvalidOperationException_ExpectedNumber(reader.TokenType);
}
return ReadCore(ref reader);
}
public override void Write(Utf8JsonWriter writer, UInt128 value, JsonSerializerOptions options)
{
WriteCore(writer, value);
}
private static UInt128 ReadCore(ref Utf8JsonReader reader)
{
int bufferLength = reader.ValueLength;
#if NET8_0_OR_GREATER
byte[]? rentedBuffer = null;
Span<byte> buffer = bufferLength <= JsonConstants.StackallocByteThreshold
? stackalloc byte[JsonConstants.StackallocByteThreshold]
: (rentedBuffer = ArrayPool<byte>.Shared.Rent(bufferLength));
#else
char[]? rentedBuffer = null;
Span<char> buffer = bufferLength <= JsonConstants.StackallocCharThreshold
? stackalloc char[JsonConstants.StackallocCharThreshold]
: (rentedBuffer = ArrayPool<char>.Shared.Rent(bufferLength));
#endif
int written = reader.CopyValue(buffer);
if (!TryParse(buffer.Slice(0, written), out UInt128 result))
{
ThrowHelper.ThrowFormatException(NumericType.UInt128);
}
if (rentedBuffer != null)
{
#if NET8_0_OR_GREATER
ArrayPool<byte>.Shared.Return(rentedBuffer);
#else
ArrayPool<char>.Shared.Return(rentedBuffer);
#endif
}
return result;
}
private static void WriteCore(Utf8JsonWriter writer, UInt128 value)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WriteRawValue(buffer.Slice(0, written));
}
internal override UInt128 ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(reader.TokenType == JsonTokenType.PropertyName);
return ReadCore(ref reader);
}
internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, UInt128 value, JsonSerializerOptions options, bool isWritingExtensionDataProperty)
{
#if NET8_0_OR_GREATER
Span<byte> buffer = stackalloc byte[MaxFormatLength];
#else
Span<char> buffer = stackalloc char[MaxFormatLength];
#endif
Format(buffer, value, out int written);
writer.WritePropertyName(buffer);
}
internal override UInt128 ReadNumberWithCustomHandling(ref Utf8JsonReader reader, JsonNumberHandling handling, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String &&
(JsonNumberHandling.AllowReadingFromString & handling) != 0)
{
return ReadCore(ref reader);
}
return Read(ref reader, Type, options);
}
internal override void WriteNumberWithCustomHandling(Utf8JsonWriter writer, UInt128 value, JsonNumberHandling handling)
{
if ((JsonNumberHandling.WriteAsString & handling) != 0)
{
#if NET8_0_OR_GREATER
const byte Quote = JsonConstants.Quote;
Span<byte> buffer = stackalloc byte[MaxFormatLength + 2];
#else
const char Quote = (char)JsonConstants.Quote;
Span<char> buffer = stackalloc char[MaxFormatLength + 2];
#endif
buffer[0] = Quote;
Format(buffer.Slice(1), value, out int written);
int length = written + 2;
buffer[length - 1] = Quote;
writer.WriteRawValue(buffer.Slice(0, length));
}
else
{
WriteCore(writer, value);
}
}
// UInt128.TryParse(ROS<byte>) is not available on .NET 7, only UInt128.TryParse(ROS<char>).
private static bool TryParse(
#if NET8_0_OR_GREATER
ReadOnlySpan<byte> buffer,
#else
ReadOnlySpan<char> buffer,
#endif
out UInt128 result)
{
return UInt128.TryParse(buffer, CultureInfo.InvariantCulture, out result);
}
private static void Format(
#if NET8_0_OR_GREATER
Span<byte> destination,
#else
Span<char> destination,
#endif
UInt128 value, out int written)
{
bool formattedSuccessfully = value.TryFormat(destination, out written, provider: CultureInfo.InvariantCulture);
Debug.Assert(formattedSuccessfully);
}
}
}
......@@ -40,7 +40,7 @@ private static JsonConverterFactory[] GetDefaultFactoryConverters()
private static Dictionary<Type, JsonConverter> GetDefaultSimpleConverters()
{
const int NumberOfSimpleConverters = 28;
const int NumberOfSimpleConverters = 31;
var converters = new Dictionary<Type, JsonConverter>(NumberOfSimpleConverters);
// Use a dictionary for simple converters.
......@@ -54,6 +54,7 @@ private static JsonConverterFactory[] GetDefaultFactoryConverters()
#if NETCOREAPP
Add(JsonMetadataServices.DateOnlyConverter);
Add(JsonMetadataServices.TimeOnlyConverter);
Add(JsonMetadataServices.HalfConverter);
#endif
Add(JsonMetadataServices.DoubleConverter);
Add(JsonMetadataServices.DecimalConverter);
......@@ -73,6 +74,10 @@ private static JsonConverterFactory[] GetDefaultFactoryConverters()
Add(JsonMetadataServices.UInt16Converter);
Add(JsonMetadataServices.UInt32Converter);
Add(JsonMetadataServices.UInt64Converter);
#if NET7_0_OR_GREATER
Add(JsonMetadataServices.Int128Converter);
Add(JsonMetadataServices.UInt128Converter);
#endif
Add(JsonMetadataServices.UriConverter);
Add(JsonMetadataServices.VersionConverter);
......
......@@ -108,6 +108,23 @@ public static partial class JsonMetadataServices
public static JsonConverter<long> Int64Converter => s_int64Converter ??= new Int64Converter();
private static JsonConverter<long>? s_int64Converter;
#if NET7_0_OR_GREATER
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Int128"/> values.
/// </summary>
/// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
public static JsonConverter<Int128> Int128Converter => s_int128Converter ??= new Int128Converter();
private static JsonConverter<Int128>? s_int128Converter;
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="UInt128"/> values.
/// </summary>
/// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
[CLSCompliant(false)]
public static JsonConverter<UInt128> UInt128Converter => s_uint128Converter ??= new UInt128Converter();
private static JsonConverter<UInt128>? s_uint128Converter;
#endif
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="JsonArray"/> values.
/// </summary>
......@@ -171,6 +188,15 @@ public static partial class JsonMetadataServices
public static JsonConverter<object?> ObjectConverter => s_objectConverter ??= new DefaultObjectConverter();
private static JsonConverter<object?>? s_objectConverter;
#if NETCOREAPP
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Half"/> values.
/// </summary>
/// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
public static JsonConverter<Half> HalfConverter => s_halfConverter ??= new HalfConverter();
private static JsonConverter<Half>? s_halfConverter;
#endif
/// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="float"/> values.
/// </summary>
......
......@@ -583,6 +583,13 @@ private bool NumberHandingIsApplicable()
potentialNumberType == typeof(ushort) ||
potentialNumberType == typeof(uint) ||
potentialNumberType == typeof(ulong) ||
#if NETCOREAPP
potentialNumberType == typeof(Half) ||
#endif
#if NET7_0_OR_GREATER
potentialNumberType == typeof(Int128) ||
potentialNumberType == typeof(UInt128) ||
#endif
potentialNumberType == JsonTypeInfo.ObjectType;
}
......
......@@ -615,6 +615,9 @@ public static void ThrowFormatException(NumericType numericType)
case NumericType.Int64:
message = SR.FormatInt64;
break;
case NumericType.Int128:
message = SR.FormatInt128;
break;
case NumericType.UInt16:
message = SR.FormatUInt16;
break;
......@@ -624,6 +627,12 @@ public static void ThrowFormatException(NumericType numericType)
case NumericType.UInt64:
message = SR.FormatUInt64;
break;
case NumericType.UInt128:
message = SR.FormatUInt128;
break;
case NumericType.Half:
message = SR.FormatHalf;
break;
case NumericType.Single:
message = SR.FormatSingle;
break;
......@@ -740,9 +749,12 @@ internal enum NumericType
Int16,
Int32,
Int64,
Int128,
UInt16,
UInt32,
UInt64,
UInt128,
Half,
Single,
Double,
Decimal
......
......@@ -66,6 +66,11 @@ public static IEnumerable<object[]> GetTestDictionaries()
yield return WrapArgs(ushort.MaxValue, 1);
yield return WrapArgs(uint.MaxValue, 1);
yield return WrapArgs(ulong.MaxValue, 1);
#if NETCOREAPP
yield return WrapArgs(Half.MinValue, 1);
yield return WrapArgs(Int128.MinValue, 1);
yield return WrapArgs(UInt128.MaxValue, 1);
#endif
static object[] WrapArgs<TKey, TValue>(TKey key, TValue value, string? expectedJson = null)
{
......@@ -334,7 +339,15 @@ public async Task TestEscapedValuesOnDeserialize(string escapedPropertyName, obj
MyEnum.Bar, typeof(Dictionary<MyEnum, int>) },
new object[] { @"\u0042\u0061\u0072\u002c\u0042\u0061\u007a",
MyEnumFlags.Bar | MyEnumFlags.Baz, typeof(Dictionary<MyEnumFlags, int>) },
new object[] { @"\u002b", '+', typeof(Dictionary<char, int>) }
new object[] { @"\u002b", '+', typeof(Dictionary<char, int>) },
#if NETCOREAPP
new object[] { @"\u0033\u002e\u0031\u0032\u0035\u0065\u0034",
(Half)3.125e4, typeof(Dictionary<Half, int>) },
new object[] { @"\u002D\u0031\u0037\u0030\u0031\u0034\u0031\u0031\u0038\u0033\u0034\u0036\u0030\u0034\u0036\u0039\u0032\u0033\u0031\u0037\u0033\u0031\u0036\u0038\u0037\u0033\u0030\u0033\u0037\u0031\u0035\u0038\u0038\u0034\u0031\u0030\u0035\u0037\u0032\u0038",
Int128.MinValue, typeof(Dictionary<Int128, int>) },
new object[] { @"\u0033\u0034\u0030\u0032\u0038\u0032\u0033\u0036\u0036\u0039\u0032\u0030\u0039\u0033\u0038\u0034\u0036\u0033\u0034\u0036\u0033\u0033\u0037\u0034\u0036\u0030\u0037\u0034\u0033\u0031\u0037\u0036\u0038\u0032\u0031\u0031\u0034\u0035\u0035",
UInt128.MaxValue, typeof(Dictionary<UInt128, int>) },
#endif
};
public class MyPublicClass { }
......
......@@ -20,6 +20,11 @@ internal class JsonNumberTestData
public static List<float> Floats { get; set; }
public static List<double> Doubles { get; set; }
public static List<decimal> Decimals { get; set; }
#if NETCOREAPP
public static List<Int128> Int128s { get; set; }
public static List<UInt128> UInt128s { get; set; }
public static List<Half> Halfs { get; set; }
#endif
public static List<byte?> NullableBytes { get; set; }
public static List<sbyte?> NullableSBytes { get; set; }
......@@ -32,6 +37,11 @@ internal class JsonNumberTestData
public static List<float?> NullableFloats { get; set; }
public static List<double?> NullableDoubles { get; set; }
public static List<decimal?> NullableDecimals { get; set; }
#if NETCOREAPP
public static List<Int128?> NullableInt128s { get; set; }
public static List<UInt128?> NullableUInt128s { get; set; }
public static List<Half?> NullableHalfs { get; set; }
#endif
public static byte[] JsonData { get; set; }
......@@ -237,6 +247,58 @@ static JsonNumberTestData()
}
#endregion
#if NETCOREAPP
#region generate Int128s
Int128s = new List<Int128>
{
0,
(Int128)long.MaxValue + 1,
(Int128)long.MinValue - 1,
Int128.MaxValue,
Int128.MinValue
};
for (int i = 0; i < numberOfItems; i++)
{
Int128 value = random.Next(int.MinValue, int.MaxValue);
if (value < 0)
value += Int128.MinValue;
else
value += Int128.MaxValue;
Int128s.Add(value);
}
#endregion
#region generate UInt128s
UInt128s = new List<UInt128>
{
(UInt128)ulong.MaxValue + 1,
UInt128.MaxValue,
UInt128.MinValue
};
for (int i = 0; i < numberOfItems; i++)
{
UInt128 value = (UInt128)random.Next(int.MinValue, int.MaxValue);
UInt128s.Add(value);
}
#endregion
#region generate Halfs
Halfs = new List<Half>
{
(Half)0.000,
(Half)1.1234e1,
(Half)(-1.1234e1),
Half.MaxValue,
Half.MinValue
};
for (int i = 0; i < numberOfItems; i++)
{
Half value = JsonTestHelper.NextHalf(random);
Halfs.Add(value);
}
#endregion
#endif
#region generate the json
var builder = new StringBuilder();
builder.Append("{");
......@@ -319,6 +381,11 @@ static JsonNumberTestData()
NullableFloats = new List<float?>(Floats.Select(num => (float?)num));
NullableDoubles = new List<double?>(Doubles.Select(num => (double?)num));
NullableDecimals = new List<decimal?>(Decimals.Select(num => (decimal?)num));
#if NETCOREAPP
NullableInt128s = new List<Int128?>(Int128s.Select(num => (Int128?)num));
NullableUInt128s = new List<UInt128?>(UInt128s.Select(num => (UInt128?)num));
NullableHalfs = new List<Half?>(Halfs.Select(num => (Half?)num));
#endif
string jsonString = builder.ToString();
JsonData = Encoding.UTF8.GetBytes(jsonString);
......
......@@ -23,6 +23,16 @@ internal static partial class JsonTestHelper
public const string SingleFormatString = "G9";
#endif
#if NETCOREAPP
public static Half NextHalf(Random random)
{
double mantissa = (random.NextDouble() * 2.0) - 1.0;
double exponent = Math.Pow(2.0, random.Next(-15, 16));
Half value = (Half)(mantissa * exponent);
return value;
}
#endif
public static float NextFloat(Random random)
{
double mantissa = (random.NextDouble() * 2.0) - 1.0;
......
......@@ -63,6 +63,11 @@ public async Task Number_AsRootType_RoundTrip()
await RunAsRootTypeTest(JsonNumberTestData.Floats);
await RunAsRootTypeTest(JsonNumberTestData.Doubles);
await RunAsRootTypeTest(JsonNumberTestData.Decimals);
#if NETCOREAPP
await RunAsRootTypeTest(JsonNumberTestData.Int128s);
await RunAsRootTypeTest(JsonNumberTestData.UInt128s);
await RunAsRootTypeTest(JsonNumberTestData.Halfs);
#endif
await RunAsRootTypeTest(JsonNumberTestData.NullableBytes);
await RunAsRootTypeTest(JsonNumberTestData.NullableSBytes);
await RunAsRootTypeTest(JsonNumberTestData.NullableShorts);
......@@ -74,6 +79,11 @@ public async Task Number_AsRootType_RoundTrip()
await RunAsRootTypeTest(JsonNumberTestData.NullableFloats);
await RunAsRootTypeTest(JsonNumberTestData.NullableDoubles);
await RunAsRootTypeTest(JsonNumberTestData.NullableDecimals);
#if NETCOREAPP
await RunAsRootTypeTest(JsonNumberTestData.NullableInt128s);
await RunAsRootTypeTest(JsonNumberTestData.NullableUInt128s);
await RunAsRootTypeTest(JsonNumberTestData.NullableHalfs);
#endif
}
private async Task RunAsRootTypeTest<T>(List<T> numbers)
......@@ -373,6 +383,11 @@ public async Task Number_AsCollectionElement_RoundTrip()
await RunAsCollectionElementTest(JsonNumberTestData.Floats);
await RunAsCollectionElementTest(JsonNumberTestData.Doubles);
await RunAsCollectionElementTest(JsonNumberTestData.Decimals);
#if NETCOREAPP
await RunAsCollectionElementTest(JsonNumberTestData.Int128s);
await RunAsCollectionElementTest(JsonNumberTestData.UInt128s);
await RunAsCollectionElementTest(JsonNumberTestData.Halfs);
#endif
// https://github.com/dotnet/runtime/issues/66220
if (!PlatformDetection.IsAppleMobile)
......@@ -388,6 +403,11 @@ public async Task Number_AsCollectionElement_RoundTrip()
await RunAsCollectionElementTest(JsonNumberTestData.NullableFloats);
await RunAsCollectionElementTest(JsonNumberTestData.NullableDoubles);
await RunAsCollectionElementTest(JsonNumberTestData.NullableDecimals);
#if NETCOREAPP
await RunAsCollectionElementTest(JsonNumberTestData.NullableInt128s);
await RunAsCollectionElementTest(JsonNumberTestData.NullableUInt128s);
await RunAsCollectionElementTest(JsonNumberTestData.NullableHalfs);
#endif
}
}
......@@ -761,35 +781,57 @@ public async Task FloatingPointConstants_Pass()
async Task PerformFloatingPointSerialization(string testString)
{
string testStringAsJson = $@"""{testString}""";
#if NETCOREAPP
string testJson = @$"{{""HalfNumber"":{testStringAsJson},""FloatNumber"":{testStringAsJson},""DoubleNumber"":{testStringAsJson}}}";
#else
string testJson = @$"{{""FloatNumber"":{testStringAsJson},""DoubleNumber"":{testStringAsJson}}}";
#endif
StructWithNumbers obj;
switch (testString)
{
case "NaN":
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionsAllowFloatConstants);
#if NETCOREAPP
Assert.Equal(Half.NaN, obj.HalfNumber);
#endif
Assert.Equal(float.NaN, obj.FloatNumber);
Assert.Equal(double.NaN, obj.DoubleNumber);
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionReadFromStr);
#if NETCOREAPP
Assert.Equal(Half.NaN, obj.HalfNumber);
#endif
Assert.Equal(float.NaN, obj.FloatNumber);
Assert.Equal(double.NaN, obj.DoubleNumber);
break;
case "Infinity":
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionsAllowFloatConstants);
#if NETCOREAPP
Assert.Equal(Half.PositiveInfinity, obj.HalfNumber);
#endif
Assert.Equal(float.PositiveInfinity, obj.FloatNumber);
Assert.Equal(double.PositiveInfinity, obj.DoubleNumber);
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionReadFromStr);
#if NETCOREAPP
Assert.Equal(Half.PositiveInfinity, obj.HalfNumber);
#endif
Assert.Equal(float.PositiveInfinity, obj.FloatNumber);
Assert.Equal(double.PositiveInfinity, obj.DoubleNumber);
break;
case "-Infinity":
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionsAllowFloatConstants);
#if NETCOREAPP
Assert.Equal(Half.NegativeInfinity, obj.HalfNumber);
#endif
Assert.Equal(float.NegativeInfinity, obj.FloatNumber);
Assert.Equal(double.NegativeInfinity, obj.DoubleNumber);
obj = await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionReadFromStr);
#if NETCOREAPP
Assert.Equal(Half.NegativeInfinity, obj.HalfNumber);
#endif
Assert.Equal(float.NegativeInfinity, obj.FloatNumber);
Assert.Equal(double.NegativeInfinity, obj.DoubleNumber);
break;
......@@ -831,11 +873,17 @@ async Task PerformFloatingPointSerialization(string testString)
[InlineData("\u0020Inf\u0069ni\u0074y")] // " Infinity"
[InlineData("\u002BInf\u0069nity")] // "+Infinity"
#pragma warning restore xUnit1025
[ActiveIssue("https://github.com/dotnet/runtime/issues/89094", TestPlatforms.OSX)]
public async Task FloatingPointConstants_Fail(string testString)
{
string testStringAsJson = $@"""{testString}""";
string testJson = @$"{{""FloatNumber"":{testStringAsJson}}}";
string testJson;
#if NETCOREAPP
testJson = @$"{{""HalfNumber"":{testStringAsJson}}}";
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionReadFromStr));
#endif
testJson = @$"{{""FloatNumber"":{testStringAsJson}}}";
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<StructWithNumbers>(testJson, s_optionReadFromStr));
......@@ -847,6 +895,11 @@ public async Task FloatingPointConstants_Fail(string testString)
[Fact]
public async Task AllowFloatingPointConstants_WriteAsNumber_IfNotConstant()
{
#if NETCOREAPP
Half half = (Half)1;
// Not written as "1"
Assert.Equal("1", await Serializer.SerializeWrapper(half, s_optionsAllowFloatConstants));
#endif
float @float = 1;
// Not written as "1"
Assert.Equal("1", await Serializer.SerializeWrapper(@float, s_optionsAllowFloatConstants));
......@@ -862,6 +915,9 @@ public async Task AllowFloatingPointConstants_WriteAsNumber_IfNotConstant()
[InlineData("-Infinity")]
public async Task Unquoted_FloatingPointConstants_Read_Fail(string testString)
{
#if NETCOREAPP
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<Half>(testString, s_optionsAllowFloatConstants));
#endif
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<float>(testString, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<double?>(testString, s_optionReadFromStr));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<double>(testString, s_optionReadFromStrAllowFloatConstants));
......@@ -869,6 +925,9 @@ public async Task Unquoted_FloatingPointConstants_Read_Fail(string testString)
public struct StructWithNumbers
{
#if NETCOREAPP
public Half HalfNumber { get; set; }
#endif
public float FloatNumber { get; set; }
public double DoubleNumber { get; set; }
}
......@@ -927,6 +986,12 @@ public async Task FloatingPointConstants_IncompatibleNumber()
await AssertFloatingPointIncompatible_Fails<uint?>();
await AssertFloatingPointIncompatible_Fails<ulong?>();
await AssertFloatingPointIncompatible_Fails<decimal?>();
#if NETCOREAPP
await AssertFloatingPointIncompatible_Fails<Int128>();
await AssertFloatingPointIncompatible_Fails<UInt128>();
await AssertFloatingPointIncompatible_Fails<Int128?>();
await AssertFloatingPointIncompatible_Fails<UInt128?>();
#endif
}
private async Task AssertFloatingPointIncompatible_Fails<T>()
......@@ -967,12 +1032,21 @@ public async Task UnsupportedFormats()
await AssertUnsupportedFormatThrows<ulong?>();
await AssertUnsupportedFormatThrows<float?>();
await AssertUnsupportedFormatThrows<decimal?>();
#if NETCOREAPP
await AssertUnsupportedFormatThrows<Int128>();
await AssertUnsupportedFormatThrows<UInt128>();
await AssertUnsupportedFormatThrows<Half>();
await AssertUnsupportedFormatThrows<Int128?>();
await AssertUnsupportedFormatThrows<UInt128?>();
await AssertUnsupportedFormatThrows<Half?>();
#endif
}
private async Task AssertUnsupportedFormatThrows<T>()
{
string[] testCases = new[]
{
"01", // leading zeroes
"$123.46", // Currency
"100.00 %", // Percent
"1234,57", // Fixed point
......@@ -985,6 +1059,27 @@ private async Task AssertUnsupportedFormatThrows<T>()
}
}
#if NETCOREAPP
[Fact]
public async Task InvalidNumberFormatThrows()
{
await AssertInvalidNumberFormatThrows<Int128>("170141183460469231731687303715884105728"); // MaxValue + 1
await AssertInvalidNumberFormatThrows<Int128>("-170141183460469231731687303715884105729"); // MaxValue - 1
await AssertInvalidNumberFormatThrows<Int128>("3.14");
await AssertInvalidNumberFormatThrows<UInt128>("340282366920938463463374607431768211456"); // MaxValue + 1
await AssertInvalidNumberFormatThrows<Int128>("3.14");
await AssertInvalidNumberFormatThrows<UInt128>("-1");
await AssertInvalidNumberFormatThrows<Half>("65520");
await AssertInvalidNumberFormatThrows<Half>("-65520");
}
private async Task AssertInvalidNumberFormatThrows<T>(string testString)
{
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<T>(testString));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<T>($@"""{testString}""", s_optionReadFromStr));
}
#endif
[Fact]
public async Task EscapingTest()
{
......@@ -1009,6 +1104,12 @@ public async Task EscapingTest()
await PerformEscapingTest(JsonNumberTestData.Floats, options);
await PerformEscapingTest(JsonNumberTestData.Doubles, options);
await PerformEscapingTest(JsonNumberTestData.Decimals, options);
#if NETCOREAPP
await PerformEscapingTest(JsonNumberTestData.Int128s, options);
await PerformEscapingTest(JsonNumberTestData.UInt128s, options);
await PerformEscapingTest(JsonNumberTestData.Halfs, options);
#endif
}
private async Task PerformEscapingTest<T>(List<T> numbers, JsonSerializerOptions options)
......@@ -1080,6 +1181,11 @@ public async Task Number_RoundtripNull()
await Perform_Number_RoundTripNull_Test<ulong>();
await Perform_Number_RoundTripNull_Test<float>();
await Perform_Number_RoundTripNull_Test<decimal>();
#if NETCOREAPP
await Perform_Number_RoundTripNull_Test<Int128>();
await Perform_Number_RoundTripNull_Test<UInt128>();
await Perform_Number_RoundTripNull_Test<Half>();
#endif
}
private async Task Perform_Number_RoundTripNull_Test<T>()
......@@ -1105,6 +1211,11 @@ public async Task NullableNumber_RoundtripNull()
await Perform_NullableNumber_RoundTripNull_Test<ulong?>();
await Perform_NullableNumber_RoundTripNull_Test<float?>();
await Perform_NullableNumber_RoundTripNull_Test<decimal?>();
#if NETCOREAPP
await Perform_NullableNumber_RoundTripNull_Test<Int128?>();
await Perform_NullableNumber_RoundTripNull_Test<UInt128?>();
await Perform_NullableNumber_RoundTripNull_Test<Half?>();
#endif
}
private async Task Perform_NullableNumber_RoundTripNull_Test<T>()
......@@ -1133,6 +1244,11 @@ public async Task Disallow_ArbritaryStrings_On_AllowFloatingPointConstants()
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<float>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<double>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<decimal>(json, s_optionsAllowFloatConstants));
#if NETCOREAPP
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<Int128>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<UInt128>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<Half>(json, s_optionsAllowFloatConstants));
#endif
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<byte?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<sbyte?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<short?>(json, s_optionsAllowFloatConstants));
......@@ -1144,6 +1260,11 @@ public async Task Disallow_ArbritaryStrings_On_AllowFloatingPointConstants()
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<float?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<double?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<decimal?>(json, s_optionsAllowFloatConstants));
#if NETCOREAPP
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<Int128?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<UInt128?>(json, s_optionsAllowFloatConstants));
await Assert.ThrowsAsync<JsonException>(async () => await Serializer.DeserializeWrapper<Half?>(json, s_optionsAllowFloatConstants));
#endif
}
[Fact]
......
......@@ -244,6 +244,68 @@ public NumberHandlingTests_Metadata()
[JsonSerializable(typeof(List<decimal>))]
[JsonSerializable(typeof(Queue<decimal>))]
[JsonSerializable(typeof(ImmutableList<decimal>))]
#if NETCOREAPP
[JsonSerializable(typeof(Int128))]
[JsonSerializable(typeof(Int128[]))]
[JsonSerializable(typeof(ConcurrentQueue<Int128>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Int128>))]
[JsonSerializable(typeof(IEnumerable<Int128>))]
[JsonSerializable(typeof(Collection<Int128>))]
[JsonSerializable(typeof(HashSet<Int128>))]
[JsonSerializable(typeof(List<Int128>))]
[JsonSerializable(typeof(Queue<Int128>))]
[JsonSerializable(typeof(ImmutableList<Int128>))]
[JsonSerializable(typeof(UInt128))]
[JsonSerializable(typeof(UInt128[]))]
[JsonSerializable(typeof(ConcurrentQueue<UInt128>))]
[JsonSerializable(typeof(GenericICollectionWrapper<UInt128>))]
[JsonSerializable(typeof(IEnumerable<UInt128>))]
[JsonSerializable(typeof(Collection<UInt128>))]
[JsonSerializable(typeof(HashSet<UInt128>))]
[JsonSerializable(typeof(List<UInt128>))]
[JsonSerializable(typeof(Queue<UInt128>))]
[JsonSerializable(typeof(ImmutableList<UInt128>))]
[JsonSerializable(typeof(Half))]
[JsonSerializable(typeof(Half[]))]
[JsonSerializable(typeof(ConcurrentQueue<Half>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Half>))]
[JsonSerializable(typeof(IEnumerable<Half>))]
[JsonSerializable(typeof(Collection<Half>))]
[JsonSerializable(typeof(HashSet<Half>))]
[JsonSerializable(typeof(List<Half>))]
[JsonSerializable(typeof(Queue<Half>))]
[JsonSerializable(typeof(ImmutableList<Half>))]
[JsonSerializable(typeof(Int128?))]
[JsonSerializable(typeof(Int128?[]))]
[JsonSerializable(typeof(ConcurrentQueue<Int128?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Int128?>))]
[JsonSerializable(typeof(IEnumerable<Int128?>))]
[JsonSerializable(typeof(Collection<Int128?>))]
[JsonSerializable(typeof(HashSet<Int128?>))]
[JsonSerializable(typeof(List<Int128?>))]
[JsonSerializable(typeof(Queue<Int128?>))]
[JsonSerializable(typeof(ImmutableList<Int128?>))]
[JsonSerializable(typeof(UInt128?))]
[JsonSerializable(typeof(UInt128?[]))]
[JsonSerializable(typeof(ConcurrentQueue<UInt128?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<UInt128?>))]
[JsonSerializable(typeof(IEnumerable<UInt128?>))]
[JsonSerializable(typeof(Collection<UInt128?>))]
[JsonSerializable(typeof(HashSet<UInt128?>))]
[JsonSerializable(typeof(List<UInt128?>))]
[JsonSerializable(typeof(Queue<UInt128?>))]
[JsonSerializable(typeof(ImmutableList<UInt128?>))]
[JsonSerializable(typeof(Half?))]
[JsonSerializable(typeof(Half?[]))]
[JsonSerializable(typeof(ConcurrentQueue<Half?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Half?>))]
[JsonSerializable(typeof(IEnumerable<Half?>))]
[JsonSerializable(typeof(Collection<Half?>))]
[JsonSerializable(typeof(HashSet<Half?>))]
[JsonSerializable(typeof(List<Half?>))]
[JsonSerializable(typeof(Queue<Half?>))]
[JsonSerializable(typeof(ImmutableList<Half?>))]
#endif
[JsonSerializable(typeof(List<byte>))]
[JsonSerializable(typeof(List<sbyte>))]
[JsonSerializable(typeof(List<short>))]
......@@ -632,6 +694,68 @@ public NumberHandlingTests_Default()
[JsonSerializable(typeof(List<short>))]
[JsonSerializable(typeof(List<int>))]
[JsonSerializable(typeof(List<long>))]
#if NETCOREAPP
[JsonSerializable(typeof(Int128))]
[JsonSerializable(typeof(Int128[]))]
[JsonSerializable(typeof(ConcurrentQueue<Int128>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Int128>))]
[JsonSerializable(typeof(IEnumerable<Int128>))]
[JsonSerializable(typeof(Collection<Int128>))]
[JsonSerializable(typeof(HashSet<Int128>))]
[JsonSerializable(typeof(List<Int128>))]
[JsonSerializable(typeof(Queue<Int128>))]
[JsonSerializable(typeof(ImmutableList<Int128>))]
[JsonSerializable(typeof(UInt128))]
[JsonSerializable(typeof(UInt128[]))]
[JsonSerializable(typeof(ConcurrentQueue<UInt128>))]
[JsonSerializable(typeof(GenericICollectionWrapper<UInt128>))]
[JsonSerializable(typeof(IEnumerable<UInt128>))]
[JsonSerializable(typeof(Collection<UInt128>))]
[JsonSerializable(typeof(HashSet<UInt128>))]
[JsonSerializable(typeof(List<UInt128>))]
[JsonSerializable(typeof(Queue<UInt128>))]
[JsonSerializable(typeof(ImmutableList<UInt128>))]
[JsonSerializable(typeof(Half))]
[JsonSerializable(typeof(Half[]))]
[JsonSerializable(typeof(ConcurrentQueue<Half>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Half>))]
[JsonSerializable(typeof(IEnumerable<Half>))]
[JsonSerializable(typeof(Collection<Half>))]
[JsonSerializable(typeof(HashSet<Half>))]
[JsonSerializable(typeof(List<Half>))]
[JsonSerializable(typeof(Queue<Half>))]
[JsonSerializable(typeof(ImmutableList<Half>))]
[JsonSerializable(typeof(Int128?))]
[JsonSerializable(typeof(Int128?[]))]
[JsonSerializable(typeof(ConcurrentQueue<Int128?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Int128?>))]
[JsonSerializable(typeof(IEnumerable<Int128?>))]
[JsonSerializable(typeof(Collection<Int128?>))]
[JsonSerializable(typeof(HashSet<Int128?>))]
[JsonSerializable(typeof(List<Int128?>))]
[JsonSerializable(typeof(Queue<Int128?>))]
[JsonSerializable(typeof(ImmutableList<Int128?>))]
[JsonSerializable(typeof(UInt128?))]
[JsonSerializable(typeof(UInt128?[]))]
[JsonSerializable(typeof(ConcurrentQueue<UInt128?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<UInt128?>))]
[JsonSerializable(typeof(IEnumerable<UInt128?>))]
[JsonSerializable(typeof(Collection<UInt128?>))]
[JsonSerializable(typeof(HashSet<UInt128?>))]
[JsonSerializable(typeof(List<UInt128?>))]
[JsonSerializable(typeof(Queue<UInt128?>))]
[JsonSerializable(typeof(ImmutableList<UInt128?>))]
[JsonSerializable(typeof(Half?))]
[JsonSerializable(typeof(Half?[]))]
[JsonSerializable(typeof(ConcurrentQueue<Half?>))]
[JsonSerializable(typeof(GenericICollectionWrapper<Half?>))]
[JsonSerializable(typeof(IEnumerable<Half?>))]
[JsonSerializable(typeof(Collection<Half?>))]
[JsonSerializable(typeof(HashSet<Half?>))]
[JsonSerializable(typeof(List<Half?>))]
[JsonSerializable(typeof(Queue<Half?>))]
[JsonSerializable(typeof(ImmutableList<Half?>))]
#endif
[JsonSerializable(typeof(List<ushort>))]
[JsonSerializable(typeof(List<uint>))]
[JsonSerializable(typeof(List<ulong>))]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册