We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 8 of 22
pub use re-exports and the facade pattern
Every well-regarded Rust crate separates its file layout from its public
API, and the tool for it is one keyword pair: pub use.
You organise the source however makes sense for the people editing it —
engine/parts.rs, engine/wheels.rs, twelve private modules deep — and then,
at the crate root, you publish a flat, curated surface:
mod engine; // private: nobody outside can say `engine::`
pub use engine::Engine; // but this is public API
pub use engine::parts::Bolt;
Users write my_crate::Engine. You move Engine to a different file next
Tuesday and nobody notices. That is the whole reason the pattern exists, and it
leads directly to the definition that makes SemVer tractable:
A crate’s public API is the set of paths reachable from outside it — not the set of items marked
pub.
The task
pub fn public_api(
modules: Vec<(String, String)>,
items: Vec<(String, String)>,
reexports: Vec<(String, String)>,
) -> Vec<String>
-
modulesanditemsare(path, visibility)pairs, visibility being"pub","pub(crate)"or"private". -
reexportsare(containing_module, target_path)pairs, each meaningpub use <target>;written in<containing_module>.
Return every path by which something is reachable from outside the crate,
sorted — plus the marker "E0364:<target>" for any re-export whose target is
narrower than pub.
Three things the tests are checking
An item in a private module is invisible — until it is re-exported. The
original path disappears (nobody outside can name crate::inner), and the
re-export path appears. pub use short-circuits the privacy chain: it does
not make inner public, it makes the item reachable by a new route.
An item can be reachable twice. If the containing module is also pub,
you get both paths, and both are API you now have to keep working. rustdoc will
render the type twice unless you add #[doc(no_inline)]. Facade crates
generally keep the inner modules private for exactly this reason.
A re-export cannot widen anything. pub use inner::T; where T is only
pub(crate) is E0364 — T is only public within the crate, and cannot be
re-exported outside. And you get a second, confusing diagnostic for free: an
unused import warning, because the failed re-export binds nothing. Two errors,
one mistake. When you see that pair, look at the target’s visibility, not at the
use line.
A pub use written inside a private module is not an error at all — it just
creates no externally reachable path, since the module it lives in is not
reachable either.
pub_use is a restriction lint, and some teams turn it on
clippy::pub_use forbids the pattern outright. The argument is that re-exports
make it harder to see where a type actually comes from, and that a reader
chasing my_crate::Engine has to grep. The counter-argument is that a crate
without a facade has its file layout welded into its SemVer surface forever.
Both positions are real. pub_use is restriction, which means “we implemented
the check, you decide the policy” — not “this is bad Rust”.
Contract
-
The crate root is
"crate"and is always externally reachable. -
Every module on a path appears in
modules. A re-export whose target is not initemsis ignored. - Re-exports are single-hop: no re-export targets another re-export.
- Sort the result lexicographically; markers and paths share one list.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.