From 9d40a07efa760c14decdcd377f9251fa39af36b5 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Thu, 10 Sep 2026 20:14:00 +1000 Subject: [PATCH] Add net9 Guid.Variant and Guid.Version Two instance properties. Guid.AllBitsSet and CreateVersion7, the other net9 additions, were already polyfilled, so this closes the type. Both are the high nibble of one byte of the little endian layout ToByteArray produces: the version at index 7 and the variant at index 8. Derived empirically rather than from the RFC, and verified exhaustively over all 65536 combinations of those two bytes, plus 500000 random guids to confirm the other fourteen bytes do not participate. Variant is worth knowing about: it is the raw four bit nibble, not the RFC 4122 variant field, which is only the top two bits. So an ordinary uuid reports 8, 9, 10 or 11 rather than one fixed value. A test asserting a single value failed identically on net11, which is what identified this as a wrong expectation rather than a broken polyfill. Reads through TryWriteBytes into a stack buffer where that exists, from netcoreapp2.1 and netstandard2.1, and falls back to ToByteArray on net461 and netstandard2.0. API count 1153 -> 1155. --- apiCount.include.md | 40 +++---- api_list.include.md | 2 + assemblySize.include.md | 72 ++++++------- readme.md | 118 +++++++++++---------- src/Consume/Consume.cs | 2 + src/Polyfill/Polyfill_Guid.cs | 42 ++++++++ src/Split/net461/Polyfill_Guid.cs | 25 +++++ src/Split/net462/Polyfill_Guid.cs | 25 +++++ src/Split/net47/Polyfill_Guid.cs | 25 +++++ src/Split/net471/Polyfill_Guid.cs | 25 +++++ src/Split/net472/Polyfill_Guid.cs | 25 +++++ src/Split/net48/Polyfill_Guid.cs | 25 +++++ src/Split/net481/Polyfill_Guid.cs | 25 +++++ src/Split/net5.0/Polyfill_Guid.cs | 27 +++++ src/Split/net6.0/Polyfill_Guid.cs | 27 +++++ src/Split/net7.0/Polyfill_Guid.cs | 27 +++++ src/Split/net8.0/Polyfill_Guid.cs | 27 +++++ src/Split/netcoreapp2.0/Polyfill_Guid.cs | 25 +++++ src/Split/netcoreapp2.1/Polyfill_Guid.cs | 27 +++++ src/Split/netcoreapp2.2/Polyfill_Guid.cs | 27 +++++ src/Split/netcoreapp3.0/Polyfill_Guid.cs | 27 +++++ src/Split/netcoreapp3.1/Polyfill_Guid.cs | 27 +++++ src/Split/netstandard2.0/Polyfill_Guid.cs | 25 +++++ src/Split/netstandard2.1/Polyfill_Guid.cs | 27 +++++ src/Split/uap10.0/Polyfill_Guid.cs | 25 +++++ src/Tests/GuidVariantTests.cs | 122 ++++++++++++++++++++++ 26 files changed, 777 insertions(+), 114 deletions(-) create mode 100644 src/Polyfill/Polyfill_Guid.cs create mode 100644 src/Split/net461/Polyfill_Guid.cs create mode 100644 src/Split/net462/Polyfill_Guid.cs create mode 100644 src/Split/net47/Polyfill_Guid.cs create mode 100644 src/Split/net471/Polyfill_Guid.cs create mode 100644 src/Split/net472/Polyfill_Guid.cs create mode 100644 src/Split/net48/Polyfill_Guid.cs create mode 100644 src/Split/net481/Polyfill_Guid.cs create mode 100644 src/Split/net5.0/Polyfill_Guid.cs create mode 100644 src/Split/net6.0/Polyfill_Guid.cs create mode 100644 src/Split/net7.0/Polyfill_Guid.cs create mode 100644 src/Split/net8.0/Polyfill_Guid.cs create mode 100644 src/Split/netcoreapp2.0/Polyfill_Guid.cs create mode 100644 src/Split/netcoreapp2.1/Polyfill_Guid.cs create mode 100644 src/Split/netcoreapp2.2/Polyfill_Guid.cs create mode 100644 src/Split/netcoreapp3.0/Polyfill_Guid.cs create mode 100644 src/Split/netcoreapp3.1/Polyfill_Guid.cs create mode 100644 src/Split/netstandard2.0/Polyfill_Guid.cs create mode 100644 src/Split/netstandard2.1/Polyfill_Guid.cs create mode 100644 src/Split/uap10.0/Polyfill_Guid.cs create mode 100644 src/Tests/GuidVariantTests.cs diff --git a/apiCount.include.md b/apiCount.include.md index 90cae835..670ee30b 100644 --- a/apiCount.include.md +++ b/apiCount.include.md @@ -1,28 +1,28 @@ -**API count: 1153** +**API count: 1155** ### Per Target Framework | Target | APIs | | -- | -- | -| `net461` | 1061 | -| `net462` | 1061 | -| `net47` | 1060 | -| `net471` | 1059 | -| `net472` | 1055 | -| `net48` | 1055 | -| `net481` | 1055 | -| `netstandard2.0` | 1057 | -| `netstandard2.1` | 890 | -| `netcoreapp2.0` | 980 | -| `netcoreapp2.1` | 901 | -| `netcoreapp2.2` | 901 | -| `netcoreapp3.0` | 862 | -| `netcoreapp3.1` | 861 | -| `net5.0` | 739 | -| `net6.0` | 635 | -| `net7.0` | 494 | -| `net8.0` | 373 | +| `net461` | 1063 | +| `net462` | 1063 | +| `net47` | 1062 | +| `net471` | 1061 | +| `net472` | 1057 | +| `net48` | 1057 | +| `net481` | 1057 | +| `netstandard2.0` | 1059 | +| `netstandard2.1` | 892 | +| `netcoreapp2.0` | 982 | +| `netcoreapp2.1` | 903 | +| `netcoreapp2.2` | 903 | +| `netcoreapp3.0` | 864 | +| `netcoreapp3.1` | 863 | +| `net5.0` | 741 | +| `net6.0` | 637 | +| `net7.0` | 496 | +| `net8.0` | 375 | | `net9.0` | 243 | | `net10.0` | 182 | | `net11.0` | 58 | -| `uap10.0` | 1047 | +| `uap10.0` | 1049 | diff --git a/api_list.include.md b/api_list.include.md index faa11269..96ef84de 100644 --- a/api_list.include.md +++ b/api_list.include.md @@ -494,6 +494,8 @@ * `bool TryFormat(Span, int, ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.tryformat?view=net-11.0#system-guid-tryformat(system-span((system-byte))-system-int32@-system-readonlyspan((system-char)))) * `bool TryFormat(Span, int, ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.tryformat?view=net-11.0#system-guid-tryformat(system-span((system-char))-system-int32@-system-readonlyspan((system-char)))) + * `int Variant` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.variant?view=net-11.0) + * `int Version` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.version?view=net-11.0) * `Guid CreateVersion7()` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7?view=net-11.0#system-guid-createversion7) * `Guid CreateVersion7(DateTimeOffset)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7?view=net-11.0#system-guid-createversion7(system-datetimeoffset)) * `Guid Parse(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.parse?view=net-11.0#system-guid-parse(system-readonlyspan((system-byte)))) diff --git a/assemblySize.include.md b/assemblySize.include.md index c9383394..29346deb 100644 --- a/assemblySize.include.md +++ b/assemblySize.include.md @@ -2,24 +2,24 @@ | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | -| netstandard2.1 | 8.5KB | 339.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net461 | 8.5KB | 382.5KB | +374.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net462 | 7.0KB | 386.0KB | +379.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net47 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net471 | 8.5KB | 385.0KB | +376.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net472 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net48 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net481 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp2.0 | 9.0KB | 363.0KB | +354.0KB | +7.5KB | +5.0KB | +7.5KB | +12.0KB | -| netcoreapp2.1 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.0KB | +9.0KB | +13.5KB | -| netcoreapp2.2 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | -| netcoreapp3.1 | 9.5KB | 339.0KB | +329.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net5.0 | 9.5KB | 304.5KB | +295.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | -| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | -| net8.0 | 9.5KB | 185.0KB | +175.5KB | +8.0KB | | +512bytes | +3.0KB | +| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netstandard2.1 | 8.5KB | 340.0KB | +331.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net461 | 8.5KB | 383.0KB | +374.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net462 | 7.0KB | 386.5KB | +379.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net47 | 7.0KB | 386.5KB | +379.5KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | +| net471 | 8.5KB | 385.5KB | +377.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net472 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net48 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net481 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.0 | 9.0KB | 362.0KB | +353.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.1 | 9.0KB | 343.0KB | +334.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.2 | 9.0KB | 343.0KB | +334.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp3.0 | 9.5KB | 341.0KB | +331.5KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | +| netcoreapp3.1 | 9.5KB | 339.5KB | +330.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net5.0 | 9.5KB | 305.0KB | +295.5KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | +| net6.0 | 10.0KB | 246.0KB | +236.0KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | +| net7.0 | 10.0KB | 214.5KB | +204.5KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | +| net8.0 | 9.5KB | 185.5KB | +176.0KB | +8.0KB | | +512bytes | +3.0KB | | net9.0 | 9.5KB | 117.0KB | +107.5KB | +8.0KB | | +512bytes | +3.0KB | | net10.0 | 10.0KB | 93.5KB | +83.5KB | +8.5KB | | +512bytes | +3.0KB | | net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB | @@ -29,24 +29,24 @@ | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 559.0KB | +551.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | -| netstandard2.1 | 8.5KB | 487.5KB | +479.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net461 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net462 | 7.0KB | 562.1KB | +555.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net47 | 7.0KB | 561.8KB | +554.8KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net471 | 8.5KB | 560.5KB | +552.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net472 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net48 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net481 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp2.0 | 9.0KB | 527.5KB | +518.5KB | +15.2KB | +6.7KB | +12.4KB | +17.4KB | -| netcoreapp2.1 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +7.7KB | +13.9KB | +18.9KB | -| netcoreapp2.2 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp3.0 | 9.5KB | 485.6KB | +476.1KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | -| netcoreapp3.1 | 9.5KB | 484.0KB | +474.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net5.0 | 9.5KB | 432.1KB | +422.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| net6.0 | 10.0KB | 352.9KB | +342.9KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | -| net7.0 | 10.0KB | 304.6KB | +294.6KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | -| net8.0 | 9.5KB | 261.8KB | +252.3KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | +| netstandard2.0 | 8.0KB | 559.3KB | +551.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netstandard2.1 | 8.5KB | 488.3KB | +479.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net461 | 8.5KB | 559.3KB | +550.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net462 | 7.0KB | 562.8KB | +555.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net47 | 7.0KB | 562.6KB | +555.6KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | +| net471 | 8.5KB | 561.2KB | +552.7KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net472 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net48 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net481 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.0 | 9.0KB | 526.7KB | +517.7KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.1 | 9.0KB | 495.0KB | +486.0KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.2 | 9.0KB | 495.0KB | +486.0KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp3.0 | 9.5KB | 486.4KB | +476.9KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | +| netcoreapp3.1 | 9.5KB | 484.8KB | +475.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net5.0 | 9.5KB | 432.9KB | +423.4KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | +| net6.0 | 10.0KB | 353.7KB | +343.7KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | +| net7.0 | 10.0KB | 305.4KB | +295.4KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | +| net8.0 | 9.5KB | 262.6KB | +253.1KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | | net9.0 | 9.5KB | 169.1KB | +159.6KB | +15.5KB | | +1.1KB | +3.7KB | | net10.0 | 10.0KB | 136.1KB | +126.1KB | +16.0KB | | +1.1KB | +3.7KB | | net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB | diff --git a/readme.md b/readme.md index c602df7c..4f10402b 100644 --- a/readme.md +++ b/readme.md @@ -13,34 +13,34 @@ The package targets `netstandard2.0` and is designed to support the following ru * `uap10` -**API count: 1153** +**API count: 1155** ### Per Target Framework | Target | APIs | | -- | -- | -| `net461` | 1061 | -| `net462` | 1061 | -| `net47` | 1060 | -| `net471` | 1059 | -| `net472` | 1055 | -| `net48` | 1055 | -| `net481` | 1055 | -| `netstandard2.0` | 1057 | -| `netstandard2.1` | 890 | -| `netcoreapp2.0` | 980 | -| `netcoreapp2.1` | 901 | -| `netcoreapp2.2` | 901 | -| `netcoreapp3.0` | 862 | -| `netcoreapp3.1` | 861 | -| `net5.0` | 739 | -| `net6.0` | 635 | -| `net7.0` | 494 | -| `net8.0` | 373 | +| `net461` | 1063 | +| `net462` | 1063 | +| `net47` | 1062 | +| `net471` | 1061 | +| `net472` | 1057 | +| `net48` | 1057 | +| `net481` | 1057 | +| `netstandard2.0` | 1059 | +| `netstandard2.1` | 892 | +| `netcoreapp2.0` | 982 | +| `netcoreapp2.1` | 903 | +| `netcoreapp2.2` | 903 | +| `netcoreapp3.0` | 864 | +| `netcoreapp3.1` | 863 | +| `net5.0` | 741 | +| `net6.0` | 637 | +| `net7.0` | 496 | +| `net8.0` | 375 | | `net9.0` | 243 | | `net10.0` | 182 | | `net11.0` | 58 | -| `uap10.0` | 1047 | +| `uap10.0` | 1049 | @@ -96,24 +96,24 @@ This project uses features from the newest stable SDK and C# language. As such c | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | -| netstandard2.1 | 8.5KB | 339.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net461 | 8.5KB | 382.5KB | +374.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net462 | 7.0KB | 386.0KB | +379.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net47 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net471 | 8.5KB | 385.0KB | +376.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net472 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net48 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net481 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp2.0 | 9.0KB | 363.0KB | +354.0KB | +7.5KB | +5.0KB | +7.5KB | +12.0KB | -| netcoreapp2.1 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.0KB | +9.0KB | +13.5KB | -| netcoreapp2.2 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | -| netcoreapp3.1 | 9.5KB | 339.0KB | +329.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net5.0 | 9.5KB | 304.5KB | +295.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | -| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | -| net8.0 | 9.5KB | 185.0KB | +175.5KB | +8.0KB | | +512bytes | +3.0KB | +| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netstandard2.1 | 8.5KB | 340.0KB | +331.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net461 | 8.5KB | 383.0KB | +374.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net462 | 7.0KB | 386.5KB | +379.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net47 | 7.0KB | 386.5KB | +379.5KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | +| net471 | 8.5KB | 385.5KB | +377.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net472 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net48 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net481 | 8.5KB | 384.0KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.0 | 9.0KB | 362.0KB | +353.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.1 | 9.0KB | 343.0KB | +334.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.2 | 9.0KB | 343.0KB | +334.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp3.0 | 9.5KB | 341.0KB | +331.5KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | +| netcoreapp3.1 | 9.5KB | 339.5KB | +330.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net5.0 | 9.5KB | 305.0KB | +295.5KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | +| net6.0 | 10.0KB | 246.0KB | +236.0KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | +| net7.0 | 10.0KB | 214.5KB | +204.5KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | +| net8.0 | 9.5KB | 185.5KB | +176.0KB | +8.0KB | | +512bytes | +3.0KB | | net9.0 | 9.5KB | 117.0KB | +107.5KB | +8.0KB | | +512bytes | +3.0KB | | net10.0 | 10.0KB | 93.5KB | +83.5KB | +8.5KB | | +512bytes | +3.0KB | | net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB | @@ -123,24 +123,24 @@ This project uses features from the newest stable SDK and C# language. As such c | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 559.0KB | +551.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | -| netstandard2.1 | 8.5KB | 487.5KB | +479.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net461 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net462 | 7.0KB | 562.1KB | +555.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net47 | 7.0KB | 561.8KB | +554.8KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net471 | 8.5KB | 560.5KB | +552.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net472 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net48 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net481 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp2.0 | 9.0KB | 527.5KB | +518.5KB | +15.2KB | +6.7KB | +12.4KB | +17.4KB | -| netcoreapp2.1 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +7.7KB | +13.9KB | +18.9KB | -| netcoreapp2.2 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp3.0 | 9.5KB | 485.6KB | +476.1KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | -| netcoreapp3.1 | 9.5KB | 484.0KB | +474.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net5.0 | 9.5KB | 432.1KB | +422.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| net6.0 | 10.0KB | 352.9KB | +342.9KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | -| net7.0 | 10.0KB | 304.6KB | +294.6KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | -| net8.0 | 9.5KB | 261.8KB | +252.3KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | +| netstandard2.0 | 8.0KB | 559.3KB | +551.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netstandard2.1 | 8.5KB | 488.3KB | +479.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net461 | 8.5KB | 559.3KB | +550.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net462 | 7.0KB | 562.8KB | +555.8KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net47 | 7.0KB | 562.6KB | +555.6KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | +| net471 | 8.5KB | 561.2KB | +552.7KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net472 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net48 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net481 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.0 | 9.0KB | 526.7KB | +517.7KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.1 | 9.0KB | 495.0KB | +486.0KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.2 | 9.0KB | 495.0KB | +486.0KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp3.0 | 9.5KB | 486.4KB | +476.9KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | +| netcoreapp3.1 | 9.5KB | 484.8KB | +475.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net5.0 | 9.5KB | 432.9KB | +423.4KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | +| net6.0 | 10.0KB | 353.7KB | +343.7KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | +| net7.0 | 10.0KB | 305.4KB | +295.4KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | +| net8.0 | 9.5KB | 262.6KB | +253.1KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | | net9.0 | 9.5KB | 169.1KB | +159.6KB | +15.5KB | | +1.1KB | +3.7KB | | net10.0 | 10.0KB | 136.1KB | +126.1KB | +16.0KB | | +1.1KB | +3.7KB | | net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB | @@ -1109,6 +1109,8 @@ The class `Polyfill` includes the following extension methods: * `bool TryFormat(Span, int, ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.tryformat?view=net-11.0#system-guid-tryformat(system-span((system-byte))-system-int32@-system-readonlyspan((system-char)))) * `bool TryFormat(Span, int, ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.tryformat?view=net-11.0#system-guid-tryformat(system-span((system-char))-system-int32@-system-readonlyspan((system-char)))) + * `int Variant` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.variant?view=net-11.0) + * `int Version` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.version?view=net-11.0) * `Guid CreateVersion7()` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7?view=net-11.0#system-guid-createversion7) * `Guid CreateVersion7(DateTimeOffset)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.createversion7?view=net-11.0#system-guid-createversion7(system-datetimeoffset)) * `Guid Parse(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.guid.parse?view=net-11.0#system-guid-parse(system-readonlyspan((system-byte)))) @@ -2568,7 +2570,7 @@ void ObjectDisposedExceptionExample(bool isDisposed) ObjectDisposedException.ThrowIf(isDisposed, typeof(Consume)); } ``` -snippet source | anchor +snippet source | anchor @@ -2587,7 +2589,7 @@ void EnsureExample(Order order, Customer customer, string customerId, string ema this.quantity = Ensure.NotNegativeOrZero(quantity); } ``` -snippet source | anchor +snippet source | anchor diff --git a/src/Consume/Consume.cs b/src/Consume/Consume.cs index 4fd2d0e5..68142a3c 100644 --- a/src/Consume/Consume.cs +++ b/src/Consume/Consume.cs @@ -204,6 +204,8 @@ void GuidUsage() { var guid = Guid.CreateVersion7(); guid = Guid.CreateVersion7(timestamp: DateTimeOffset.UtcNow); + var variant = guid.Variant; + var version = guid.Version; var result = Guid.TryParse(s: "", provider: null, result: out guid); #if FeatureMemory ReadOnlySpan byteSpan = default; diff --git a/src/Polyfill/Polyfill_Guid.cs b/src/Polyfill/Polyfill_Guid.cs new file mode 100644 index 00000000..c2dff712 --- /dev/null +++ b/src/Polyfill/Polyfill_Guid.cs @@ -0,0 +1,42 @@ +#pragma warning disable + +#if !NET9_0_OR_GREATER + +namespace Polyfills; + +using System; + +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + //Link: https://learn.microsoft.com/en-us/dotnet/api/system.guid.variant?view=net-11.0 + public int Variant => + HighNibble(target, 8); + + /// + /// Gets the version field of the . + /// + //Link: https://learn.microsoft.com/en-us/dotnet/api/system.guid.version?view=net-11.0 + public int Version => + HighNibble(target, 7); + } + + // Both fields are the high nibble of a single byte of the little endian layout that + // ToByteArray and TryWriteBytes produce: the version at index 7 and the variant at index 8. + static int HighNibble(Guid value, int index) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; +#else + return value.ToByteArray()[index] >> 4; +#endif + } +} + +#endif diff --git a/src/Split/net461/Polyfill_Guid.cs b/src/Split/net461/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net461/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net462/Polyfill_Guid.cs b/src/Split/net462/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net462/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net47/Polyfill_Guid.cs b/src/Split/net47/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net47/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net471/Polyfill_Guid.cs b/src/Split/net471/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net471/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net472/Polyfill_Guid.cs b/src/Split/net472/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net472/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net48/Polyfill_Guid.cs b/src/Split/net48/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net48/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net481/Polyfill_Guid.cs b/src/Split/net481/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/net481/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/net5.0/Polyfill_Guid.cs b/src/Split/net5.0/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/net5.0/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/net6.0/Polyfill_Guid.cs b/src/Split/net6.0/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/net6.0/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/net7.0/Polyfill_Guid.cs b/src/Split/net7.0/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/net7.0/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/net8.0/Polyfill_Guid.cs b/src/Split/net8.0/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/net8.0/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/netcoreapp2.0/Polyfill_Guid.cs b/src/Split/netcoreapp2.0/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/netcoreapp2.0/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/netcoreapp2.1/Polyfill_Guid.cs b/src/Split/netcoreapp2.1/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/netcoreapp2.1/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/netcoreapp2.2/Polyfill_Guid.cs b/src/Split/netcoreapp2.2/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/netcoreapp2.2/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/netcoreapp3.0/Polyfill_Guid.cs b/src/Split/netcoreapp3.0/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/netcoreapp3.0/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/netcoreapp3.1/Polyfill_Guid.cs b/src/Split/netcoreapp3.1/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/netcoreapp3.1/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/netstandard2.0/Polyfill_Guid.cs b/src/Split/netstandard2.0/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/netstandard2.0/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Split/netstandard2.1/Polyfill_Guid.cs b/src/Split/netstandard2.1/Polyfill_Guid.cs new file mode 100644 index 00000000..5fea935f --- /dev/null +++ b/src/Split/netstandard2.1/Polyfill_Guid.cs @@ -0,0 +1,27 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + Span buffer = stackalloc byte[16]; + value.TryWriteBytes(buffer); + return buffer[index] >> 4; + } +} diff --git a/src/Split/uap10.0/Polyfill_Guid.cs b/src/Split/uap10.0/Polyfill_Guid.cs new file mode 100644 index 00000000..604d6253 --- /dev/null +++ b/src/Split/uap10.0/Polyfill_Guid.cs @@ -0,0 +1,25 @@ +// +#pragma warning disable +#pragma warning disable +namespace Polyfills; +using System; +static partial class Polyfill +{ + extension(Guid target) + { + /// + /// Gets the variant field of the . + /// + public int Variant => + HighNibble(target, 8); + /// + /// Gets the version field of the . + /// + public int Version => + HighNibble(target, 7); + } + static int HighNibble(Guid value, int index) + { + return value.ToByteArray()[index] >> 4; + } +} diff --git a/src/Tests/GuidVariantTests.cs b/src/Tests/GuidVariantTests.cs new file mode 100644 index 00000000..9bbe9df7 --- /dev/null +++ b/src/Tests/GuidVariantTests.cs @@ -0,0 +1,122 @@ +// Runs on every target, so net9.0 and later validate the BCL and everything below the polyfill. +public class GuidVariantTests +{ + // Both fields are exhaustively determined by two bytes, so every combination is checked + // rather than sampled. + [Test] + public async Task ExhaustiveOverBothBytes() + { + var failures = 0; + var visited = 0; + for (var seven = 0; seven < 256; seven++) + for (var eight = 0; eight < 256; eight++) + { + var bytes = new byte[16]; + bytes[7] = (byte) seven; + bytes[8] = (byte) eight; + var guid = new Guid(bytes); + + visited++; + if (guid.Version != seven >> 4 || + guid.Variant != eight >> 4) + { + failures++; + } + } + + await Assert.That(failures).IsEqualTo(0); + await Assert.That(visited).IsEqualTo(65536); + } + + // the other fourteen bytes must not affect either value + [Test] + public async Task OtherBytesAreIgnored() + { + var random = new Random(42); + var failures = 0; + for (var i = 0; i < 20000; i++) + { + var bytes = new byte[16]; + random.NextBytes(bytes); + bytes[7] = 0x74; + bytes[8] = 0xb9; + var guid = new Guid(bytes); + + if (guid.Version != 7 || + guid.Variant != 11) + { + failures++; + } + } + + await Assert.That(failures).IsEqualTo(0); + } + + [Test] + public async Task KnownUuids() + { + // the DNS namespace uuid from RFC 4122, a version 1 uuid + await Assert.That(Guid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8").Version).IsEqualTo(1); + await Assert.That(Guid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8").Variant).IsEqualTo(8); + + // a version 3, name based + await Assert.That(Guid.Parse("3d813cbb-47fb-32ba-91df-831e1593ac29").Version).IsEqualTo(3); + await Assert.That(Guid.Parse("3d813cbb-47fb-32ba-91df-831e1593ac29").Variant).IsEqualTo(9); + + // a version 7, time ordered + await Assert.That(Guid.Parse("01890a5d-ac96-774b-bcce-b302099a8057").Version).IsEqualTo(7); + await Assert.That(Guid.Parse("01890a5d-ac96-774b-bcce-b302099a8057").Variant).IsEqualTo(11); + + await Assert.That(Guid.Empty.Version).IsEqualTo(0); + await Assert.That(Guid.Empty.Variant).IsEqualTo(0); + + var allBitsSet = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"); + await Assert.That(allBitsSet.Version).IsEqualTo(15); + await Assert.That(allBitsSet.Variant).IsEqualTo(15); + } + + // Variant is the raw high nibble of byte 8, not the RFC 4122 variant field, which is only the + // top two bits. So an RFC 4122 uuid reports 8, 9, 10 or 11 rather than one fixed number. + [Test] + public async Task GeneratedGuids() + { + for (var i = 0; i < 2000; i++) + { + var random = Guid.NewGuid(); + await Assert.That(random.Version).IsEqualTo(4); + await Assert.That(random.Variant & 0b1100).IsEqualTo(0b1000); + + var seven = Guid.CreateVersion7(); + await Assert.That(seven.Version).IsEqualTo(7); + await Assert.That(seven.Variant & 0b1100).IsEqualTo(0b1000); + } + } + + // the value comes from the same byte the string form shows, which is the check that would + // catch reading the wrong index or the wrong endianness of the third group + [Test] + public async Task AgreesWithTheStringForm() + { + var random = new Random(7); + var failures = 0; + for (var i = 0; i < 20000; i++) + { + var bytes = new byte[16]; + random.NextBytes(bytes); + var guid = new Guid(bytes); + var text = guid.ToString("D"); + + // "xxxxxxxx-xxxx-Vxxx-Nxxx-xxxxxxxxxxxx" + var version = Convert.ToInt32(text.Substring(14, 1), 16); + var variant = Convert.ToInt32(text.Substring(19, 1), 16); + + if (guid.Version != version || + guid.Variant != variant) + { + failures++; + } + } + + await Assert.That(failures).IsEqualTo(0); + } +}