macro_rules! plugin_model {
(@output_ty $Input:tt) => { ... };
(@output_ty $Input:tt, $Output:tt) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => { ... };
}Expand description
Defines a plugin model in a fully generic, and type-safe way.
The macro generates:
- A
structrepresenting the plugin model (derivingDefault) - An implementation of either
PurePluginModelorMutablePluginModel
This removes repetitive boilerplate while ensuring that the relationships between input, output, and context types are enforced at compile time.
Exactly one of:
input:-> immutable model (PurePluginModel)input: mut-> mutable model (MutablePluginModel)
Optionally:
context:enables contextual execution (otherwise context defaults to())root:+child:attaches the model to a plugin family for late resolution
§Syntax
§Immutable Model (No Context)
ⓘ
plugin_model! {
name: pub ModelName, // Required: struct visibility and struct name of the plugin model
input: InputType, // Required: generic immutable input type
output: OutputType, // Optional: output type (defaults to input if omitted)
others: [T1, T2], // Optional: additional generic parameters
bounds: [TraitBounds], // Required: trait bounds for generics
compute: |input, ctx| { ... } // Required: compute logic (`ctx` is `()`)
}§Immutable Model with Context
ⓘ
plugin_model! {
name: pub ModelName, // Required: struct visibility and struct name of the plugin model
input: InputType, // Required: generic immutable input type
output: OutputType, // Optional: output type (defaults to input if omitted)
others: [T1, T2], // Optional: additional generic parameters
context: ContextType, // Required: context struct used during execution
bounds: [TraitBounds], // Required: trait bounds for generics
compute: |input, ctx| { ... } // `ctx: &ContextType`
}§Mutable Model
ⓘ
plugin_model! {
name: pub ModelName, // Required: struct visibility and struct name of the plugin model
input: mut InputType, // Required: mutable input type (`&mut InputType`)
output: OutputType, // Optional: output type (defaults to immutable input type)
others: [T1, T2], // Optional: additional generic parameters
context: ContextType, // Optional: context struct (defaults to `()`)
bounds: [TraitBounds], // Required: trait bounds for generics
compute: |input, ctx| { ... } // Uses `compute_mut`
}§Output Type Semantics
- If
outputis omitted, the output type defaults to the immutable input type, even for mutable models (it does not default to()). - This rule applies to both immutable and mutable plugin models.
- If a unit output
()is desired, it must be specified explicitly as:
ⓘ
output: Output,
bounds: [Output: Default]The Default bound is required so compute’s block can construct the output value.
§Semantics
- Each model is fully generic over its input, output, and optional context.
- If
contextis omitted, the model uses()as its context type. - If
rootandchildare provided, the model becomes a member of a plugin family and is selected indirectly using the(root, child, context)resolution lattice. - Immutable variants use
computewith shared input references. - Mutable variants use
compute_mutand may mutate the input in-place.
All constraints are enforced purely through trait bounds and associated types, guaranteeing compile-time correctness of model wiring and resolution.