We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 8 of 22
Model public item paths and re-exports
Implement a small model of externally reachable item paths. The model is
inspired by Rust's module visibility and pub use, with the exact rules below.
It does not perform full Rust name resolution or privacy checking.
pub fn public_api(
modules: Vec<(String, String)>,
items: Vec<(String, String)>,
reexports: Vec<(String, String)>,
) -> Vec<String>
Inputs
modules and items contain (path, visibility) pairs. Visibility is one of
"pub", "pub(crate)" or "private". Declaration paths are unique within each
list. Paths use :: between nonempty names and start at crate; all required
ancestor modules and re-export sites are declared. The root "crate" is
implicit and always externally reachable.
Each re-export is (containing_module, target_item_path). It introduces the
target's final name in the containing module. For example, re-exporting
crate::inner::Thing at crate introduces crate::Thing.
Re-exports only target declarations in items, not modules or other re-exports.
Ignore targets absent from items.
Output rules
Return a sorted list of distinct strings, containing item paths and error markers. Do not include module paths or the root by themselves.
- A module is externally reachable if it is
puband every ancestor between it and the root is alsopub. Both other visibility labels block this route. - Include an item's original path when the item is
puband its containing module is externally reachable. - For each re-export with a known target, inspect the target's own visibility.
If it is not
pub, include"E0364:<target>". Include this marker even if the re-export site is private or has an unreachable ancestor. - Otherwise, include
containing_module::target_leafonly when the site is externally reachable. For this model, the target's ancestor visibility does not prevent that re-export.
Deduplicate both paths and markers, then sort them together using Rust string ordering. A repeated re-export adds no duplicate output. If different targets produce the same output path, include that string once; this model does not report name collisions.
For example, a public crate::inner::Thing inside a private crate::inner,
re-exported at the root, produces ["crate::Thing"]. If inner is public
instead, the output is ["crate::Thing", "crate::inner::Thing"].
With no items and no known re-export targets, the output is empty.
How this relates to Rust
A public re-export can provide a convenient path while keeping an implementation module private. Here is a complete library file:
mod engine {
pub struct Engine;
pub(crate) mod parts {
pub struct Bolt;
}
}
pub use engine::Engine;
pub use engine::parts::Bolt;
If the crate is named facade, a separate binary can use it like this:
fn main() {
let _engine = facade::Engine;
let _bolt = facade::Bolt;
}
External code cannot use facade::engine::Engine, because engine is private.
The library root can access parts because it is pub(crate). Making parts
private would prevent that root-level use from traversing it. Real Rust checks
whether the path is accessible at the re-export site; the exercise deliberately
omits that check and applies output rule 4 instead.
Similarly, E0364:<target> is this exercise's fixed marker for a non-public
target, not a prediction of every Rust diagnostic. Actual diagnostics depend
on the kind of item and the inaccessible part of the path. For example,
re-exporting a restricted function can produce E0364, while a restricted type
can produce E0365. An inaccessible module path can produce E0603.
A public re-export does not make a restricted target public. A public item in a
private module is a different case: the item is already pub, but its original
path is hidden from external code. An accessible re-export can supply a new path.
If both paths are public, callers may rely on either. Reorganizing implementation modules can preserve those paths through re-exports, but compatibility also includes signatures, trait implementations and documented behavior. Reachable paths are only one part of an API contract.
Repair the starter
The first loop checks only the immediate containing module. It needs to check
all ancestors up to the root. The re-export loop currently inserts every target
name, including missing targets and restricted items. Apply the rules in order,
then let the existing BTreeSet handle sorting and duplicate removal.
Your solution must compile, match the outputs and pass Clippy with warnings treated as errors.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.