Skip to content

Add net10 IPAddress.IsValid and IsValidUtf8 - #603

Merged
SimonCropp merged 1 commit into
mainfrom
ipaddress-isvalid
Sep 10, 2026
Merged

Add net10 IPAddress.IsValid and IsValidUtf8#603
SimonCropp merged 1 commit into
mainfrom
ipaddress-isvalid

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

Two members, both net10 — and the shortlist entry named only IsValidUtf8, but IsValid(ReadOnlySpan<char>) arrived alongside it and would be odd to ship without.

A third net10 member cannot be added

Parse(ReadOnlySpan<byte>) is also new in net10, and is the obvious companion to the TryParse(ReadOnlySpan<byte>) Polyfill already has. It cannot be polyfilled: GuidPolyfill already declares Parse(ReadOnlySpan<byte>), and because static extension members carry no receiver in their emitted signature, the two are CS0111 Type 'Polyfill' already defines a member called 'Parse' with the same parameter types. Differing return types do not help.

This is the third time this constraint has bitten — after the three Math.BigMul overloads in #594 — so it is //Note:d on TryParse(ReadOnlySpan<byte>), the nearest member that did ship, naming the specific clash.

Worth recording how it surfaced: dotnet build of Polyfill.csproj passed, because that project does not define FeatureMemory and so compiles IPAddressPolyfill.cs away entirely. Only the Consume build across all 22 TFMs caught it. Consume is the real gate for this repo, not the library project.

Verified against net11 rather than assumed equivalent

A 31-input corpus, chosen for the places these parsers historically disagree — partial IPv4 (1.2.3, 1.2, 1), leading and trailing whitespace, 01.02.03.04, IPv6 with scope ids (fe80::1%eth0, fe80::1%12), bracketed ([::1]) and port-suffixed (1.2.3.4:80) forms, ::ffff:1.2.3.4, and full-width (1.2.3.4) and Arabic-Indic (١.٢.٣.٤) digits:

  • IsValid(span) agrees with TryParse(string, out _) on every input — 0 mismatches.
  • IsValidUtf8(bytes) agrees with IsValid(chars) on every input — 0 mismatches.
  • Malformed UTF-8 (FF, a truncated C3, an overlong C3 28, a surrogate encoding ED A0 80) is rejected, and Encoding.UTF8.GetString + IsValid agrees, since the replacement characters do not parse.
  • An empty span is not valid, for either overload.

So the polyfill is TryParse(span.ToString(), out _) and the UTF-8 equivalent, and the tests use TryParse(string) as the oracle — an API that exists unchanged on every framework Polyfill targets, and which the BCL's own IsValid matches.

Allocation note, applied to the whole file

Both new members go through the string overload, which allocates where the BCL validates straight from the span. That is //Note:d — and the same note is added to the three pre-existing members in this file (Parse(ReadOnlySpan<char>), both TryParse span overloads), which have exactly the same characteristic and were previously undocumented. Documenting only the new ones would have left the section inconsistent.

Verification

Solution clean in Release, Consume clean across all 22 TFMs, tests green on net11.0 (1730), net10.0 (1730), net9.0 (1730), net8.0 (1727), net462 (1676), plus PublicTests, EmbeddedTests, UnsafeTests, NoRefsTests and NoExtrasTests. net9.0 is inside the polyfill's window, so it and net10.0 run the identical corpus against the two implementations.

API count 1151 → 1153.

Two members, both net10. The third net10 addition, Parse(ReadOnlySpan<byte>), cannot
be added: GuidPolyfill already declares Parse(ReadOnlySpan<byte>), and static extension
members carry no receiver in their signature, so the two collide with CS0111. Noted on
TryParse(ReadOnlySpan<byte>), which is the nearest member that did ship.

Verified against net11 over a corpus of 31 inputs covering partial IPv4, leading and
trailing whitespace, IPv6 with scope ids, bracketed and port suffixed forms, and
full width and Arabic-Indic digits: IsValid agrees with TryParse on every one, and
IsValidUtf8 agrees with IsValid. Malformed UTF-8 is rejected, and an empty span is not
valid.

Both route through the string overload, which allocates where the BCL validates straight
from the span. Noted, and the same note added to the three existing members in the file,
which have the same characteristic and were previously undocumented.

API count 1151 -> 1153.
@SimonCropp SimonCropp added this to the 11.3.0 milestone Sep 10, 2026
@SimonCropp
SimonCropp merged commit 398b0b6 into main Sep 10, 2026
4 of 6 checks passed
@SimonCropp
SimonCropp deleted the ipaddress-isvalid branch September 10, 2026 10:07
This was referenced Sep 10, 2026
This was referenced Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant