modum
modum is a proc-macro attribute that rewrites one named Rust item into a generated module path:
NameLikeThis -> name::LikeThis (or name::like_this / name::LIKE_THIS depending on item kind).
Why Use modum?
- Reduce top-level namespace noise by grouping related items under lightweight modules.
- Keep call-sites readable with stable
module::itemaccess patterns. - Make naming conventions explicit across types, functions, and constants.
- Stay compile-time only: no runtime cost, just generated Rust.
The Problem modum Solves
In medium/large crates, top-level items pile up quickly:
- similar prefixes repeated across many items (
UserCreate,UserDelete,UserList, ...) - naming collisions between constants/functions/types
- uneven style drift between Pascal/camel/snake naming sources
modum turns the first semantic segment into a namespace module, so names become easier to scan and group:
UserCreate->user::CreateuserCreate->user::create(forfn)USER_TOTAL->user::TOTAL(forconst/static)
How modum Works
#[modum]:
- Parses the item identifier into segments (
PascalCase,camelCase, orsnake_case). - Uses the first segment as the generated module name (lowercase).
- Uses the remaining segments as the inner item name.
- Re-emits your item as:
pub mod <head>
The original top-level item name is removed. The generated module path is the API.
Table of Contents
Quick Start
use modum;
;
pub const STATE_TOTAL: usize = 22;
Naming Model
Input Styles
PascalCasecamelCasesnake_case
Split Rule
- First segment -> module name (lowercase)
- Remaining segments -> tail item name
Tail Casing by Item Kind
struct,enum,trait,type,union->PascalCasefn->snake_caseconst,static->SCREAMING_SNAKE_CASE
Examples
HTTPServer(struct) ->http::ServermyHTTPServer(fn) ->my::http_serverstate_total(const) ->state::TOTALSTATE_TOTAL(const) ->state::TOTAL
Supported Items
#[modum] supports:
structenumtraittypeunionfn(free function)conststatic
Unsupported item kinds fail with a compile-time error.
Examples
Structs and Enums
use modum;
;
Functions
use modum;
Const and Static
use modum;
pub const STATE_TOTAL: usize = 22;
pub static METRIC_SUM: usize = 99;
Traits and Type Aliases
use modum;
pub type AppList<T> = ;
;
Common Errors and Tips
-
Single-segment names are rejected:
Fooorfoodo not have enough segments.- Use at least two segments, like
FooBar,foo_bar,fooBar.
-
Macro ordering with derives/attr macros matters:
- Prefer placing
#[modum]above#[derive(...)]and similar attribute macros. - Example:
;
- Prefer placing
-
Duplicate generated module names will conflict:
- Two items whose first segment is the same in the same scope both generate the same module.
- Example:
app_valueandapp_stateboth try to createmod app.
-
Original top-level name no longer exists:
- After rewrite, use
module::Itemonly.
- After rewrite, use
API Reference
#[modum]
Apply to one supported named item.
use modum;
;
Generated shape:
Rules:
- No macro arguments are accepted (
#[modum(...)]is invalid). - Item attributes (other than
#[modum]) are preserved. - Module visibility follows the original item visibility.
- Inner generated items are always
pubsomodule::Itemis usable from the parent scope.
Limitations
- Only supported on the item kinds listed above.
- Does not currently merge multiple transformed items into one generated module.
- Renaming/moving into a module can affect privacy and path resolution in edge cases.
License
MIT