Skip to content

Commit d6c3a82

Browse files
ghost1faceCopilot
andauthored
Netstandard20 (#28)
* feat: netstandard20 support with smaller surface area of change * chore: Remove unnecessary dependency since the frameworks include it * feat: Allow tests to run on net481 on windows machines for local testing to validate netstandard20 * chore: Update documentation * chore: dotnet format * chore: Remove unused constant added in testing * Update src/ToonFormat/Internal/Decode/Scanner.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/ToonFormat.Tests/ToonFormat.Tests.csproj Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/ToonFormat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/ToonFormat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/ToonFormat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: Update CompilerFeatureRequiredAttribute to have xml documentation --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 3faa8c3 commit d6c3a82

File tree

19 files changed

+223
-51
lines changed

19 files changed

+223
-51
lines changed

CONTRIBUTING.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ dotnet test --collect:"XPlat Code Coverage"
3636

3737
### .NET Version Support
3838

39-
We target .NET 8.0 and .NET 9.0 for broad compatibility.
39+
We target .NET Standard 2.0 for maximum compatibility across .NET Framework, .NET Core, and .NET 5+. On Windows machines, the `net481` development
40+
framework will need to be installed to validate .NET Standard
4041

4142
### Type Safety
4243

Directory.Build.props

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project>
2+
<PropertyGroup>
3+
<TargetFrameworks>netstandard2.0;net8.0;net9.0;net10.0</TargetFrameworks>
4+
</PropertyGroup>
5+
6+
<!--
7+
1. CI Builds only run tests on modern supported frameworks
8+
2. Local builds run tests on .NET Framework 4.8.1 (Windows only) and modern supported frameworks
9+
-->
10+
<Choose>
11+
<When Condition=" '$(CI)' == 'true'">
12+
<PropertyGroup>
13+
<TestTargetFrameworks>net8.0;net9.0;net10.0</TestTargetFrameworks>
14+
</PropertyGroup>
15+
</When>
16+
17+
<Otherwise>
18+
19+
<Choose>
20+
<When Condition=" $([MSBuild]::IsOsPlatform('Windows')) ">
21+
<PropertyGroup>
22+
<TestTargetFrameworks>net481;net8.0;net9.0;net10.0</TestTargetFrameworks>
23+
</PropertyGroup>
24+
</When>
25+
26+
<Otherwise>
27+
<PropertyGroup>
28+
<TestTargetFrameworks>net8.0;net9.0;net10.0</TestTargetFrameworks>
29+
</PropertyGroup>
30+
</Otherwise>
31+
</Choose>
32+
33+
</Otherwise>
34+
</Choose>
35+
</Project>

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# TOON Format for .NET
22

33
[![NuGet version](https://img.shields.io/nuget/v/Toon.Format.svg)](https://www.nuget.org/packages/Toon.Format/)
4-
[![.NET version](https://img.shields.io/badge/.NET-8.0%20%7C%209.0-512BD4)](https://dotnet.microsoft.com/)
4+
[![.NET version](https://img.shields.io/badge/.NET-Standard%202.0-512BD4)](https://dotnet.microsoft.com/)
5+
[![.NET version](https://img.shields.io/badge/.NET-8.0%20%7C%209.0%20%7C10.0-512BD4)](https://dotnet.microsoft.com/)
56
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
67

78
**Token-Oriented Object Notation** is a compact, human-readable encoding of the JSON data model that minimizes tokens and makes structure easy for models to follow. Combines YAML-like indentation with CSV-like tabular arrays. Fully compatible with the [official TOON specification v3.0](https://github.com/toon-format/spec).
89

9-
**Key Features:** Minimal syntax • TOON Encoding and Decoding • Tabular arrays for uniform data • Path expansion • Strict mode validation • .NET 8.0, 9.0 and 10.0 • 520+ tests with 99.7% spec coverage.
10+
**Key Features:** Minimal syntax • TOON Encoding and Decoding • Tabular arrays for uniform data • Path expansion • Strict mode validation • .NET Standard, .NET 8.0, 9.0 and 10.0 • 520+ tests with 99.7% spec coverage.
1011

1112
## Quick Start
1213

@@ -253,7 +254,7 @@ This implementation:
253254
- Supports all TOON v3.0 features
254255
- Handles all edge cases and strict mode validations
255256
- Fully documented with XML comments
256-
- Production-ready for .NET 8.0, .NET 9.0 and .NET 10.0
257+
- Production-ready for .NET Standard 2.0, .NET 8.0, .NET 9.0 and .NET 10.0
257258

258259
See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
259260

src/ToonFormat/Internal/Decode/Parser.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ internal static class Parser
4747
int bracketStart = -1;
4848

4949
// For quoted keys, find bracket after closing quote (not inside the quoted string)
50+
#if NETSTANDARD2_0
51+
if (trimmed.StartsWith(Constants.DOUBLE_QUOTE.ToString()))
52+
#else
5053
if (trimmed.StartsWith(Constants.DOUBLE_QUOTE))
54+
#endif
5155
{
5256
var closingQuoteIndex = StringUtils.FindClosingQuote(trimmed, 0);
5357
if (closingQuoteIndex == -1)

src/ToonFormat/Internal/Decode/Scanner.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@ public static ScanResult ToParsedLines(string source, int indentSize, bool stric
188188
}
189189
parsed.Add(new ParsedLine
190190
{
191-
Raw = new string(lineSpan),
191+
Raw = lineSpan.ToString(),
192192
Indent = indent,
193-
Content = new string(contentSpan),
193+
Content = contentSpan.ToString(),
194194
Depth = lineDepth,
195195
LineNumber = lineNumber
196196
});

src/ToonFormat/Internal/Encode/Encoders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static string EncodeValue(JsonNode? value, ResolvedEncodeOptions options)
5757
/// <summary>
5858
/// Encodes a JsonObject as key-value pairs.
5959
/// </summary>
60-
public static void EncodeObject(JsonObject value, LineWriter writer, int depth, ResolvedEncodeOptions options, IReadOnlySet<string>? rootLiteralKeys = null,
60+
public static void EncodeObject(JsonObject value, LineWriter writer, int depth, ResolvedEncodeOptions options, IReadOnlyCollection<string>? rootLiteralKeys = null,
6161
string? pathPrefix = null, int? remainingDepth = null)
6262
{
6363
var keys = (value as IDictionary<string, JsonNode>).Keys!;
@@ -96,7 +96,7 @@ public static void EncodeKeyValuePair(
9696
int depth,
9797
ResolvedEncodeOptions options,
9898
IReadOnlyCollection<string>? siblings = null,
99-
IReadOnlySet<string>? rootLiteralKeys = null,
99+
IReadOnlyCollection<string>? rootLiteralKeys = null,
100100
string? pathPrefix = null,
101101
int? flattenDepth = null)
102102
{

src/ToonFormat/Internal/Encode/Folding.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal class KeyChain
4646

4747
internal static class Folding
4848
{
49-
public static FoldResult? TryFoldKeyChain(string key, JsonNode? value, IReadOnlyCollection<string> siblings, ResolvedEncodeOptions options, IReadOnlySet<string>? rootLiteralKeys = null,
49+
public static FoldResult? TryFoldKeyChain(string key, JsonNode? value, IReadOnlyCollection<string> siblings, ResolvedEncodeOptions options, IReadOnlyCollection<string>? rootLiteralKeys = null,
5050
string? pathPrefix = null, int? flattenDepth = null)
5151
{
5252
// Only fold when safe mode is enabled
@@ -149,7 +149,11 @@ private static KeyChain CollectSingleKeyChain(string startKey, JsonNode? startVa
149149

150150
private static string BuildFoldedKey(IReadOnlyCollection<string> segments)
151151
{
152+
#if NETSTANDARD2_0
153+
return string.Join(Constants.DOT.ToString(), segments);
154+
#else
152155
return string.Join(Constants.DOT, segments);
156+
#endif
153157
}
154158
}
155159
}

src/ToonFormat/Internal/Encode/Normalize.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal static class Normalize
2222
/// Normalizes an arbitrary .NET value to a JsonNode representation.
2323
/// Handles primitives, collections, dates, and custom objects.
2424
/// </summary>
25+
/// <param name="value">The value to be normalized.</param>
2526
public static JsonNode? NormalizeValue(object? value)
2627
{
2728
// null
@@ -40,7 +41,7 @@ internal static class Normalize
4041
{
4142
// Canonicalize signed zero via FloatUtils
4243
var dn = FloatUtils.NormalizeSignedZero(d);
43-
if (!double.IsFinite(dn))
44+
if (!NumericUtils.IsFinite(dn))
4445
return null;
4546
return JsonValue.Create(dn);
4647
}
@@ -49,7 +50,7 @@ internal static class Normalize
4950
{
5051
// Canonicalize signed zero via FloatUtils
5152
var fn = FloatUtils.NormalizeSignedZero(f);
52-
if (!float.IsFinite(fn))
53+
if (!NumericUtils.IsFinite(fn))
5354
return null;
5455
return JsonValue.Create(fn);
5556
}
@@ -138,11 +139,16 @@ internal static class Normalize
138139
return JsonValue.Create(l);
139140
case double d:
140141
if (BitConverter.DoubleToInt64Bits(d) == BitConverter.DoubleToInt64Bits(-0.0)) return JsonValue.Create(0.0);
141-
if (!double.IsFinite(d)) return null;
142+
if (!NumericUtils.IsFinite(d)) return null;
142143
return JsonValue.Create(d);
143144
case float f:
145+
#if NETSTANDARD2_0
146+
// netstandard does not have BitConverter.SingleToInt32Bits
147+
if (FloatUtils.NormalizeSignedZero(f).Equals(0.0f)) return JsonValue.Create(0.0f);
148+
#else
144149
if (BitConverter.SingleToInt32Bits(f) == BitConverter.SingleToInt32Bits(-0.0f)) return JsonValue.Create(0.0f);
145-
if (!float.IsFinite(f)) return null;
150+
#endif
151+
if (!NumericUtils.IsFinite(f)) return null;
146152
return JsonValue.Create(f);
147153
case decimal dec:
148154
return JsonValue.Create(dec);

src/ToonFormat/Internal/Encode/Primitives.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ private static string FormatNumber(double value)
5252
if (result.Contains('.'))
5353
{
5454
result = result.TrimEnd('0');
55-
if (result.EndsWith('.'))
55+
#if NETSTANDARD2_0
56+
if (result.EndsWith(Constants.DOT.ToString()))
57+
#else
58+
if (result.EndsWith(Constants.DOT))
59+
#endif
5660
result = result.TrimEnd('.');
5761
}
5862

src/ToonFormat/Internal/Shared/FloatUtils.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ internal static class FloatUtils
1414
/// <returns></returns>
1515
public static bool NearlyEqual(double a, double b, double absEps = 1e-12, double relEps = 1e-9)
1616
{
17-
if (double.IsNaN(a) && double.IsNaN(b)) return true; // ҵ���ϳ���Ҫ�� NaN == NaN
17+
if (double.IsNaN(a) && double.IsNaN(b)) return true;
1818
if (double.IsInfinity(a) || double.IsInfinity(b)) return a.Equals(b);
19-
if (a == b) return true; // ���� 0.0 == -0.0����ȫ���
19+
if (a == b) return true;
2020

2121
var diff = Math.Abs(a - b);
2222
var scale = Math.Max(Math.Abs(a), Math.Abs(b));
23-
if (scale == 0) return diff <= absEps; // ���߶��ӽ� 0
23+
if (scale == 0) return diff <= absEps;
2424
return diff <= Math.Max(absEps, relEps * scale);
2525
}
2626

@@ -35,7 +35,19 @@ public static double NormalizeSignedZero(double v) =>
3535
/// <summary>
3636
/// Explicitly change -0.0f to +0.0f for float values.
3737
/// </summary>
38-
public static float NormalizeSignedZero(float v) =>
39-
BitConverter.SingleToInt32Bits(v) == BitConverter.SingleToInt32Bits(-0.0f) ? 0.0f : v;
38+
public static float NormalizeSignedZero(float v)
39+
{
40+
#if NETSTANDARD2_0
41+
unsafe
42+
{
43+
int* vBits = (int*)&v;
44+
float negZero = -0.0f;
45+
int* zeroBits = (int*)&negZero;
46+
return *vBits == *zeroBits ? 0.0f : v;
47+
}
48+
#else
49+
return BitConverter.SingleToInt32Bits(v) == BitConverter.SingleToInt32Bits(-0.0f) ? 0.0f : v;
50+
#endif
51+
}
4052
}
4153
}

0 commit comments

Comments
 (0)