Skip to content

Read the whole unit table out of the library instead of typing it - #508

Merged
thebhef merged 1 commit into
mainfrom
task149-units-table
Oct 4, 2026
Merged

thebhef merged 1 commit into
mainfrom
task149-units-table

Conversation

@thebhef

@thebhef thebhef commented Sep 23, 2026

Copy link
Copy Markdown
Owner

The unit facade offered 49 hand-typed rows across 15 of the 110
quantities runtime_units carries, documented as "deliberately a
curated subset". That curation is why a project carrying an LPM unit
string had nothing to map it to: litres were not offered and L / min
could not be composed either, because neither volume nor volume rate
was a dimension the app named. The owner's ruling is that the app does
not curate the library's units at all, so the table now comes from the
library.

Cargo.toml enables the crate's All feature, and units.rs derives
Dimension and UNITS from it. The only hand-written part left is the
dimensions! list: one row per library quantity saying what this
facade calls it. Everything else is read back out of the library — its
own enumeration of a quantity's units, each multiplier, and each
symbol, singular and plural. The table is 2289 rows over 109
dimensions: 930 base units, 1359 prefixed rungs, 115 bases carrying an
SI ladder.

A unit is a prefixed rung of another where the library's name for
it says so and its multiplier agrees with the prefix. Both halves
matter, and the second is what keeps the table honest against the
library's own inconsistencies: ampere per micrometer is named like a
micro-rung of ampere per meter and is a million of them, and 0.6.3
tabulates every sievert above the sievert with a stray x10^-2, so its
decasievert is a tenth of a sievert. Neither goes on a ladder; both
are offered as base units of their own. A rung of a rung is walked down
to the base it really sits on, and dropped where the prefixes do not
add up to one.

The facade's own contributions are now exactly three, each documented
in the module docs: the absolute-temperature offsets (the library
builds no absolute-temperature quantity, so a 0 degC that is 273.15 K
is ours — and the intervals it does carry become a dimension of their
own beside them, per the ruling), the ratio family's scale policy (one
picker row whose column is now every proportion scale the library
carries, not three), and the dimensionless scalar placeholder.

Recognition of a database's unit string gains a pass over every
spelling the library gives a unit, after the built-in recognitions and
the unit ids and before the prefix composition. It is unique or
nothing, as every other pass is: 123 of the 6544 library spellings name
two units and are refused. Four of those matter for an automotive
database — K, degC, degF and h — and all four are already
resolved by the built-in recognitions to the absolute scale and the
hour. C stays deliberately unrecognised: the library spells Celsius
degC and so is unambiguous internally, but a DBC that writes C
means Celsius about as often as coulomb.

Composition resolves against the whole list now, so a product lands on
the first dimension of Dimension::all() sharing its exponents; the
fifteen this facade already named stay at the head in the order they
always resolved in, and the other ninety-four follow alphabetically.
Composed::dimensions is new and answers the whole equivalence class
in that order, which is what a widened kind-lock reads.

Tests: the family, id-uniqueness, spelling round-trip and prefix
cross-check now run over the whole table (the cross-check compares
1000+ composed factors against the library's own answer, up from 100).
New tests enumerate the library and assert every unit is offered as a
base or a rung of one, pin the serialized dimension names against the
fifteen a project file carries, pin the first resolution of every
composition the suite names, and cover the library's two
self-contradictions by name.

Compile and size, measured on one machine the same day with
cargo clean -p cannet-gui -p runtime_units --release then
cargo build -p cannet-gui --release: 137 s -> 176 s (+39 s), and
cannet-gui.exe 24,467,968 -> 25,579,520 bytes (+1.06 MiB).

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com

This was referenced Sep 23, 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