Repository navigation
v0.8.0 - a char door, one generic door, the platform's own format, and Android
0.8.0 comes from Norse Architecture, which is replacing its last hand-written scalar parsers with HyperCast and filed the two issues behind the first two highlights. It also adds one new platform family: C#, Go and Swift now reach Android. Everything is additive, and no input gets a different verdict than it did in 0.7.0. The full list is in CHANGELOG.md.
Highlights
-
A char door, in the core and every binding (#22). It reads exactly one character verbatim, checked before trimming, so
" "is a space and"6"the digit six. Otherwise it reads one declared code point: decimal65,U+0041,0x41,&H41, or an HTML entityA/A. A surrogate or anything pastU+10FFFFisOutOfRange. It is the twenty-sixth C ABI export,cast_char, andcorpus/char.jsonis replayed by all eight suites.Language Door Returns Rust cast_charcharC# Cast.CharcharJava Cast.characterCharacterGo CharruneSwift Cast.charUnicode.ScalarPHP, Ruby, Python Cast::char,HyperCast.char,cast_chara one-character string C# and Java return a scalar past
U+FFFFasOutOfRange, since theircharis one UTF-16 unit. -
One door generic over every target (#21), in C#, Go and Swift. It picks the door from the requested type, so a caller holding a generic
Troutes through HyperCast in one call.- C#:
Cast.Scalar<T>overbool, the numerics,Guid,DateOnly,TimeOnly,DateTimeOffset,TimeSpan,charandDateTime.Scalar<DateTime>reads RFC 3339 asUtcDateTime. - Go:
Scalar[V ScalarTarget, T Text]. A type outside the union is a compile error. - Swift:
Cast.scalar<T: ScalarCastTarget>(_:format:).
- C#:
-
The numeric doors take the platform's own format object. A caller holding a culture or locale passes it straight through instead of building a
NumFormatfirst. Each maps to the core's format with every lenience on, and aNumFormatis still how to declare anything stricter.- C#: an
IFormatProvider?overload of every numeric door,Numeric<T>andScalar<T>.nullis the current culture, as inTryParse. - Java: a
Localeoverload of every numeric door.NumFormat.from(Locale)is now cached per locale (52.6 ns against 437.6 uncached). - Swift: a
locale:overload of every numeric door,numericandscalar. - PHP: every numeric door accepts
NumFormat|\NumberFormatter, plusNumFormat::fromNumberFormatter. intl stays optional. - Ruby: Rails'
separator:,delimiter:andunit:keywords on every numeric door, plusNumFormat.from_i18nfor anI18n.t("number.format")Hash. - Python and Go keep taking a
NumFormat, since neither standard library has a per-object locale to take.
Every bridge now documents what a culture carries that the core's format cannot yet: a minus sign other than ASCII
-, currency separators that differ from the number ones, and a percent symbol other than%. The roadmap plans the round that closes those gaps. - C#: an
-
Android, in C#, Go and Swift, on arm64 and x86_64.
Language How C# The package carries android-arm64andandroid-x64, so a .NET MAUI app has the core on every platform MAUI targets with nothing but the package reference. CoreCLR loadslibhypercast.sofrom the APK, and a Native AOT publish links it in from a static archive. The libraries are NDK-built for API 21 and 16 KB-aligned, as Android 15 devices and Google Play require.Go GOOS=androidlinksgo/staticlib/android_{arm64,amd64}, with the NDK's clang asCC.Swift Links the artifact bundle's Android variants with the Swift SDK for Android (Swift 6.3+, API 28+). CI builds the C# app both ways for both RIDs from a package packed in the same run, cross-builds the Go and Swift suites, and runs everything x86_64 in an emulator with 16 KB pages.
Fixed
- Ruby: the native extension survives a compacting garbage collection. It kept a handful of Ruby objects (
Success,Fault,Date,DateTime,Decimaland the two built-in formats) in a Rust static that a compacting GC could move. A door called after a compaction could then segfault. Each is now pinned when the extension loads, and a new spec compacts before calling a door. - Go: a build with no cgo (
CGO_ENABLED=0) once again fails with only the one explanatory error, instead of also reportingundefined: symChar.
Upgrade notes
Source-compatible for every consumer except one narrow case.
- Java: a call that passed a literal
nullas the format, such asCast.i32(text, null), no longer compiles, because the newLocaleoverload makes it ambiguous. It already threw at run time, so no working code depends on it. - Rust:
version = "0.8"inCargo.toml. Under 0.x caret rules,"0.7"never resolves to 0.8.
Verifying
Every native library and static archive in this release is built by CI and carries a build-provenance attestation, the new Android libraries and archives included:
gh attestation verify go/staticlib/android_arm64/libhypercast.a \
--repo SkunkWerkx/HyperCast --signer-repo SkunkWerkx/.githubThe gems and Python wheels are attested by this repo's own release.yml, so --repo SkunkWerkx/HyperCast alone verifies them.
The CHANGELOG.md and roadmap links point at the v0.8.0 tag, so they'll only resolve once you've pushed it. If staging ends up on a different date, change the 2026-10-08 in the CHANGELOG heading to match.
C# and Java return a scalar past U+FFFF as OutOfRange, since their char is one UTF-16 unit.
-
One door generic over every target (#21), in C#, Go and Swift. It picks the door from the requested type, so a caller holding a generic
Troutes through HyperCast in one call.- C#:
Cast.Scalar<T>overbool, the numerics,Guid,DateOnly,TimeOnly,DateTimeOffset,TimeSpan,charandDateTime.Scalar<DateTime>reads RFC 3339 asUtcDateTime. - Go:
Scalar[V ScalarTarget, T Text]. A type outside the union is a compile error. - Swift:
Cast.scalar<T: ScalarCastTarget>(_:format:).
- C#:
-
The numeric doors take the platform's own format object. A caller holding a culture or locale passes it straight through instead of building a
NumFormatfirst. Each maps to the core's format with every lenience on, and aNumFormatis still how to declare anything stricter.- C#: an
IFormatProvider?overload of every numeric door,Numeric<T>andScalar<T>.nullis the current culture, as inTryParse. - Java: a
Localeoverload of every numeric door.NumFormat.from(Locale)is now cached per locale (52.6 ns against 437.6 uncached). - Swift: a
locale:overload of every numeric door,numericandscalar. - PHP: every numeric door accepts
NumFormat|\NumberFormatter, plusNumFormat::fromNumberFormatter. intl stays optional. - Ruby: Rails'
separator:,delimiter:andunit:keywords on every numeric door, plusNumFormat.from_i18nfor anI18n.t("number.format")Hash. - Python and Go keep taking a
NumFormat, since neither standard library has a per-object locale to take.
Every bridge now documents what a culture carries that the core's format cannot yet: a minus sign other than ASCII
-, currency separators that differ from the number ones, and a percent symbol other than%. The roadmap plans the round that closes those gaps. - C#: an
-
Android, in C#, Go and Swift, on arm64 and x86_64.
Language How C# The package carries android-arm64andandroid-x64, so a .NET MAUI app has the core on every platform MAUI targets with nothing but the package reference. CoreCLR loadslibhypercast.sofrom the APK, and a Native AOT publish links it in from a static archive. The libraries are NDK-built for API 21 and 16 KB-aligned, as Android 15 devices and Google Play require.Go GOOS=androidlinksgo/staticlib/android_{arm64,amd64}, with the NDK's clang asCC.Swift Links the artifact bundle's Android variants with the Swift SDK for Android (Swift 6.3+, API 28+). CI builds the C# app both ways for both RIDs from a package packed in the same run, cross-builds the Go and Swift suites, and runs everything x86_64 in an emulator with 16 KB pages.
Fixed
- Ruby: the native extension survives a compacting garbage collection. It kept a handful of Ruby objects (
Success,Fault,Date,DateTime,Decimaland the two built-in formats) in a Rust static that a compacting GC could move. A door called after a compaction could then segfault. Each is now pinned when the extension loads, and a new spec compacts before calling a door. - Go: a build with no cgo (
CGO_ENABLED=0) once again fails with only the one explanatory error, instead of also reportingundefined: symChar.
Upgrade notes
Source-compatible for every consumer except one narrow case.
- Java: a call that passed a literal
nullas the format, such asCast.i32(text, null), no longer compiles, because the newLocaleoverload makes it ambiguous. It already threw at run time, so no working code depends on it.
Fixed
- Ruby: the native extension survives a compacting garbage collection. It kept a handful of Ruby objects (
Success,Fault,Date,DateTime,Decimaland the two built-in formats) in a Rust static that a compacting GC could move. A door called after a compaction could then segfault. Each is now pinned when the extension loads, and a new spec compacts before calling a door. - Go: a build with no cgo (
CGO_ENABLED=0) once again fails with only the one explanatory error, instead of also reportingundefined: symChar.
Upgrade notes
Source-compatible for every consumer except one narrow case.
- Java: a call that passed a literal
nullas the format, such asCast.i32(text, null), no longer compiles, because the newLocaleoverload makes it ambiguous. It already threw at run time, so no working code depends on it. - Rust:
version = "0.8"inCargo.toml. Under 0.x caret rules,"0.7"never resolves to 0.8.
Verifying
Every native library and static archive in this release is built by CI and carries a build-provenance attestation, the new Android libraries and archives included:
gh attestation verify go/staticlib/android_arm64/libhypercast.a \
--repo SkunkWerkx/HyperCast --signer-repo SkunkWerkx/.githubThe gems and Python wheels are attested by this repo's own release.yml, so --repo SkunkWerkx/HyperCast alone verifies them.