| name | non-exhaustive-public-types |
| description | Use when defining a public `enum` or `struct` in a library crate that may gain variants or fields later — keep future additions from being breaking changes. |
Mark Public Types #[non_exhaustive]
Rule
Public enums and public-fielded structs in library crates whose variants/fields are expected to grow should be marked #[non_exhaustive]:
#[non_exhaustive]
pub enum Authority {
AuthControlled,
OwnerControlled,
RbacControlled { role: RoleSymbol },
}
#[non_exhaustive]
pub struct Header {
pub version: u8,
pub flags: u32,
}
This forces external code to use a wildcard match arm (or default field syntax) and lets the library add new variants/fields in a minor release without breaking downstreams.
Don't mark types #[non_exhaustive] when the closed set is part of the contract — e.g. NoteType, a protocol-level enum fixed by the spec and serialized with a fixed-width discriminant, where adding a variant is a breaking protocol change anyway.
Why
Without #[non_exhaustive], a downstream exhaustive match or struct literal compiles today but breaks the moment a minor release adds a variant or field. The attribute makes the wildcard arm mandatory, turning those additions from breaking to non-breaking.
Examples
#[non_exhaustive]
pub enum TransferPolicy {
AllowAll,
Blocklist,
Allowlist { allow_list: AllowlistStorage },
Custom(AccountProcedureRoot),
}
match policy {
TransferPolicy::AllowAll => ...,
TransferPolicy::Blocklist => ...,
TransferPolicy::Allowlist { .. } => ...,
TransferPolicy::Custom(_) => ...,
_ => ...,
}
pub enum TransferPolicy {
AllowAll,
Blocklist,
Allowlist { allow_list: AllowlistStorage },
Custom(AccountProcedureRoot),
}