Module :: mod_interface
Provides the mod_interface!
macro to define structured module interfaces with controlled visibility and propagation, simplifying the creation of layered architectures in Rust.
Overview
The mod_interface
crate introduces a procedural macro (mod_interface!
) designed to streamline module organization in Rust projects. It helps address common challenges in maintaining complex codebases:
- Structured Interfaces: Define clear boundaries and relationships between modules (layers) using predefined exposure levels. This promotes a layered architecture where visibility and propagation of items are explicitly controlled.
- Reduced Boilerplate: The macro automatically generates the necessary
use
statements and module structures based on simple directives, reducing manual effort and potential errors. - Improved Readability: By encouraging the explicit definition of a module's interface and how its items are exposed, the crate helps make the codebase easier to understand, navigate, and refactor, reducing cognitive load.
It offers a convention-based approach to modularity, particularly useful for designing complex systems where clear structure and controlled visibility are paramount.
Basic Concepts
In the mod_interface
crate, the concepts of layers and namespaces are central to its modularity approach. Here's a refined explanation:
- Namespaces: These are standard Rust modules that help organize code into logical groups.
- Layers: A layer is a specialized module structured using
mod_interface!
. It contains a set of predefined submodules, referred to as Exposure Levels, which dictate how the contents of the module are propagated to parent layers.
The Exposure Levels within a layer determine the visibility and propagation scope:
Level | Propagation Scope | Purpose |
---|---|---|
private |
Internal only | Original definitions |
own |
Layer only (no propagation) | Layer-specific public items |
orphan |
Immediate parent | Items for direct parent |
exposed |
All ancestors | Items for hierarchy use |
prelude |
All ancestors + intended glob | Core interface essentials (glob use) |
Developers should define all entities within the private
submodule and then re-export them through the other four exposure levels (own
, orphan
, exposed
, prelude
) based on the desired propagation strategy.
Syntax of mod_interface
Macro
The mod_interface
macro provides several directives to manage the relationships between layers and entities:
layer <name>
: Define and include<name>.rs
(or<name>/mod.rs
) as a child layer within the current module.use <path>
: Integrate an existing module at<path>
as a layer into the current module's interface.reuse <path>
: Similar touse
, integrates an existing module layer, potentially with slightly different propagation rules intended for reusing common interfaces.<level> use <item>
: Re-export<item>
(fromprivate
or elsewhere) into the specified exposure level (own
,orphan
,exposed
, orprelude
).<level> mod <name>
: Define<name>.rs
(or<name>/mod.rs
) as a "micro module" and include its contents directly into the specified exposure level.
These directives provide flexibility in organizing and managing the modular structure of a Rust program, enhancing both readability and maintainability.
Example: Using Layers and Entities
This example shows a parent module using a child
layer, demonstrating how items propagate based on their assigned exposure level.
For a module to be used as a layer, it must contain the necessary exposure levels (private
, own
, orphan
, exposed
, prelude
). The mod_interface!
macro helps generate these.
use mod_interface;
// Define a module named `child`.
// Parent module also needs a private namespace.
// Parent module uses the `child` layer.
crate mod_interface!
// fn main() // Example usage demonstrating visibility:
use mod_interface;
// Define a module named `child`
// Parent module also needs a private namespace.
// Parent module uses the `child` layer.
/* crate::mod_interface! { use super::child; } */
// Expanded code generated by the macro:
pub use *;
/// Own namespace of the module.
/// Orphan namespace of the module.
/// Exposed namespace of the module.
/// Prelude to use essentials: `use my_module::prelude::*`.
// fn main() // Example usage demonstrating visibility:
Debugging
To debug module interface use directive #![ debug ]
in macro mod_interface
. Let's update the main file of the example :
!
mod_interface
Full sample see at sample directory.
To add to your project
Try out from the repository
Try out from the repository