Skip to content

feat(meta): re-export the streaming surface from the crate root - #224

Merged
Crauzer merged 4 commits into
mainfrom
feat/bin-stream-reexports
Sep 1, 2026
Merged

feat(meta): re-export the streaming surface from the crate root#224
Crauzer merged 4 commits into
mainfrom
feat/bin-stream-reexports

Conversation

@Crauzer

@Crauzer Crauzer commented Sep 1, 2026

Copy link
Copy Markdown
Member

The bin-streaming reader is merged and unreleased. Before it ships, two gaps in its
public surface are worth closing, because both are compiler-proven rather than a
matter of taste, and neither can be fixed later without a second version bump.

The root under-exported stream

stream publishes twenty-one names; the root re-exported eleven. ValueView was
among them but ContainerView, MapView, StructView and OptionalView — the four
you reach by matching on it — were not, so every real walk imported from two places.

The root now mirrors the module's own pub use list. This is what
section 4
already claimed ("re-exported from the crate root") and what #207 promised, so it
closes a gap rather than opening a question. No collisions: tree, error, file
and data_override share none of the ten new names.

concrete carries what Rust cannot infer

A type parameter's default applies in type position but never in expression position.
That makes concrete::BinStream load-bearing rather than a convenience:

let mut stream = ltk_meta::BinStream::mount(File::open(path)?)?;
// error[E0283]: type annotations needed for `BinStream<File, _>`

LruObjectCache::new is the same case, so it joins it. NoCache is re-exported
rather than aliased, because an associated function resolves through a type alias
but a unit struct's value constructor does not.

The views are deliberately not aliased. They are only ever named in type
position, where the default already applies, so the root re-export above is enough —
a second path would rebuild the two-import-site problem this removes.

One trait was missing its default

ObjectCache was the only type in the module without M = NoMeta. A consumer
holding a policy in a struct field had no inference to lean on and had to write
Box<dyn ObjectCache<NoMeta> + Send>, importing NoMeta from a third path. It now
carries the default the rest of the surface has. Nothing published contains this
trait, so it costs no compatibility.

Guard

tests/import_surface.rs names every streaming type from the root or concrete and
nowhere else, mounts with no turbofish and no annotation, names the four sub-views in
type position, and holds a cache policy in a struct field. It asserts real fixture
content, so it fails on a lost export and on a lost default, not merely on a
rename.

Docs

Section 4 read as though moving M onto the handle resolved the annotation problem.
It does not — mount is expression position — and it promised concrete aliases for
two types that do not exist. Both corrected in place; S12 keeps its ID; ADR-0010 is
untouched and still carries the argument.

#210, #211 and #217 are parked with the evidence against each rather than with
"later". All three stay open.

Verification

cargo fmt --all --check, cargo clippy -p ltk_meta --all-targets -- -D warnings,
cargo test --workspace and cargo doc -p ltk_meta --no-deps (under
RUSTDOCFLAGS="-D warnings") all clean.

Also here, as a separate chore: commit: cargo clippy --workspace --all-targets -- -D warnings
was failing at crates/ltk_anim/src/rig/write.rs:71 on unnecessary_sort_by — a clippy 1.97
regression in a file untouched since 2025-09-26, so main was already red. sort_by_key with
Reverse is the same stable descending sort by the same key, so the bytes written do not move.
It is chore rather than fix on purpose: nothing was broken for a user, and release_commits
would read fix as reason to cut an ltk_anim release this does not warrant. The workspace
clippy gate is now green.

The root re-exported eleven of the twenty-one names `stream` publishes, so
any real walk imported from two places: `ValueView` was at the root, but the
four sub-views you reach by matching on it were not. Mirror the module's own
`pub use` list, which is what section 4 of the design already claimed and what
#207 promised.

`concrete` grows the names Rust cannot infer without it. A type parameter's
default applies in type position but never in expression position, so
`BinStream::mount` and `LruObjectCache::new` need an alias to pin `M` where
the views, named only in type position, do not. `NoCache` is re-exported
rather than aliased: an associated function resolves through a type alias, a
unit struct's value constructor does not.

`ObjectCache` was the one type in the module carrying no `M = NoMeta`
default, which left a consumer storing a policy in a struct field spelling
`Box<dyn ObjectCache<NoMeta> + Send>` and importing `NoMeta` from a third
path. Give the trait the default the rest of the surface has. Nothing
published carries this trait yet, so it costs no compatibility.

`tests/import_surface.rs` is the guard: it names every streaming type from
the root or `concrete` and nowhere else, mounts without a turbofish or an
annotation, and names the sub-views in type position, so the spread cannot
come back unnoticed.
…t streaming work

Section 4 read as though moving `M` onto the handle resolved the annotation
problem. It does not: `mount` is expression position, where no default ever
applies, so what a consumer depends on is the `concrete` alias. Handle
placement is what makes `M` reachable by one at all. It also promised
`BinOverrideStream` and `BinFileStream` aliases for types that do not exist
yet, so scope the claim to the shipped surface and say the PTCH handles want
the same treatment when they land. S12 keeps its ID and states the rule;
ADR-0010 still carries the argument.

Park #210, #211 and #217 with the evidence rather than with "later", so the
next session does not re-derive it. The delta writer recovers a fidelity its
consumer already has, and introduces a mixed-numbering refusal a uniform
re-encode never meets; it returns with a measurement. Streaming resolve saves
nothing for a consumer that already reaches its object in O(1) and persists
no paths. PTCH streaming has no consumer at all. All three stay open.
clippy 1.97 raises `unnecessary_sort_by` on the descending comparator, which
has had `--workspace --all-targets -- -D warnings` failing on main since the
toolchain moved. `sort_by_key` with `Reverse` is the same stable descending
sort by the same key, so the bytes written do not move.

Deliberately not a `fix`: nothing was broken for a user, and `release_commits`
would read `fix` as reason to cut an ltk_anim release this does not warrant.
Section 4.4 and ADR-0011 argued the cache from two named consumers and no
numbers. Appendix B puts numbers on it, against a live install: a hit is 286x
cheaper than a miss, but the only access pattern a shipped file can attest -
an editor chasing links - revisits little enough to buy 1.2x, while a
re-requested working set buys 8.3x.

The useful part is that both fall out of one ratio, so a consumer predicts its
own payoff from its own hit rate rather than re-running this. It also says
plainly what the corpus does not support: pattern 2 is modelled, not
harvested, and the miss cost is warm.

PRD-002's "caching by default" exclusion cites the appendix rather than
restating it - the measurement is what makes NoCache-by-default the right
default rather than a hedge.
@Crauzer
Crauzer merged commit 9dd2fcb into main Sep 1, 2026
1 check passed
@Crauzer
Crauzer deleted the feat/bin-stream-reexports branch September 1, 2026 06:50
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