External Publication
Visit Post

Pre-RFC: `pub(api)` visibility, and static enforcement of crate-internal API boundaries

Rust Internals [Unofficial] May 6, 2026
Source

I think I understand your proposition better now. Admittedly I haven't been able to write large solo rust codebases recently so I've been a bit slow on the uptake. The "power" your RFC adds (in the general case, thinking beyond just APIs and its intended use cases) is opt-in #[api_boundary] compile-time exclusion of symbol exports, with a custom syntax pub(api)to whitelist exports beyond the boundary. Maybe its just me, but the benefits of this can be gained simply by being attentive and understanding existing visibility rules. Perhaps better developer tooling should be provided, to allow for IDEs/linters to help when refactoring with upholding a project's various invariants. Also, given mod api, you can always add another private module layer (e.g. imp or _api) and export the "api surface" all in the api module top level, guaranteeing only symbols named there are exported as the API surface. This pattern can already uphold the refactoring issues you've presented (to my understanding?), it just adds more lines of code.

Also, I've realised my 'Vis Assignments' idea is functionally identical to kornel's excellent suggestion:

Couldn't you replace !#[api] with use crate::something as api and use pub(in api)?

As in converting my original example,

// vis api = vis!(in crate::resources);
use crate::resources as api;
// vis anotherapi = vis!(in crate::resources);
use crate::resources as anotherapi;

// pub(api) fn foo() {}
pub(in api) fn foo() {}

// pub(anotherapi) fn bar() {}
pub(in anotherapi) fn bar() {}

The "bridge" between this patter ('Vis Assigments') and pub(api) symbol export exclusion is the addition of a private module boundary, with which you can gain the power of #[api_boundary] at the cost of increased code.

pub(in crate::anythingyouwant) mod api {
  pub use _api::{Something};
  mod _api {
    use crate::anythingyouwant as api;
    pub(in api) struct Something { };
  }
}

// OK
use api::Something;

// in crate::different
// COMPILE ERROR
use crate::anythingyouwant::api::Something;

Discussion in the ATmosphere

Loading comments...