We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 4 of 22
Restricted visibility: pub(crate), pub(super), pub(in path)
Implement a visibility checker for direct paths within one crate's module tree. Given item declarations, a viewing module and a target path, return whether that module can access the target through the supplied path.
pub fn visible_from(items: Vec<(String, String)>, viewer: String, target: String) -> bool
Each entry in items is (path, visibility). Modules have entries too.
Paths start with crate and use :: between components. Entries are unique,
all containing modules below the crate root are present, and viewer names
the root or a module in this tree. The root itself need not have an entry.
Return false for an unknown target.
Supported visibility strings are private, pub, pub(crate),
pub(super) and pub(in crate::...). Restriction paths name valid enclosing
scopes, including the declaring module itself. This exercise excludes
imports, re-exports, aliases, struct-field access and trait-specific rules.
Turn each visibility into an allowed scope
For an item at crate::a::b::item, its declaring module is crate::a::b.
A visibility scope includes the named module and all its descendants.
| Visibility | Allowed scope before checking ancestor modules |
|---|---|
private |
The declaring module and its descendants. |
pub(super) |
The declaring module's parent and its descendants. |
pub(in P) |
Module P and its descendants. |
pub(crate) |
The current crate. |
pub |
No item-level restriction for viewers in this crate. |
Module paths need component boundaries. crate::a::child is inside
crate::a, but crate::ab is not. Check equality or a prefix ending in ::,
rather than a bare string prefix.
Check every part of the target path
An accessible item can still be hidden behind an inaccessible containing
module. Check the target, then each declared ancestor module up to the root.
Return false as soon as any visibility rejects the viewer.
For example, suppose crate::outer is public, crate::outer::inner is
private, and crate::outer::inner::Thing is public:
crate::outercan accessThing:inneris private toouterand its descendants, so the viewing module is admitted.crate::outer::inner::deepcan also access it.crate::othercannot access it through that path becauseinnerrejects that viewer.
A private module does not hide its contents from every module outside itself. Its privacy boundary is its declaring module. In particular, a private top-level module is declared at the crate root and is accessible throughout that crate, subject to the visibility of the items inside it.
Understand pub(super) in context
An item declared inside crate::a with pub(super) is visible within
crate, including sibling modules such as crate::b. An item declared
inside crate::a::nested with pub(super) is instead visible within
crate::a. The meaning depends on where the item is declared.
That item-level scope does not bypass the path checks. A more restrictive containing module can still prevent a viewer from reaching the item.
Restriction paths describe enclosing scopes
pub(in crate::a) can restrict an item declared inside crate::a::nested
to crate::a and its descendants. It cannot grant access only to an unrelated
sibling module. A restriction to a non-ancestor scope is rejected by Rust
with E0742; the exercise supplies valid restrictions, so you do not need
to diagnose invalid declarations.
Keep the model's limits clear
pub and pub(crate) admit the same viewers in this model because every
viewer is in the same crate. They differ for external callers. Full Rust
visibility also includes re-exports, which can expose an item through a new
public path even when its original module path is private. This checker
handles only the paths supplied in items.
A single source file can contain nested modules and demonstrate real privacy errors. Here the declarations arrive as runtime data, so implement their access rules as a boolean function. The harness runs several viewer/target queries over the same item table and collects the answers in order.
Check the target and its ancestors using the same scope predicate. Passing requires compilation, correct query results and 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.