tomevault-io

non-exhaustive-public-types

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.

tomevault-io 1 Updated 1mo ago
GitHub

Install

npx skillscat add tomevault-io/tomes/non-exhaustive-public-types

Install via the SkillsCat registry.

SKILL.md

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

// Good: a standards-level enum that is expected to gain variants over time
#[non_exhaustive]
pub enum TransferPolicy {
    AllowAll,
    Blocklist,
    Allowlist { allow_list: AllowlistStorage },
    Custom(AccountProcedureRoot),
}

// External callers are forced to include a wildcard, so a future variant
// (e.g. a time-locked or volume-limited policy) stays non-breaking:
match policy {
    TransferPolicy::AllowAll => ...,
    TransferPolicy::Blocklist => ...,
    TransferPolicy::Allowlist { .. } => ...,
    TransferPolicy::Custom(_) => ...,
    _ => ...,   // adding a variant in a minor release: still compiles
}

// Bad: closed public enum, so any new transfer policy is a breaking change
pub enum TransferPolicy {
    AllowAll,
    Blocklist,
    Allowlist { allow_list: AllowlistStorage },
    Custom(AccountProcedureRoot),
}

Source: 0xMiden/protocol — distributed by TomeVault.

Categories