frame_suite/
plugins.rs

1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ```````````````````````````````` PLUGINS SUITE ````````````````````````````````
14// ===============================================================================
15
16//! Pluggable, type-safe execution framework for composing runtime behavior via plugin
17//! models and families.
18//!
19//! This module offers two complementary abstractions for extensible, type-safe
20//! runtime behaviour:
21//!
22//! - Read [Plugin Model](#plugin-model) to understand the **fundamental unit**
23//!   of computation - a single operation plugin, analogous to a pure function
24//!   or a procedure that may mutate its input and produce an output.
25//!
26//! - Read [Plugin Families](#plugin-families) when modelling a **cohesive
27//!   state-machine-like component** composed of multiple related operations
28//!   (methods). A family groups several operation-specific plugin models under
29//!   one logical root, while the concrete implementation variant of each
30//!   operation is plugged via a single family model.
31//!
32//! > **Note:** Plugin families are built on top of plugin models.  
33//! > To correctly design or use families, one must first understand the
34//! > plugin model abstraction, since families internally orchestrate multiple
35//! > models as their operational building blocks.
36//!
37//! In short:
38//!
39//! ```text
40//! Simple, single-step transformation?                 -> Plugin Model
41//! Multi-operation logical component / state machine? -> Plugin Family (built from Plugin Models)
42//! ```
43//!
44//! Both approaches share the same execution infrastructure and compile-time
45//! type-safety guarantees, but differ in how behaviour is structured,
46//! composed, and ultimately resolved.
47//!
48//! # Plugin Model
49//!
50//! A **plugin model** is a type-safe, swappable unit of computation with optional
51//! context. It enables deterministic, composable, and runtime-configurable behavior.
52//!
53//! Each model:
54//! - Implements [`PurePluginModel<Input, Context, Output>`] or
55//!   [`MutablePluginModel<Input, Context, Output>`]
56//! - Produces an output from input (and optional context)
57//!
58//! Execution:
59//! - `compute(input, &context) -> output`
60//! - `compute_mut(&mut input, &context) -> output`
61//!
62//! Context:
63//! - Provided via [`ModelContext`]
64//! - Defined using [`plugin_context`](crate::plugin_context)
65//!
66//! Tooling:
67//! - Declare via [`plugin_types`](crate::plugin_types)
68//! - Define via [`plugin_model`](crate::plugin_model)
69//! - Execute via [`plugin_output`](crate::plugin_output)
70//! - Test with [`plugin_test`](crate::plugin_test)
71//!
72//! ## Motivation
73//!
74//! Conventional trait-based designs couple the **contract** and the
75//! **implementation** into a single resolution step:
76//!
77//! ```text
78//! Sub-set Contract (Trait Bounds)
79//!        |
80//!        v
81//! Concrete Type (Implementation)
82//! ```
83//!
84//! The implementation is chosen first, and the contract is something it must
85//! satisfy. Any **stronger bounds or richer behavior** remain internal to the
86//! concrete type and cannot be independently selected or composed.
87//!
88//! This leads to key limitations:
89//!
90//! - Behavior is fixed once the type is chosen
91//! - Stronger capabilities cannot be surfaced or selected explicitly
92//! - Context-driven or configuration-based behavior becomes difficult
93//!
94//! ## Behaviour Model
95//!
96//! Plugin models treat behavior as a **compatibility problem between two
97//! independent entities**:
98//!
99//! ```text
100//! Sub-set Contract (Pallet)
101//!        <->
102//! Super-set Capability (Model + Bounds + Context)
103//! ```
104//!
105//! These are defined independently and only come together through
106//! **compatibility matching**.
107//!
108//! Matching rule:
109//!
110//! - The super-set must satisfy all requirements of the sub-set
111//! - The sub-set must allow the super-set's stronger bounds
112//!
113//! Only when both conditions hold does a valid composition exist.
114//!
115//! ## Benefits
116//!
117//! - Decoupled contract and behavior
118//! - Multiple interchangeable implementations
119//! - Context-driven execution
120//! - Late selection via configuration
121//! - Full compile-time verification
122//!
123//! Behaviour is not implemented, it is resolved by matching a sub-set contract
124//! with a compatible super-set capability.
125//!
126//! ## Example: Sorter Plugin
127//!
128//! This example shows how a pallet can dynamically select sorting strategies
129//! at runtime via plugin types.
130//!
131//! ```ignore
132//!
133//! // ----- Support Crate -------
134//!
135//! /// A generic sorter plugin trait.
136//! ///
137//! /// This trait defines a plugin point where the actual sorting logic
138//! /// is provided by an associated plugin model and its context.
139//! pub trait Sorter<Input> {
140//!     /// The output type produced by the sorter.
141//!     type Output;
142//!
143//!     // Declare the associated plugin model and context types.
144//!     // These will be supplied by downstream crates (e.g., pallets or runtime).
145//!     plugin_types! {
146//!         input: Input,
147//!         output: Self::Output,
148//!         model: Model,
149//!         context: Context,
150//!     }
151//!
152//!     plugin_output! {
153//!         /// Execute the sorting logic using the injected plugin model.
154//!         ///
155//!         /// The actual implementation is resolved at compile time based on
156//!         /// the associated `Model` and `Context` types.
157//!         fn sort
158//!         input: values,
159//!         model: Self::Model,
160//!         context: Self::Context,
161//!     }
162//! }
163//!
164//! // ----- Pallet Crate -------
165//!
166//! /// Pallet configuration exposing plugin hook points.
167//! ///
168//! /// The runtime will decide which concrete model and context to use.
169//! pub trait Config: frame_system::Config {
170//!     /// Input type consumed by the sorter plugin.
171//!     type InputX;
172//!
173//!     /// Output type produced by the sorter plugin.
174//!     type OutputX;
175//!
176//!     // Declare pallet-level plugin types that must satisfy the plugin contract.
177//!     plugin_types! {
178//!         input: Self::InputX,
179//!         output: Self::OutputX,
180//!         model: ModelX,     // Concrete model chosen by the runtime
181//!         context: ContextX, // Concrete context provider chosen by the runtime
182//!     }
183//! }
184//!
185//! /// Implement the generic sorter plugin for the pallet.
186//! ///
187//! /// The pallet simply forwards execution to the configured model.
188//! impl<T: Config> Sorter<T::InputX> for Pallet<T> {
189//!     type Output = T::OutputX;
190//!     type Model = T::ModelX;
191//!     type Context = T::ContextX;
192//! }
193//!
194//! /// Helper function demonstrating how the plugin is executed generically.
195//! fn try_sort<T: Config>(values: &T::InputX) -> T::OutputX {
196//!     <Pallet<T> as Sorter<T::InputX>>::sort(values)
197//! }
198//!
199//! // ----- Runtime Crate -------
200//!
201//! /// Define a generic plugin model.
202//! /// This model sorts the generic type `Vector` in ascending order and then
203//! /// purges all elements greater than the runtime `until` threshold.
204//! /// Such many models like this can live in plugin-registries
205//! plugin_model! {
206//!     name: CappedSort,
207//!     input: Vector,
208//!     output: Vector,
209//!     context: UntilConfig<Number>,
210//!     others: [Number],
211//!     bounds: [
212//!         // Elements must be comparable and clonable
213//!         Number: Unsigned + Clone + Ord,
214//!         // Vector must be iterable and rebuildable after filtering
215//!         Vector: IntoIterator<Item = Number> + FromIterator<Number> + Clone,
216//!     ],
217//!     compute: |values, ctx| {
218//!         // Clone input so original remains unchanged
219//!         let mut v: Vector = values.clone();
220//!
221//!         // Retrieve runtime threshold from context
222//!         let until = ctx.0.clone();
223//!
224//!         // Sort from small to large
225//!         let mut temp: Vec<Number> = v.into_iter().collect();
226//!         temp.sort();
227//!
228//!         // Find first element greater than `until`
229//!         // Purge that element and everything after it
230//!         let filtered = temp
231//!             .into_iter()
232//!             .take_while(|x| *x <= until)
233//!             .collect::<Vec<_>>();
234//!
235//!         // Rebuild the output vector from the filtered values
236//!         filtered.into_iter().collect()
237//!     }
238//! }
239//!
240//! /// Context data structure holding the threshold value.
241//! /// Such many models's contexts like this can live in
242//! /// plugin-registries, as models and its contexts are tightly coupled
243//! struct UntilConfig<Number>(Number);
244//!
245//! /// Define a concrete context provider supplying the threshold.
246//! plugin_context! {
247//!     name: MyContext,
248//!     context: UntilConfig<u8>,
249//!     value: UntilConfig(10),
250//! }
251//!
252//! /// Inject the concrete model and context into the runtime configuration.
253//! impl Config for Runtime {
254//!     type InputX = Vec<u8>;
255//!     type OutputX = Vec<u8>;
256//!     type ModelX = CappedSort;   // Uses capped sorting logic
257//!     type ContextX = MyContext;  // Provides the `until` threshold
258//! }
259//!
260//! // Example behavior:
261//! // Input:  vec![12, 3, 8, 25, 5]
262//! // Sorted: [3, 5, 8, 12, 25]
263//! // until = 10
264//! // Output: [3, 5, 8]   // elements > 10 are purged
265//!
266//! ```
267//!
268//! The pallet only assumes a generic "sorter" transformation. The runtime injects
269//! `CappedSort`, which sorts values ascending and purges elements greater than a
270//! contextual `until` threshold. The pallet sees only the minimal contract,
271//! while the runtime provides richer, context-driven logic.
272//!
273//! # Plugin Families
274//!
275//! A **plugin family** extends a single plugin model into a **unified logical
276//! plugin** with multiple related operations.
277//!
278//! Unlike a model (one computation), a family represents a cohesive component
279//! (e.g., state machine or service) whose operations are selected via *child*
280//! markers, while a **family type** maps them to concrete models.
281//!
282//! This lets callers use a single interface while deferring implementation
283//! choice to runtime configuration.
284//!
285//! ## Motivation
286//!
287//! A single model fits simple transformations:
288//!
289//! ```text
290//! Model   -> Implementation
291//! Context -> Parameters
292//! ```
293//!
294//! But real systems need:
295//!
296//! - Multiple related operations
297//! - Multiple strategy variants
298//! - Configurable behaviour
299//!
300//! A **plugin family** groups these operations under one unit, where:
301//!
302//! - Children = operations
303//! - Family type = model mapping
304//!
305//! Result: structured, state-machine-like design with compile-time resolution.
306//!
307//! ## State-Machine Style Logical Plugin
308//!
309//! A plugin family acts as a logical component exposing multiple operations,
310//! similar to a state machine or service:
311//!
312//! ```text
313//! Family Root (Unified Interface)
314//!   |-- Child A -> Operation A
315//!   |-- Child B -> Operation B
316//!   |-- Child C -> Operation C -> Concrete Model (via Family Type)
317//! ```
318//!
319//! - **Root**: unified special-interface
320//! - **Child**: operation selector
321//! - **Family type**: maps each operation to a concrete model
322//!
323//! Calling a child is equivalent to invoking a method on the plugin.
324//! The concrete model is resolved by the family type, with context passed
325//! through to execution.
326//!
327//! ### Family Contract Consistency
328//!
329//! All models within a **family type** are expected to share the same
330//! execution contract:
331//!
332//! ```text
333//! Input   -> shared
334//! Output  -> shared
335//! Context -> shared
336//! ```
337//!
338//! This allows the family to behave as a **uniform pluggable component**,
339//! where operations can be invoked without knowledge of the underlying model.
340//!
341//! ```text
342//! Family Type
343//!   |-- Child A -> ModelA<Input, Context, Output>
344//!   |-- Child B -> ModelB<Input, Context, Output>
345//!   |-- Child C -> ModelC<Input, Context, Output>
346//! ```
347//!
348//! With a consistent `(Input, Output, Context)` signature, callers interact
349//! through the root interface while the compiler resolves the concrete model.
350//!
351//! While not strictly enforced, consistent contracts are recommended for
352//! clarity and interchangeability.
353//!
354//! ### Trait Bound Consistency
355//!
356//! Plugin models define `(Input, Output, Context)` generically via trait bounds.
357//!
358//! Within a **family type**, the concrete types must satisfy the **combined
359//! bounds** of all possible models.
360//!
361//! ```text
362//! ModelA requires: Input: Ord
363//! ModelB requires: Input: Clone
364//! ```
365//!
366//! -> Caller must provide:
367//!
368//! ```text
369//! Input: Ord + Clone
370//! ```
371//!
372//! The family contract therefore reflects the **union of required bounds**:
373//!
374//! ```text
375//! Family Contract
376//!   Input: Ord + Clone
377//!   Output: ...
378//! ```
379//!
380//! This guarantees that any selected model can be resolved safely at compile time.
381//!
382//! ## Plugin Family as a Logical Plugin State Machine
383//!
384//! ```text
385//!                         +---------------------------------------+
386//!                         |           FAMILY ROOT                  |
387//!                         |   Unified logical plugin interface    |
388//!                         +--------------------+------------------+
389//!                                              |
390//!                                      Concrete Family Type
391//!                                              |
392//!          +-----------------------------------+-----------------------------------+
393//!          |                                   |                                   |
394//!   +--------------+                    +--------------+                    +--------------+
395//!   |   Child A    |                    |   Child B    |                    |   Child C    |
396//!   | Operation A  |                    | Operation B  |                    | Operation C  |
397//!   +------+-------+                    +------+-------+                    +------+-------+
398//!          |                                   |                                   |
399//!   +------+-------+                    +------+-------+                    +------+-------+
400//!   |   Model A    |                    |   Model B    |                    |   Model C    |
401//!   | selected by  |                    | selected by  |                    | selected by  |
402//!   | Family Type  |                    | Family Type  |                    | Family Type  |
403//!   +------+-------+                    +------+-------+                    +------+-------+
404//!          |                                   |                                   |
405//!          +---------------------------- Context ----------------------------------+
406//!                                   (shared across models)
407//! ```
408//!
409//! In this structure:
410//!
411//! - The **family root** represents the unified logical plugin interface.
412//! - Each **child marker** represents one operation of that interface.
413//! - The **family type** determines which concrete model implements each
414//!   operation.
415//!
416//! All models belonging to the same family share the **same context type**.
417//! The context is therefore represented as a single input flowing into the
418//! resolved model during execution.
419//!
420//! ### Resolution Flow
421//!
422//! ```text
423//! Caller invokes:
424//!   FamilyRoot + FamilyType + ChildX
425//!
426//! Compiler resolves:
427//!   (FamilyType, ChildX) -> ConcreteModel
428//!
429//! Execution:
430//!   ConcreteModel.compute(input, context)
431//! ```
432//!
433//! This allows callers to treat the family as a single logical plugin while
434//! the compiler statically resolves the concrete model for each operation.
435//!
436//! ## Declaration Model
437//!
438//! A plugin family is constructed using three complementary macros:
439//!
440//! - [`declare_family`](crate::declare_family)
441//! - [`plugin_model`](crate::plugin_model)
442//! - [`define_family`](crate::define_family)
443//!
444//! Together they define the **operations**, **models**, and **family
445//! implementation** that make up a plugin family.
446//!
447//! ### 1. Declaring the Family Interface
448//!
449//! The [`declare_family`](crate::declare_family) macro defines the **family
450//! root trait** and a set of **child marker types** representing operations
451//! of the logical plugin.
452//!
453//! ```text
454//! Family Root
455//!   |-- ChildA
456//!   |-- ChildB
457//!   |-- ChildC
458//! ```
459//!
460//! The root trait represents the unified plugin interface, while each child
461//! marker identifies one operation that the family exposes.
462//!
463//!
464//! ### 2. Defining Plugin Models
465//!
466//! Concrete behaviour is implemented using [`plugin_model`](crate::plugin_model).
467//!
468//! Each plugin model implements a specific `(Input, Context, Output)`
469//! computation and can later be attached to a family operation.
470//!
471//! ```text
472//! ModelA<Input, Context, Output>
473//! ModelB<Input, Context, Output>
474//! ModelC<Input, Context, Output>
475//! ```
476//!
477//! Models remain independent units of computation and can be reused across
478//! different families.
479//!
480//!
481//! ### 3. Defining the Family Implementation
482//!
483//! The [`define_family`](crate::define_family) macro creates a **concrete
484//! family type** that binds each child operation to a specific model.
485//!
486//! ```text
487//! FamilyType
488//!   |-- ChildA -> ModelA
489//!   |-- ChildB -> ModelB
490//!   |-- ChildC -> ModelC
491//! ```
492//!
493//! This family type represents a concrete implementation of the family root
494//! and determines which models are used for each operation.
495//!
496//!
497//! ### Resolution Model
498//!
499//! When a caller invokes an operation, it refers only to the **family root**
500//! and a **child marker**.
501//!
502//! The compiler then resolves the concrete model using the configured
503//! family type:
504//!
505//! ```text
506//! (FamilyType, Child) -> ConcreteModel
507//! ```
508//!
509//! The resolved model is then executed using the provided `(Input, Context)`
510//! values.
511//!
512//! This design allows callers to interact with the family as a single logical
513//! plugin while the runtime configuration determines the concrete behaviour
514//! through the selected **family type**.
515//!
516//!
517//! ## Immutable vs Mutable Operational Variants
518//!
519//! A family may host immutable (`PurePluginModel`) and/or mutable
520//! (`MutablePluginModel`) variants for its operations. However, mutability forms
521//! part of the execution contract:
522//!
523//! - Immutable execution resolves only to pure models.
524//! - Mutable execution resolves only to mutable models.
525//!
526//! Even if both coexist in the same family hierarchy, they are not
527//! interchangeable at the usage site because the caller's expected execution
528//! semantics are part of the type-level interface.
529//!
530//! ## Example: Family-Based Model Resolution
531//!
532//! This example demonstrates how a plugin **family** defines a semantic
533//! extension point on a caller trait and how concrete models attach
534//! themselves to that family. The runtime then selects the active model
535//! by supplying an appropriate context.
536//!
537//! In this design the **family is declared by the caller trait**, because
538//! the trait owns the extension point. Concrete plugin models merely
539//! register themselves under that family.
540//!
541//! ### Caller Trait - Declaring the Plugin Family
542//!
543//! The caller trait defines the **plugin contract** and declares the family
544//! that models may attach to.
545//!
546//! ```ignore
547//! declare_family! {
548//!     root: pub MathFamilyRoot,
549//!     child: [MaybePlusOne]
550//! }
551//!
552//! pub trait MathTrait {
553//!     type Input: AtLeast8BitUnsigned;
554//!     type Output: AtLeast8BitUnsigned;
555//!
556//!     plugin_types! {
557//!         input: Self::Input,
558//!         output: Self::Output,
559//!         root: MathFamilyRoot,
560//!         family: MathFamily
561//!         context: MathContext,
562//!     }
563//!
564//!     plugin_output! {
565//!         fn request,
566//!         input: Self::Input,
567//!         output: Self::Output,
568//!         root: MathFamilyRoot,
569//!         family: Self::MathFamily
570//!         child: MaybePlusOne,
571//!         context: Self::MathContext,
572//!     }
573//! }
574//! ```
575//!
576//! Here:
577//!
578//! - `MathFamily` defines the semantic plugin domain.
579//! - `MaybePlusOne` acts as a **child selector**, representing an optional
580//!   increment strategy.
581//!
582//! The trait itself does **not specify which model is used**.
583//!
584//! ### Plugin Models - Registering Implementations
585//!
586//! Plugin models implement behavior for a specific `(Family, Child, Context)`
587//! combination. Multiple models may attach to the same child selector.
588//!
589//! ```ignore
590//! pub struct AddOneContext;
591//!
592//! plugin_model! {
593//!     name: AddOne,
594//!     input: Value,
595//!     context: AddOneContext,
596//!     bounds: [Value: AtLeast8BitUnsigned],
597//!     compute: |v, _ctx| {
598//!         v.clone().saturating_add(One::one())
599//!     }
600//! }
601//!
602//! define_family! {
603//!     root: MathFamilyRoot,
604//!     family: OneFamily,
605//!     input: Value,
606//!     context: AddOneContext
607//!     bounds: [Value: AtLeast8BitUnsigned]
608//!     child: [                      
609//!         MaybePlusOne => AddOne,
610//!     ],
611//! }
612//!```
613//!
614//! ```ignore
615//! pub struct AddNothingContext;
616//!
617//! plugin_model! {
618//!     name: AddNothing,
619//!     input: mut Value,
620//!     context: AddNothingContext,
621//!     bounds: [Value: Clone],
622//!     compute: |v, _ctx| {
623//!         v.clone()
624//!     }
625//! }
626//!
627//! define_family! {
628//!     root: MathFamilyRoot,
629//!     family: NoneFamily,
630//!     input: Value,
631//!     context: AddNothingContext
632//!     bounds: [Value: Clone]
633//!     child: [                      
634//!         MaybePlusOne => AddNothing,
635//!     ],
636//! }
637//! ```
638//!
639//! Both models attach to the same family and child selector but differ
640//! in unified family type, context and execution behavior.
641//!
642//! ### Pallet Wiring - Remaining Generic
643//!
644//! The pallet implements the caller trait without committing to a concrete
645//! model. It simply forwards the family and context from its configuration.
646//!
647//! ```ignore
648//! struct Pallet<T: Config>(PhantomData<T>);
649//!
650//! impl<T: Config> MathTrait for Pallet<T> {
651//!     type Input = T::XInput;
652//!     type Output = T::XOutput;
653//!     type MathFamily = T::XMathFamily;
654//!     type MathContext = T::XMathContext;
655//! }
656//! ```
657//!
658//! This keeps the pallet generic and reusable across runtimes.
659//!
660//! ### Runtime Injection - Selecting the Active Model
661//!
662//! The runtime chooses the concrete behavior by supplying a context that
663//! matches one of the registered models.
664//!
665//! ```ignore
666//! pub trait Config {
667//!     type XInput: AtLeast8BitUnsigned;
668//!     type XOutput: AtLeast8BitUnsigned;
669//!
670//!     plugin_types! {
671//!         input: Self::XInput,
672//!         output: Self::XOutput,
673//!         root: MathFamilyRoot,
674//!         family: XMathFamily,
675//!         context: XMathContext,
676//!     }
677//! }
678//!
679//! plugin_context! {
680//!     name: MyContext,
681//!     context: AddOneContext,
682//!     value: AddOneContext,
683//! }
684//!
685//! pub struct Runtime;
686//!
687//! impl Config for Runtime {
688//!     type XInput = u8;
689//!     type XOutput = u8;
690//!     type XMathFamily = OneFamily;
691//!     type XMathContext = AddOneContext;
692//!
693//!     // Also can be plugged towards
694//!     // type XMathFamily = NoneFamily;
695//!     // type XMathContext = AddNothingContext;
696//! }
697//! ```
698//!
699//! ### Resolution Flow
700//!
701//! ```text
702//! Runtime selects:
703//!   Family  = OneFamily
704//!   Child   = MaybePlusOne
705//!   Context = AddOneContext
706//!
707//! Matching Model:
708//!   AddOne<Input=u8, Context=AddOneContext, Output=u8>
709//! ```
710//!
711//! If the runtime instead supplied `NoneFamily` & `AddNothingContext`, the alternative model
712//! would be selected automatically.
713//!
714//! The caller trait never names a concrete model. Instead, the compiler resolves
715//! the correct implementation purely from the type-level contract:
716//!
717//! ```text
718//! (Family, Child, Context) -> Model
719//! ```
720//!
721//! This enables fully static, type-safe plugin resolution without runtime
722//! dispatch or registration tables.
723
724// ===============================================================================
725// ````````````````````````````````` CORE TRAITS `````````````````````````````````
726// ===============================================================================
727
728/// Core trait implemented by all **immutable plugin models**.
729///
730/// A plugin model is typically a zero-sized (stateless) struct that defines
731/// a specific computation strategy. Each model represents a logically distinct
732/// variant within a plugin and may optionally depend on external context
733/// to compute its result.
734///
735/// This trait defines the **pure computation contract**: the input is owned by
736/// caller immutably and must not be mutated. The model returns a new output value
737/// derived from the input and context.
738///
739/// ## Generics
740/// - `Input`: Type of owned-data consumed by the model.
741/// - `Context`: External parameters or configuration required by the model.
742/// - `Output`: Type of value produced by the model.
743///
744/// ## Determinism
745/// Implementations are expected to be stateless and deterministic, producing
746/// the same output for the same input and context.
747pub trait PurePluginModel<Input, Context, Output>: Default {
748    /// Computes the model's output for a given immutable input and context.
749    fn compute(&self, input: Input, context: &Context) -> Output;
750}
751
752/// Trait implemented by **mutable plugin models** that may transform their
753/// input in-place while still producing an output.
754///
755/// Unlike [`PurePluginModel`], this trait explicitly allows mutation of the input,
756/// making it suitable for in-place normalization, sorting, accumulation,
757/// or other performance-sensitive transformations that avoid extra allocations.
758///
759/// Mutation is **explicit and opt-in**, preserving clarity between pure and
760/// state-transforming computations.
761///
762/// ## Generics
763/// - `Mutate`: Type of data that will be mutated in-place.
764/// - `Context`: External parameters or configuration required by the model.
765/// - `Output`: Type of value produced by the model.
766///
767/// ## Semantics
768/// - The input may be modified during computation.
769/// - The returned output may be derived from either the original or mutated state.
770/// - Implementations should still remain stateless with respect to internal storage.
771pub trait MutablePluginModel<Mutate, Context, Output>: Default {
772    /// Computes the model's output while mutating the input in-place.
773    fn compute_mut(&self, input: &mut Mutate, context: &Context) -> Output;
774}
775
776/// Represents a source of context for models.
777///
778/// Models can retrieve context from an implementor of this trait.
779pub trait ModelContext {
780    /// Associated type representing the actual context.
781    type Context;
782
783    /// Returns the context for a model.
784    fn context() -> Self::Context;
785}
786
787/// Placeholder type for models that **do not require any external context**.
788impl ModelContext for () {
789    type Context = ();
790
791    fn context() -> () {
792        ()
793    }
794}
795
796// ===============================================================================
797// ```````````````````````````````` PLUGIN TYPES `````````````````````````````````
798// ===============================================================================
799
800/// Declares **associated plugin types** inside a trait.
801///
802/// Supports both:
803/// - **concrete plugin model binding**, or
804/// - **plugin family binding** for late model selection.
805///
806/// Exactly one of `model` or `family` must be specified.
807/// Exactly one of `input` or `input: mut` must be specified.
808///
809/// ## Syntax
810///
811/// ### Immutable Concrete Model
812///
813/// ```ignore
814/// plugin_types! {
815///     input: InputType,        // Required: immutable input type
816///     output: OutputType,      // Required: output type
817///     model: ModelAssoc,       // Required: associated plugin model
818///     context: ContextAssoc,   // Required: associated context provider
819/// }
820/// ```
821///
822/// ### Mutable Concrete Model
823///
824/// ```ignore
825/// plugin_types! {
826///     input: mut MutateType,   // Required: mutable input type
827///     output: OutputType,      // Required: output type
828///     model: ModelAssoc,       // Required: associated plugin model
829///     context: ContextAssoc,   // Required: associated context provider
830/// }
831/// ```
832///
833/// ### Plugin Family (Immutable or Mutable)
834///
835/// ```ignore
836/// plugin_types! {
837///     input: InputType,        // or: input: mut MutateType
838///     output: OutputType,      // Required: output type
839///     borrow: ['a],            // Optional: lifetime parameters of input/output
840///     root: PluginFamilyRoot,  // Required: plugin family root trait
841///     family: FamilyAssoc,     // Required: associated plugin family type
842///     context: ContextAssoc,   // Required: associated context provider
843///     provides: [Send + Sync], // Optional: bounds on context
844/// }
845/// ```
846///
847/// ## Lifetimes
848///
849/// - `lifetimes` expands to `<...>` on the **family associated type**
850/// - Enables lifetime-parameterized associated types (GATs)
851///
852/// ## Context Bounds
853///
854/// You may restrict the family's **context type** using `provides`.
855///
856/// ```ignore
857/// plugin_types! {
858///     input: Input,
859///     output: Output,
860///     root: PluginFamilyRoot,
861///     family: FamilyAssoc,    
862///     context: MyContext,
863///     provides: [Send + Sync + 'static],
864/// }
865/// ```
866///
867/// Expands roughly to:
868///
869/// ```ignore
870/// type MyContext: ModelContext<Context: Send + Sync + 'static>;
871/// ```
872///
873/// ## Input / Output Constraints
874///
875/// ### Plugin Models (Immutable & Mutable)
876/// `Input` and `Output` must not contain generics or lifetime-based types (no GATs)
877///
878/// ### Plugin Families
879/// - `Input` and `Output` may include **lifetimes**
880/// - Enabled via parameter `borrow: ['a]`
881/// - Type generics are still not supported
882///
883/// ```text
884/// Model   -> concrete associated types only (no generics, no lifetimes, no GATS)
885/// Family  -> supports lifetimes only (via borrow)
886/// ```
887///
888/// ## Examples
889///
890/// ### Concrete Model
891///
892/// ```ignore
893/// pub trait Increment {
894///     type Input;
895///     type Output;
896///
897///     plugin_types! {
898///         input: Self::Input,
899///         output: Self::Output,
900///         model: AddOneModel,
901///         context: AddOneCtx,
902///     }
903/// }
904/// ```
905///
906/// ### Plugin Family
907///
908/// ```ignore
909/// pub trait MathOps {
910///     type Input;
911///     type Output;
912///
913///     plugin_types! {
914///         input: Self::Input,
915///         output: Self::Output,
916///         root: MathFamilyRoot,
917///         family: MathFamily,
918///         context: MathContext,
919///     }
920/// }
921/// ```
922#[macro_export]
923macro_rules! plugin_types {
924
925    // Immutable model arm
926    (
927        input: $InputTy:ty,
928        output: $OutputTy:ty,
929        $(#[$model_meta:meta])*
930        model: $ModelAssoc:ident,
931        $(#[$ctx_meta:meta])*
932        context: $ContextAssoc:ident $(,)?
933    ) => {
934        $(#[$model_meta])*
935        type $ModelAssoc: $crate::plugins::PurePluginModel<
936                $InputTy,
937                <Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
938                $OutputTy,
939            > + Default;
940
941        $(#[$ctx_meta])*
942        type $ContextAssoc:
943            $crate::plugins::ModelContext;
944    };
945
946    // Mutable model arm
947    (
948        input: mut $MutateTy:ty,
949        output: $OutputTy:ty,
950        $(#[$model_meta:meta])*
951        model: $ModelAssoc:ident,
952        $(#[$ctx_meta:meta])*
953        context: $ContextAssoc:ident $(,)?
954    ) => {
955        $(#[$model_meta])*
956        type $ModelAssoc: $crate::plugins::MutablePluginModel<
957                $MutateTy,
958                <Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
959                $OutputTy,
960            > + Default;
961
962        $(#[$ctx_meta])*
963        type $ContextAssoc:
964            $crate::plugins::ModelContext;
965    };
966
967    // Family model arm
968    (
969        input: $(mut)? $InputTy:ty,
970        output: $OutputTy:ty,
971        $(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
972        root: $Root:ident,
973        $(#[$model_meta:meta])*
974        family: $FamilyAssoc:ident,
975        $(#[$ctx_meta:meta])*
976        context: $ContextAssoc:ident
977        $(, provides: [$($provider:tt)*])? $(,)?
978    ) => {
979        $(#[$model_meta])*
980        type $FamilyAssoc $(<$($borrow_lt)*>)? : $Root<
981                $InputTy,
982                <Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
983                $OutputTy,
984            >;
985
986        $(#[$ctx_meta])*
987        type $ContextAssoc:
988            $crate::plugins::ModelContext$(<Context: $($provider)*>)?;
989    };
990
991}
992
993// ===============================================================================
994// ``````````````````````````````` PLUGIN CONTEXT ````````````````````````````````
995// ===============================================================================
996
997/// Generates a stateless plugin context marker type for a plugin model or a
998/// plugin family.
999///
1000/// This macro defines:
1001/// 1. A zero-sized **marker struct** representing the plugin context provider.
1002/// 2. An implementation of the [`ModelContext`] trait for that marker,
1003///    including a constructor function `context()` returning a value on demand.
1004///
1005/// The `value` construction is on-demand (via [`ModelContext::context`]) which
1006/// allows the context to depend on other constants, statics, or computed values
1007/// while remaining compile-time friendly.
1008///
1009/// When `marker` is specified, the generated struct stores them in `PhantomData`
1010/// fields so the type system correctly tracks them without affecting runtime behavior.
1011///
1012/// - Type generics are tracked using `PhantomData<(T, ...)>`, preserving the
1013///   usual marker semantics for type parameters.
1014///
1015/// ## Syntax
1016///
1017/// ```ignore
1018/// plugin_context! {
1019///     #[attributes...]                // Optional: struct-level attributes (docs, derives, etc.)
1020///     name: pub ContextName,          // Required: visibility and name of the context marker struct
1021///     context: ContextType,           // Required: type representing the context data
1022///
1023///     marker: [T, U],                // Optional: phantom-data parameters applied to the marker
1024///     bounds: [T: Default, U: Clone], // Optional: trait bounds for the generated impl
1025///
1026///     value: ContextExpression,       // Required: expression producing the context value
1027/// }
1028/// ```
1029///
1030/// ## Attributes
1031/// Optional doc comments or other attributes can be attached to the generated
1032/// marker by placing them above the macro invocation.
1033///
1034/// ## Generics Support
1035///
1036/// - Only **type generics** (`T`, `U`, etc.) are supported via `marker: [...]`
1037/// - Lifetime generics are **not supported**
1038/// - The generics are tracked using `PhantomData` and do not affect runtime behavior
1039///
1040/// ## Examples
1041///
1042/// ### Basic Context
1043///
1044/// ```ignore
1045/// plugin_context! {
1046///     name: pub ElectionContext,
1047///     context: PhragmenConfig,
1048///     value: PhragmenConfig { sequential: true }
1049/// }
1050/// ```
1051///
1052/// ### Generic Context
1053///
1054/// ```ignore
1055/// plugin_context! {
1056///     name: pub GenericContext,
1057///     marker: [T],
1058///     context: PhragmenConfig<T>,
1059///     value: PhragmenConfig { sequential: true }
1060/// }
1061/// ```
1062///
1063#[macro_export]
1064macro_rules! plugin_context {
1065    (
1066        $(#[$meta:meta])*
1067        name: $vis:vis $Name:ident,
1068        context: $ContextType:ty,
1069        $(marker: [$($marker_gen:ident),* $(,)?],)?
1070        $(bounds: [$($bounds:tt)*],)?
1071        value: $ContextLiteral:expr $(,)?
1072    ) => {
1073        $crate::__phantom_struct!(
1074            $(#[$meta])*
1075            #[allow(unused)]
1076            $vis
1077            $Name
1078            []
1079            [$($($marker_gen),*)?]
1080        );
1081
1082        impl $(< $($marker_gen,)* >)?
1083        $crate::plugins::ModelContext
1084        for $Name $(< $($marker_gen,)* >)?
1085        $(where $($bounds)*)?
1086        {
1087            type Context = $ContextType;
1088
1089            fn context() -> Self::Context {
1090                $ContextLiteral
1091            }
1092        }
1093    };
1094}
1095
1096// ===============================================================================
1097// ```````````````````````````````` PLUGIN OUTPUT ````````````````````````````````
1098// ===============================================================================
1099
1100/// Generates a strongly-typed associated function that executes a plugin model
1101/// and returns its computed output.
1102///
1103/// The macro expands to a function which:
1104/// - Instantiates the plugin model using `Default`
1105/// - Constructs the execution context via [`ModelContext::context`]
1106/// - Wraps the input, model, and context into the appropriate execution source
1107/// - Executes the model and returns the resulting output
1108///
1109/// This removes boilerplate wiring of model construction, context resolution,
1110/// and execution, while preserving full compile-time type safety.
1111///
1112/// Exactly one of the following must be specified:
1113/// - `model` -> directly executes a concrete plugin model
1114/// - `root` + `family` + `child` -> resolves a model from a plugin family
1115///
1116/// Exactly one of:
1117/// - `input:`     -> immutable execution contract ([`PurePluginModel`])
1118/// - `input: mut` -> mutable execution contract ([`MutablePluginModel`])
1119///
1120/// Optional:
1121/// - `borrow` declares function-level generic parameters for input and output
1122/// specialization in family models.
1123///
1124/// ## Syntax
1125///
1126/// ### Immutable Concrete Model
1127///
1128/// ```ignore
1129/// plugin_output! {
1130///     pub fn run_model,        // Required: function visibility and name to generate
1131///     input: MyInput,          // Required: immutable input type
1132///     output: MyOutput,        // Required: output type produced by the model
1133///     model: MyModel,          // Required: concrete immutable plugin model type
1134///     context: MyContext,      // Required: context provider implementing ModelContext
1135/// }
1136/// ```
1137///
1138/// Expands to:
1139/// `pub fn run_model(input: MyInput) -> MyOutput { ... }`
1140///
1141/// ### Mutable Concrete Model
1142///
1143/// ```ignore
1144/// plugin_output! {
1145///     pub fn run_model_mut,    // Required: function visibility and name to generate
1146///     input: mut MyInput,      // Required: mutable input type
1147///     output: MyOutput,        // Required: output type produced by the model
1148///     model: MyModel,          // Required: concrete mutable plugin model type
1149///     context: MyContext,      // Required: context provider implementing ModelContext
1150/// }
1151/// ```
1152///
1153/// ### Immutable Family-Selected Model
1154///
1155/// ```ignore
1156/// plugin_output! {
1157///     pub fn run_family,       // Required: function visibility and name to generate
1158///     input: MyInput<'a>,      // Required: immutable input type
1159///     output: MyOutput,        // Required: output type produced by the model
1160///     borrow: ['a],            // Optional: function-level liftimes over input/output
1161///     root: MyFamilyRoot,      // Required: plugin family root trait
1162///     family: MyFamily,        // Required: concrete plugin family type
1163///     child: MyChildMarker,    // Required: child model identifier within the family
1164///     context: MyContext,      // Required: context provider implementing ModelContext
1165/// }
1166/// ```
1167///
1168/// ### Mutable Family-Selected Model
1169///
1170/// ```ignore
1171/// plugin_output! {
1172///     pub fn run_family_mut,   // Required: function visibility and name to generate
1173///     input: mut MyInput,      // Required: mutable input type
1174///     output: MyOutput<'a>,    // Required: output type produced by the model
1175///     borrow: ['a],            // Optional: function-level liftimes over input/output
1176///     root: MyFamilyRoot,      // Required: plugin family root trait
1177///     family: MyFamily,        // Required: concrete plugin family type
1178///     child: MyChildMarker,    // Required: child model identifier within the family
1179///     context: MyContext,      // Required: context provider implementing ModelContext
1180/// }
1181/// ```
1182///
1183/// ## Semantics
1184///
1185/// - `model` form executes a fixed concrete plugin model.
1186/// - `root` + `family` + `child` form defers model selection to the plugin family,
1187///   where the concrete model is resolved at compile time using the
1188///   `(Input, Context, Output, Family)` signature.
1189/// - `Context` acts as the nominal discriminator within a family, while
1190///   `Input` and `Output` are validated once concretely resolved at the call site.
1191/// - Mutable variants may mutate the input in-place, but resolution remains
1192///   entirely static through trait bounds.
1193/// - All resolution is performed at compile time; no dynamic dispatch is used.
1194///
1195/// ## Input / Output Constraints
1196///
1197/// - Plugin models (immutable & mutable) use **non-GAT types only**
1198///   - No generics
1199///   - No lifetime-based types (no GATs)
1200///
1201/// - Plugin families may use **lifetimes only**
1202///   - Enabled via `borrow: ['a]`
1203///   - Type generics are not supported
1204///
1205/// ```text
1206/// Model   -> concrete types only
1207/// Family  -> supports lifetimes only
1208/// ```
1209#[macro_export]
1210macro_rules! plugin_output {
1211    // Immutable model function
1212    (
1213        $(#[$meta:meta])*
1214        $vis:vis fn $name:ident,
1215        input: $Input:ty,
1216        output: $Output:ty,
1217        model: $ModelType:ty,
1218        context: $ContextType:ty $(,)?
1219    ) => {
1220        $(#[$meta])*
1221        $vis fn $name (input: $Input) -> $Output
1222        {
1223            // Instantiate the model
1224            let model = <$ModelType>::default();
1225
1226            // Construct the context
1227            let context: <$ContextType as $crate::plugins::ModelContext>::Context =
1228                <$ContextType as $crate::plugins::ModelContext>::context();
1229
1230            // Compute and return output
1231            $crate::plugins::PurePluginModel::<_, _, _>::compute(&model, input, &context)
1232        }
1233    };
1234
1235    // Mutable model function
1236    (
1237        $(#[$meta:meta])*
1238        $vis:vis fn $name:ident,
1239        input: mut $Input:ty,
1240        output: $Output:ty,
1241        model: $ModelType:ty,
1242        context: $ContextType:ty $(,)?
1243    ) => {
1244        $(#[$meta])*
1245        $vis fn $name(input: &mut $Input) -> $Output
1246        {
1247            // Instantiate the model
1248            let model = <$ModelType>::default();
1249
1250            // Construct the context
1251            let context: <$ContextType as $crate::plugins::ModelContext>::Context =
1252                <$ContextType as $crate::plugins::ModelContext>::context();
1253
1254            // Compute and return output
1255            $crate::plugins::MutablePluginModel::<_, _, _>::compute_mut(&model, input, &context)
1256        }
1257    };
1258
1259    // Immutable Family Child-specific function
1260    (
1261        $(#[$meta:meta])*
1262        $vis:vis fn $name:ident,
1263        input: $Input:ty,
1264        output: $Output:ty,
1265        $(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
1266        root: $Root:ident,
1267        family: $Family:ty,
1268        child: $Child:ident,
1269        context: $ContextType:ty $(,)?
1270    ) => {
1271        #[doc = concat!(
1272            "Plugin invocation pure-function for the child - [`",
1273            stringify!($Child),
1274            "`] of the plugin family - [`",
1275            stringify!($Root),
1276            "`]"
1277        )]
1278        $(#[$meta])*
1279        $vis fn $name $(<$($borrow_lt)*>)? (input: $Input) -> $Output
1280        {
1281            // Resolve the concrete plugin model from the family using the root trait
1282            let model =
1283                <$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
1284                    $Output>>::$Child::default();
1285
1286            // Construct the execution context via the context provider.
1287            let context =
1288                <$ContextType as $crate::plugins::ModelContext>::context();
1289
1290            // Execute the immutable plugin model and return the computed output.
1291            <<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
1292                    $Output>>::$Child
1293                    as $crate::plugins::PurePluginModel<
1294                        $Input,
1295                        <$ContextType as $crate::plugins::ModelContext>::Context,
1296                        $Output,
1297                    >>::compute(&model, input, &context)
1298        }
1299    };
1300
1301    // Mutable Family Child-specific function
1302    (
1303        $(#[$meta:meta])*
1304        $vis:vis fn $name:ident,
1305        input: mut $Input:ty,
1306        output: $Output:ty,
1307        $(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
1308        root: $Root:ident,
1309        family: $Family:ty,
1310        child: $Child:ident,
1311        context: $ContextType:ty $(,)?
1312    ) => {
1313        #[doc = concat!(
1314            "Plugin invocation mutable-function for the child - [`",
1315            stringify!($Child),
1316            "`] of the plugin family - [`",
1317            stringify!($Root),
1318            "`]"
1319        )]
1320        $(#[$meta])*
1321        $vis fn $name $(<$($borrow_lt)*>)? (input: &mut $Input) -> $Output
1322        {
1323            // Resolve the concrete plugin model from the family using the root trait
1324            let model =
1325                <$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
1326                    $Output>>::$Child::default();
1327
1328            // Construct the execution context via the context provider.
1329            let context =
1330                <$ContextType as $crate::plugins::ModelContext>::context();
1331
1332            // Execute the immutable plugin model and return the computed output.
1333            <<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
1334                    $Output>>::$Child
1335                    as $crate::plugins::MutablePluginModel<
1336                        $Input,
1337                        <$ContextType as $crate::plugins::ModelContext>::Context,
1338                        $Output,
1339                    >>::compute_mut(&model, input, &context)
1340        }
1341    };
1342}
1343
1344// ===============================================================================
1345// ```````````````````````````````` PLUGIN TESTS `````````````````````````````````
1346// ===============================================================================
1347
1348/// Generates **table-driven unit tests** for plugin models.
1349///
1350/// It supports both **immutable** and **mutable** models, with or without context,
1351/// and with either explicit or inferred output types.
1352///
1353/// For each test case, the macro:
1354/// - Instantiates the plugin model using `Default`
1355/// - Constructs the required context (if any)
1356/// - Executes the model's computation (`compute` for immutable models,
1357///   `compute_mut` for mutable models)
1358/// - Asserts that the computed output matches the expected value
1359/// - Optionally asserts the final mutated input state for mutable models
1360///
1361/// Each test case expands into an **independent `#[test]` function**, ensuring
1362/// clear isolation and accurate failure reporting.
1363///
1364/// ## Features
1365///
1366/// - Supports **immutable** (`PurePluginModel`) and **mutable** (`MutablePluginModel`) models
1367/// - Supports **context-aware** and **context-free** plugin models
1368/// - Supports **explicit output types** or **implicit output = input**
1369/// - Optional assertion of the **mutated input value** for mutable models
1370/// - Generates one `#[test]` function per case
1371/// - Avoids boilerplate while preserving full type safety
1372/// - Mirrors the exact runtime execution contract of plugin models
1373///
1374/// ## Supported Forms
1375///
1376/// The macro supports the same four combinations for both immutable and mutable models:
1377///
1378/// | Context | Output |
1379/// +-------+------+
1380/// | Yes    | Explicit |
1381/// | Yes    | Inferred (output = input) |
1382/// | No     | Explicit |
1383/// | No     | Inferred (output = input) |
1384///
1385/// Mutable models are declared by using `input: mut Type`, which indicates that the
1386/// model will receive `&mut Type` and may transform the input in-place.
1387///
1388/// ## Syntax
1389///
1390/// ```ignore
1391/// plugin_test! {
1392///     model: ModelType,              // Plugin model type to test
1393///     input: InputType | mut InputType, // `mut` enables mutable model testing
1394///     output: OutputType,            // Optional: defaults to `InputType` if omitted
1395///     context: ContextType,          // Optional: required if model uses context
1396///     value: context_expr,           // Optional: expression constructing the context
1397///     cases: {
1398///         (test_name, input_expr, expected_output),
1399///         (test_name_2, input_expr_2, expected_output_2, expected_mutated_input), // mutable only
1400///     }
1401/// }
1402/// ```
1403///
1404/// - `model`: Plugin model type implementing `PurePluginModel` or `MutablePluginModel`
1405/// - `input`: Input type consumed by the model (`mut` indicates in-place mutation)
1406/// - `output`: Output type produced by the model (defaults to input type if omitted)
1407/// - `context`: Context type required by the model (omit for `()`)
1408/// - `value`: Expression that constructs the context instance
1409/// - `cases`: List of test tuples
1410///
1411/// Each case tuple has the form:
1412/// - `(name, input, expected_output)` for immutable models
1413/// - `(name, input, expected_output)` for mutable models when only output is asserted
1414/// - `(name, input, expected_output, expected_mutated_input)` to also verify
1415///   the final mutated state of the input
1416///
1417/// When the fourth element is provided, the macro additionally checks that the
1418/// input was correctly transformed in-place.
1419///
1420/// ## Notes
1421///
1422/// - Each test case expands into a **separate `#[test]` function**
1423/// - Context and input types must match the model's trait implementation
1424/// - Output inference (`output = input`) follows the same rule as `plugin_model!`
1425/// - Compilation fails if input, context, or output types are incompatible
1426///
1427/// This macro is intended for **testing plugin model logic in isolation** and
1428/// should not be used for testing pallet storage, dispatchables, or runtime configuration.
1429#[macro_export]
1430macro_rules! plugin_test {
1431    // Helper: choose output type, defaulting to input if not provided
1432    (@output_ty $InputType:ty) => { $InputType };
1433    (@output_ty $InputType:ty, $OutputType:ty) => { $OutputType };
1434
1435    // WITH CONTEXT, EXPLICIT OUTPUT
1436    (
1437        model: $ModelName:ty,
1438        input: $InputTy:ty,
1439        output: $OutputTy:ty,
1440        context: $ContextTy:ty,
1441        value: $ContextExpr:expr,
1442        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
1443    ) => {
1444        $(
1445            #[test] // generate a #[test] function for each case
1446            fn $test_name() {
1447                let model = <$ModelName>::default();           // instantiate model
1448                let context: $ContextTy = $ContextExpr;        // construct context
1449                let input: $InputTy = $input_expr;             // test input
1450                let result: $OutputTy =                        // compute output
1451                    <$ModelName as $crate::plugins::PurePluginModel<
1452                        $InputTy,
1453                        $ContextTy,
1454                        $OutputTy
1455                    >>::compute(&model, input, &context);
1456                assert_eq!(result, $expected);                // verify result
1457            }
1458        )*
1459    };
1460
1461    // WITH CONTEXT, OUTPUT = INPUT
1462    (
1463        model: $ModelName:ty,
1464        input: $InputTy:ty,
1465        context: $ContextTy:ty,
1466        value: $ContextExpr:expr,
1467        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
1468    ) => {
1469        $(
1470            #[test]
1471            fn $test_name() {
1472                type Output = $InputTy;
1473                let model = <$ModelName>::default();
1474                let context: $ContextTy = $ContextExpr;
1475                let input: $InputTy = $input_expr;
1476                let result: Output =
1477                    <$ModelName as $crate::plugins::PurePluginModel<
1478                        $InputTy,
1479                        $ContextTy,
1480                        Output
1481                    >>::compute(&model, input, &context);
1482                assert_eq!(result, $expected);
1483            }
1484        )*
1485    };
1486
1487    // No Context, EXPLICIT OUTPUT
1488    (
1489        model: $ModelName:ty,
1490        input: $InputTy:ty,
1491        output: $OutputTy:ty,
1492        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
1493    ) => {
1494        $(
1495            #[test]
1496            fn $test_name() {
1497                let model = <$ModelName>::default();
1498                let context: () = Default::default();
1499                let input: $InputTy = $input_expr;
1500                let result: $OutputTy =
1501                    <$ModelName as $crate::plugins::PurePluginModel<
1502                        $InputTy,
1503                        (),
1504                        $OutputTy
1505                    >>::compute(&model, input, &context);
1506                assert_eq!(result, $expected);
1507            }
1508        )*
1509    };
1510
1511    // No Context, OUTPUT = INPUT
1512    (
1513        model: $ModelName:ty,
1514        input: $InputTy:ty,
1515        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
1516    ) => {
1517        $(
1518            #[test]
1519            fn $test_name() {
1520                type Output = $InputTy;
1521                let model = <$ModelName>::default();
1522                let context: () = Default::default();
1523                let input: $InputTy = $input_expr;
1524                let result: Output =
1525                    <$ModelName as $crate::plugins::PurePluginModel<
1526                        $InputTy,
1527                        (),
1528                        Output
1529                    >>::compute(&model, input, &context);
1530                assert_eq!(result, $expected);
1531            }
1532        )*
1533    };
1534
1535    // WITH CONTEXT, EXPLICIT OUTPUT (MUTABLE)
1536    (
1537        model: $ModelName:ty,
1538        input: mut $InputTy:ty,
1539        output: $OutputTy:ty,
1540        context: $ContextTy:ty,
1541        value: $ContextExpr:expr,
1542        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
1543    ) => {
1544        $(
1545            #[test]
1546            fn $test_name() {
1547                let model = <$ModelName>::default();
1548                let context: $ContextTy = $ContextExpr;
1549                let mut input: $InputTy = $input_expr;
1550
1551                let result: $OutputTy =
1552                    <$ModelName as $crate::plugins::MutablePluginModel<
1553                        $InputTy,
1554                        $ContextTy,
1555                        $OutputTy
1556                    >>::compute_mut(&model, &mut input, &context);
1557
1558                assert_eq!(result, $expected);
1559
1560                $(
1561                    assert_eq!(input, $expected_input);
1562                )?
1563            }
1564        )*
1565    };
1566
1567    // WITH CONTEXT, OUTPUT = INPUT (MUTABLE)
1568    (
1569        model: $ModelName:ty,
1570        input: mut $InputTy:ty,
1571        context: $ContextTy:ty,
1572        value: $ContextExpr:expr,
1573        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
1574    ) => {
1575        $(
1576            #[test]
1577            fn $test_name() {
1578                type Output = $InputTy;
1579                let model = <$ModelName>::default();
1580                let context: $ContextTy = $ContextExpr;
1581                let mut input: $InputTy = $input_expr;
1582
1583                let result: Output =
1584                    <$ModelName as $crate::plugins::MutablePluginModel<
1585                        $InputTy,
1586                        $ContextTy,
1587                        Output
1588                    >>::compute_mut(&model, &mut input, &context);
1589
1590                assert_eq!(result, $expected);
1591
1592                $(
1593                    assert_eq!(input, $expected_input);
1594                )?
1595            }
1596        )*
1597    };
1598
1599    // No Context, EXPLICIT OUTPUT (MUTABLE)
1600    (
1601        model: $ModelName:ty,
1602        input: mut $InputTy:ty,
1603        output: $OutputTy:ty,
1604        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
1605    ) => {
1606        $(
1607            #[test]
1608            fn $test_name() {
1609                let model = <$ModelName>::default();
1610                let context: () = Default::default();
1611                let mut input: $InputTy = $input_expr;
1612
1613                let result: $OutputTy =
1614                    <$ModelName as $crate::plugins::MutablePluginModel<
1615                        $InputTy,
1616                        (),
1617                        $OutputTy
1618                    >>::compute_mut(&model, &mut input, &context);
1619
1620                assert_eq!(result, $expected);
1621
1622                $(
1623                    assert_eq!(input, $expected_input);
1624                )?
1625            }
1626        )*
1627    };
1628
1629    // No Context, OUTPUT = INPUT (MUTABLE)
1630    (
1631        model: $ModelName:ty,
1632        input: mut $InputTy:ty,
1633        cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
1634    ) => {
1635        $(
1636            #[test]
1637            fn $test_name() {
1638                type Output = $InputTy;
1639                let model = <$ModelName>::default();
1640                let context: () = Default::default();
1641                let mut input: $InputTy = $input_expr;
1642
1643                let result: Output =
1644                    <$ModelName as $crate::plugins::MutablePluginModel<
1645                        $InputTy,
1646                        (),
1647                        Output
1648                    >>::compute_mut(&model, &mut input, &context);
1649
1650                assert_eq!(result, $expected);
1651
1652                $(
1653                    assert_eq!(input, $expected_input);
1654                )?
1655            }
1656        )*
1657    };
1658}
1659
1660// ===============================================================================
1661// ```````````````````````````````` PLUGIN MODEL `````````````````````````````````
1662// ===============================================================================
1663
1664/// Defines a plugin model in a fully generic, and type-safe way.
1665///
1666/// The macro generates:
1667/// - A `struct` representing the plugin model (deriving `Default`)
1668/// - An implementation of either [`PurePluginModel`] or [`MutablePluginModel`]
1669///
1670/// This removes repetitive boilerplate while ensuring that the relationships
1671/// between input, output, and context types are enforced at compile time.
1672///
1673/// Exactly one of:
1674/// - `input:`     -> immutable model (`PurePluginModel`)
1675/// - `input: mut` -> mutable model (`MutablePluginModel`)
1676///
1677/// Optionally:
1678/// - `context:` enables contextual execution (otherwise context defaults to `()`)
1679/// - `root:` + `child:` attaches the model to a plugin family for late resolution
1680///
1681/// ## Syntax
1682///
1683/// ### Immutable Model (No Context)
1684///
1685/// ```ignore
1686/// plugin_model! {
1687///     name: pub ModelName,          // Required: struct visibility and struct name of the plugin model
1688///     input: InputType,             // Required: generic immutable input type
1689///     output: OutputType,           // Optional: output type (defaults to input if omitted)
1690///     others: [T1, T2],             // Optional: additional generic parameters
1691///     bounds: [TraitBounds],        // Required: trait bounds for generics
1692///     compute: |input, ctx| { ... } // Required: compute logic (`ctx` is `()`)
1693/// }
1694/// ```
1695///
1696/// ### Immutable Model with Context
1697///
1698/// ```ignore
1699/// plugin_model! {
1700///     name: pub ModelName,          // Required: struct visibility and struct name of the plugin model
1701///     input: InputType,             // Required: generic immutable input type
1702///     output: OutputType,           // Optional: output type (defaults to input if omitted)
1703///     others: [T1, T2],             // Optional: additional generic parameters
1704///     context: ContextType,         // Required: context struct used during execution
1705///     bounds: [TraitBounds],        // Required: trait bounds for generics
1706///     compute: |input, ctx| { ... } // `ctx: &ContextType`
1707/// }
1708/// ```
1709///
1710/// ### Mutable Model
1711///
1712/// ```ignore
1713/// plugin_model! {
1714///     name: pub ModelName,          // Required: struct visibility and struct name of the plugin model
1715///     input: mut InputType,         // Required: mutable input type (`&mut InputType`)
1716///     output: OutputType,           // Optional: output type (defaults to immutable input type)
1717///     others: [T1, T2],             // Optional: additional generic parameters
1718///     context: ContextType,         // Optional: context struct (defaults to `()`)
1719///     bounds: [TraitBounds],        // Required: trait bounds for generics
1720///     compute: |input, ctx| { ... } // Uses `compute_mut`
1721/// }
1722/// ```
1723///
1724/// ## Output Type Semantics
1725///
1726/// - If `output` is omitted, the output type defaults to the **immutable input type**,
1727///   even for mutable models (it does **not** default to `()`).
1728/// - This rule applies to both immutable and mutable plugin models.
1729/// - If a unit output `()` is desired, it must be specified explicitly as:
1730///
1731/// ```ignore
1732/// output: Output,
1733/// bounds: [Output: Default]
1734/// ```
1735///
1736/// The `Default` bound is required so `compute`'s block can construct the output value.
1737///
1738/// ## Semantics
1739///
1740/// - Each model is fully generic over its input, output, and optional context.
1741/// - If `context` is omitted, the model uses `()` as its context type.
1742/// - If `root` and `child` are provided, the model becomes a member of a plugin
1743///   family and is selected indirectly using the `(root, child, context)`
1744///   resolution lattice.
1745/// - Immutable variants use `compute` with shared input references.
1746/// - Mutable variants use `compute_mut` and may mutate the input in-place.
1747///
1748/// All constraints are enforced purely through trait bounds and associated
1749/// types, guaranteeing compile-time correctness of model wiring and resolution.
1750#[macro_export]
1751macro_rules! plugin_model {
1752
1753    // Helper Rule: `@output_ty`
1754    (@output_ty $Input:tt) => { $Input };
1755    (@output_ty $Input:tt, $Output:tt) => { $Output };
1756
1757    // Variant 1: No Context, Single Input, Single Output
1758    (
1759        $(#[$name_meta:meta])*
1760        name: $vis:vis $ModelName:ident,
1761        input: $Input:ident,
1762        $(output: $Output:ident ,)?
1763        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1764        bounds: [$($bounds:tt)*],
1765        $(#[$compute_meta:meta])*
1766        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1767    ) => {
1768        #[derive(Debug, Default)]
1769        $(#[$name_meta])*
1770        $vis struct $ModelName;
1771
1772        impl<
1773            $($($other_gen ,)*)?
1774            $Input
1775            $(, $Output)?
1776        > $crate::plugins::PurePluginModel<
1777            $Input,
1778            (),
1779            $crate::plugin_model!(@output_ty $Input $(, $Output)?)
1780        > for $ModelName
1781        where
1782            $($bounds)*
1783        {
1784            $(#[$compute_meta])*
1785            fn compute(
1786                &self,
1787                $input_arg: $Input,
1788                $ctx_arg: &()
1789            ) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
1790                $body
1791            }
1792        }
1793    };
1794
1795    // Variant 2: No Context, Single Input, Tuple Output
1796    (
1797        $(#[$name_meta:meta])*
1798        name: $vis:vis $ModelName:ident,
1799        input: $Input:ident,
1800        $(output: ($($Output:ident),+) ,)?
1801        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1802        bounds: [$($bounds:tt)*],
1803        $(#[$compute_meta:meta])*
1804        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1805    ) => {
1806        #[derive(Debug, Default)]
1807        $(#[$name_meta])*
1808        $vis struct $ModelName;
1809
1810        impl<
1811            $($($other_gen ,)*)?
1812            $Input
1813            $(, $($Output),+)?
1814        > $crate::plugins::PurePluginModel<
1815            $Input,
1816            (),
1817            $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
1818        > for $ModelName
1819        where
1820            $($bounds)*
1821        {
1822            $(#[$compute_meta])*
1823            fn compute(
1824                &self,
1825                $input_arg: $Input,
1826                $ctx_arg: &()
1827            ) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
1828                $body
1829            }
1830        }
1831    };
1832
1833    // Variant 3: No Context, Tuple Input, Single Output
1834    (
1835        $(#[$name_meta:meta])*
1836        name: $vis:vis $ModelName:ident,
1837        input: ($($Input:ident),+),
1838        $(output: $Output:ident ,)?
1839        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1840        bounds: [$($bounds:tt)*],
1841        $(#[$compute_meta:meta])*
1842        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1843    ) => {
1844        #[derive(Debug, Default)]
1845        $(#[$name_meta])*
1846        $vis struct $ModelName;
1847
1848        impl<
1849            $($($other_gen ,)*)?
1850            $($Input),+
1851            $(, $Output)?
1852        > $crate::plugins::PurePluginModel<
1853            ($($Input),+),
1854            (),
1855            $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
1856        > for $ModelName
1857        where
1858            $($bounds)*
1859        {
1860            $(#[$compute_meta])*
1861            fn compute(
1862                &self,
1863                $input_arg: ($($Input),+),
1864                $ctx_arg: &()
1865            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
1866                $body
1867            }
1868        }
1869    };
1870
1871    // Variant 4: No Context, Tuple Input, Tuple Output
1872    (
1873        $(#[$name_meta:meta])*
1874        name: $vis:vis $ModelName:ident,
1875        input: ($($Input:ident),+),
1876        $(output: ($($Output:ident),+) ,)?
1877        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1878        bounds: [$($bounds:tt)*],
1879        $(#[$compute_meta:meta])*
1880        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1881    ) => {
1882        #[derive(Debug, Default)]
1883        $(#[$name_meta])*
1884        $vis struct $ModelName;
1885
1886        impl<
1887            $($($other_gen ,)*)?
1888            $($Input),+
1889            $(, $($Output),+)?
1890        > $crate::plugins::PurePluginModel<
1891            ($($Input),+),
1892            (),
1893            $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
1894        > for $ModelName
1895        where
1896            $($bounds)*
1897        {
1898            $(#[$compute_meta])*
1899            fn compute(
1900                &self,
1901                $input_arg: ($($Input),+),
1902                $ctx_arg: &()
1903            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
1904                $body
1905            }
1906        }
1907    };
1908
1909    // Variant 5: Context, Single Input, Single Output
1910    (
1911        $(#[$name_meta:meta])*
1912        name: $vis:vis $ModelName:ident,
1913        input: $Input:ident,
1914        $(output: $Output:ident ,)?
1915        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1916        context: $Context:ty,
1917        bounds: [$($bounds:tt)*],
1918        $(#[$compute_meta:meta])*
1919        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1920    ) => {
1921        #[derive(Debug, Default)]
1922        $(#[$name_meta])*
1923        $vis struct $ModelName;
1924
1925        impl<
1926            $($($other_gen ,)*)?
1927            $Input
1928            $(, $Output)?
1929        > $crate::plugins::PurePluginModel<
1930            $Input,
1931            $Context,
1932            $crate::plugin_model!(@output_ty $Input $(, $Output)?)
1933        > for $ModelName
1934        where
1935            $($bounds)*
1936        {
1937            $(#[$compute_meta])*
1938            fn compute(
1939                &self,
1940                $input_arg: $Input,
1941                $ctx_arg: &$Context
1942            ) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
1943                $body
1944            }
1945        }
1946    };
1947
1948    // Variant 6: Context, Single Input, Tuple Output
1949    (
1950        $(#[$name_meta:meta])*
1951        name: $vis:vis $ModelName:ident,
1952        input: $Input:ident,
1953        $(output: ($($Output:ident),+) ,)?
1954        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1955        context: $Context:ty,
1956        bounds: [$($bounds:tt)*],
1957        $(#[$compute_meta:meta])*
1958        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1959    ) => {
1960        #[derive(Debug, Default)]
1961        $(#[$name_meta])*
1962        $vis struct $ModelName;
1963
1964        impl<
1965            $($($other_gen ,)*)?
1966            $Input
1967            $(, $($Output),+)?
1968        > $crate::plugins::PurePluginModel<
1969            $Input,
1970            $Context,
1971            $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
1972        > for $ModelName
1973        where
1974            $($bounds)*
1975        {
1976            $(#[$compute_meta])*
1977            fn compute(
1978                &self,
1979                $input_arg: $Input,
1980                $ctx_arg: &$Context
1981            ) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
1982                $body
1983            }
1984        }
1985    };
1986
1987    // Variant 7: Context, Tuple Input, Single Output
1988    (
1989        $(#[$name_meta:meta])*
1990        name: $vis:vis $ModelName:ident,
1991        input: ($($Input:ident),+),
1992        $(output: $Output:ident ,)?
1993        $(others: [$($other_gen:tt),* $(,)? ] ,)?
1994        context: $Context:ty,
1995        bounds: [$($bounds:tt)*],
1996        $(#[$compute_meta:meta])*
1997        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
1998    ) => {
1999        #[derive(Debug, Default)]
2000        $(#[$name_meta])*
2001        $vis struct $ModelName;
2002
2003        impl<
2004            $($($other_gen ,)*)?
2005            $($Input),+
2006            $(, $Output)?
2007        > $crate::plugins::PurePluginModel<
2008            ($($Input),+),
2009            $Context,
2010            $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
2011        > for $ModelName
2012        where
2013            $($bounds)*
2014        {
2015            $(#[$compute_meta])*
2016            fn compute(
2017                &self,
2018                $input_arg: ($($Input),+),
2019                $ctx_arg: &$Context
2020            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
2021                $body
2022            }
2023        }
2024    };
2025
2026    // Variant 8: Context, Tuple Input, Tuple Output
2027    (
2028        $(#[$name_meta:meta])*
2029        name: $vis:vis $ModelName:ident,
2030        input: ($($Input:ident),+),
2031        $(output: ($($Output:ident),+) ,)?
2032        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2033        context: $Context:ty,
2034        bounds: [$($bounds:tt)*],
2035        $(#[$compute_meta:meta])*
2036        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2037    ) => {
2038        #[derive(Debug, Default)]
2039        $(#[$name_meta])*
2040        $vis struct $ModelName;
2041
2042        impl<
2043            $($($other_gen ,)*)?
2044            $($Input),+
2045            $(, $($Output),+)?
2046        > $crate::plugins::PurePluginModel<
2047            ($($Input),+),
2048            $Context,
2049            $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
2050        > for $ModelName
2051        where
2052            $($bounds)*
2053        {
2054            $(#[$compute_meta])*
2055            fn compute(
2056                &self,
2057                $input_arg: ($($Input),+),
2058                $ctx_arg: &$Context
2059            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
2060                $body
2061            }
2062        }
2063    };
2064
2065    // Variant 9: No Context, Single Input, Single Output (MUTABLE)
2066    (
2067        $(#[$name_meta:meta])*
2068        name: $vis:vis $ModelName:ident,
2069        input: mut $Input:ident,
2070        $(output: $Output:ident ,)?
2071        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2072        bounds: [$($bounds:tt)*],
2073        $(#[$compute_meta:meta])*
2074        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2075    ) => {
2076        #[derive(Debug, Default)]
2077        $(#[$name_meta])*
2078        $vis struct $ModelName;
2079
2080        impl<
2081            $($($other_gen ,)*)?
2082            $Input
2083            $(, $Output)?
2084        > $crate::plugins::MutablePluginModel<
2085            $Input,
2086            (),
2087            $crate::plugin_model!(@output_ty $Input $(, $Output)?)
2088        > for $ModelName
2089        where
2090            $($bounds)*
2091        {
2092            $(#[$compute_meta])*
2093            fn compute_mut(
2094                &self,
2095                $input_arg: &mut $Input,
2096                $ctx_arg: &()
2097            ) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
2098                $body
2099            }
2100        }
2101    };
2102
2103    // Variant 10: No Context, Single Input, Tuple Output (MUTABLE)
2104    (
2105        $(#[$name_meta:meta])*
2106        name: $vis:vis $ModelName:ident,
2107        input: mut $Input:ident,
2108        $(output: ($($Output:ident),+) ,)?
2109        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2110        bounds: [$($bounds:tt)*],
2111        $(#[$compute_meta:meta])*
2112        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2113    ) => {
2114        #[derive(Debug, Default)]
2115        $(#[$name_meta])*
2116        $vis struct $ModelName;
2117
2118        impl<
2119            $($($other_gen ,)*)?
2120            $Input
2121            $(, $($Output),+)?
2122        > $crate::plugins::MutablePluginModel<
2123            $Input,
2124            (),
2125            $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
2126        > for $ModelName
2127        where
2128            $($bounds)*
2129        {
2130            $(#[$compute_meta])*
2131            fn compute_mut(
2132                &self,
2133                $input_arg: &mut $Input,
2134                $ctx_arg: &()
2135            ) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
2136                $body
2137            }
2138        }
2139    };
2140
2141    // Variant 11: No Context, Tuple Input, Single Output (MUTABLE)
2142    (
2143        $(#[$name_meta:meta])*
2144        name: $vis:vis $ModelName:ident,
2145        input: mut ($($Input:ident),+),
2146        $(output: $Output:ident ,)?
2147        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2148        bounds: [$($bounds:tt)*],
2149        $(#[$compute_meta:meta])*
2150        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2151    ) => {
2152        #[derive(Debug, Default)]
2153        $(#[$name_meta])*
2154        $vis struct $ModelName;
2155
2156        impl<
2157            $($($other_gen ,)*)?
2158            $($Input),+
2159            $(, $Output)?
2160        > $crate::plugins::MutablePluginModel<
2161            ($($Input),+),
2162            (),
2163            $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
2164        > for $ModelName
2165        where
2166            $($bounds)*
2167        {
2168            $(#[$compute_meta])*
2169            fn compute_mut(
2170                &self,
2171                $input_arg: &mut ($($Input),+),
2172                $ctx_arg: &(),
2173            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
2174                $body
2175            }
2176        }
2177    };
2178
2179    // Variant 12: No Context, Tuple Input, Tuple Output (MUTABLE)
2180    (
2181        $(#[$name_meta:meta])*
2182        name: $vis:vis $ModelName:ident,
2183        input: mut ($($Input:ident),+),
2184        $(output: ($($Output:ident),+) ,)?
2185        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2186        bounds: [$($bounds:tt)*],
2187        $(#[$compute_meta:meta])*
2188        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2189    ) => {
2190        #[derive(Debug, Default)]
2191        $(#[$name_meta])*
2192        $vis struct $ModelName;
2193
2194        impl<
2195            $($($other_gen ,)*)?
2196            $($Input),+
2197            $(, $($Output),+)?
2198        > $crate::plugins::MutablePluginModel<
2199            ($($Input),+),
2200            (),
2201            $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
2202        > for $ModelName
2203        where
2204            $($bounds)*
2205        {
2206            $(#[$compute_meta])*
2207            fn compute_mut(
2208                &self,
2209                $input_arg: &mut ($($Input),+),
2210                $ctx_arg: &(),
2211            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
2212                $body
2213            }
2214        }
2215    };
2216
2217    // Variant 13: Context, Single Input, Single Output (MUTABLE)
2218    (
2219        $(#[$name_meta:meta])*
2220        name: $vis:vis $ModelName:ident,
2221        input: mut $Input:ident,
2222        $(output: $Output:ident ,)?
2223        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2224        context: $Context:ty,
2225        bounds: [$($bounds:tt)*],
2226        $(#[$compute_meta:meta])*
2227        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2228    ) => {
2229        #[derive(Debug, Default)]
2230        $(#[$name_meta])*
2231        $vis struct $ModelName;
2232
2233        impl<
2234            $($($other_gen ,)*)?
2235            $Input
2236            $(, $Output)?
2237        > $crate::plugins::MutablePluginModel<
2238            $Input,
2239            $Context,
2240            $crate::plugin_model!(@output_ty $Input $(, $Output)?)
2241        > for $ModelName
2242        where
2243            $($bounds)*
2244        {
2245            $(#[$compute_meta])*
2246            fn compute_mut(
2247                &self,
2248                $input_arg: &mut $Input,
2249                $ctx_arg: &$Context
2250            ) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
2251                $body
2252            }
2253        }
2254    };
2255
2256    // Variant 14: Context, Single Input, Tuple Output (MUTABLE)
2257    (
2258        $(#[$name_meta:meta])*
2259        name: $vis:vis $ModelName:ident,
2260        input: mut $Input:ident,
2261        $(output: ($($Output:ident),+) ,)?
2262        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2263        context: $Context:ty,
2264        bounds: [$($bounds:tt)*],
2265        $(#[$compute_meta:meta])*
2266        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2267    ) => {
2268        #[derive(Debug, Default)]
2269        $(#[$name_meta])*
2270        $vis struct $ModelName;
2271
2272        impl<
2273            $($($other_gen ,)*)?
2274            $Input
2275            $(, $($Output),+)?
2276        > $crate::plugins::MutablePluginModel<
2277            $Input,
2278            $Context,
2279            $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
2280        > for $ModelName
2281        where
2282            $($bounds)*
2283        {
2284            $(#[$compute_meta])*
2285            fn compute_mut(
2286                &self,
2287                $input_arg: &mut $Input,
2288                $ctx_arg: &$Context
2289            ) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
2290                $body
2291            }
2292        }
2293    };
2294
2295    // Variant 15: Context, Tuple Input, Single Output (MUTABLE)
2296    (
2297        $(#[$name_meta:meta])*
2298        name: $vis:vis $ModelName:ident,
2299        input: mut ($($Input:ident),+),
2300        $(output: $Output:ident ,)?
2301        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2302        context: $Context:ty,
2303        bounds: [$($bounds:tt)*],
2304        $(#[$compute_meta:meta])*
2305        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2306    ) => {
2307        #[derive(Debug, Default)]
2308        $(#[$name_meta])*
2309        $vis struct $ModelName;
2310
2311        impl<
2312            $($($other_gen ,)*)?
2313            $($Input),+
2314            $(, $Output)?
2315        > $crate::plugins::MutablePluginModel<
2316            ($($Input),+),
2317            $Context,
2318            $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
2319        > for $ModelName
2320        where
2321            $($bounds)*
2322        {
2323            $(#[$compute_meta])*
2324            fn compute_mut(
2325                &self,
2326                $input_arg: &mut ($($Input),+),
2327                $ctx_arg: &$Context
2328            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
2329                $body
2330            }
2331        }
2332    };
2333
2334    // Variant 16: Context, Tuple Input, Tuple Output (MUTABLE)
2335    (
2336        $(#[$name_meta:meta])*
2337        name: $vis:vis $ModelName:ident,
2338        input: mut ($($Input:ident),+),
2339        $(output: ($($Output:ident),+) ,)?
2340        $(others: [$($other_gen:tt),* $(,)? ] ,)?
2341        context: $Context:ty,
2342        bounds: [$($bounds:tt)*],
2343        $(#[$compute_meta:meta])*
2344        compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
2345    ) => {
2346        #[derive(Debug, Default)]
2347        $(#[$name_meta])*
2348        $vis struct $ModelName;
2349
2350        impl<
2351            $($($other_gen ,)*)?
2352            $($Input),+
2353            $(, $($Output),+)?
2354        > $crate::plugins::MutablePluginModel<
2355            ($($Input),+),
2356            $Context,
2357            $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
2358        > for $ModelName
2359        where
2360            $($bounds)*
2361        {
2362            $(#[$compute_meta])*
2363            fn compute_mut(
2364                &self,
2365                $input_arg: &mut ($($Input),+),
2366                $ctx_arg: &$Context
2367            ) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
2368                $body
2369            }
2370        }
2371
2372    };
2373
2374}
2375
2376// ===============================================================================
2377// ``````````````````````````````` DECLARE FAMILY ````````````````````````````````
2378// ===============================================================================
2379
2380/// Declares a plugin model family using marker types.
2381///
2382/// This macro generates a **family root trait** and one or more **child markers**
2383/// used to represent operations within that family.
2384///
2385/// The generated markers are purely type-level and contain no runtime data.
2386/// Concrete plugin implementations attach to a `(Root, Child)` pair via
2387/// [`plugin_model!`](crate::plugin_model), allowing models to be selected later through context
2388/// and trait bounds.
2389///
2390/// ## Parameters
2391/// - `root`: Declares the **family root trait**.
2392///   - Can include a visibility modifier (`pub`, `pub(crate)`, etc.).
2393///   - The same visibility is applied to all child marker structs.
2394///   - Prefix with `mut` to create a mutable plugin family.
2395/// - `child`: A list of **child marker types** representing operations
2396///   within the family.
2397///
2398/// ## Syntax
2399///
2400/// ```ignore
2401/// declare_family! {
2402///     root: pub FamilyRoot,
2403///     child: [OperationA, OperationB, OperationC]
2404/// }
2405/// ```
2406///
2407/// Mutable families use the `mut` keyword:
2408///
2409/// ```ignore
2410/// declare_family! {
2411///     root: mut pub FamilyRoot,
2412///     child: [OperationA, OperationB]
2413/// }
2414/// ```
2415///
2416/// ## Generated Types
2417///
2418/// The macro generates:
2419///
2420/// - A **child marker struct** for each entry in `child`.
2421/// - A **family root trait** defining associated plugin model types
2422///   for each child operation.
2423///
2424/// The child marker structs are zero-sized types used purely as
2425/// identifiers for operations within the family.
2426///
2427/// The root trait declares an associated model type per child:
2428///
2429/// - Immutable families require models implementing [`PurePluginModel`].
2430/// - Mutable families require models implementing [`MutablePluginModel`].
2431///
2432/// Each associated type corresponds to a concrete plugin implementation
2433/// bound to that operation.
2434///
2435/// These associated model types are later used by [`plugin_model!`](crate::plugin_model) to bind
2436/// concrete implementations to specific `(Root, Child)` combinations.
2437///
2438/// ## Example
2439///
2440/// ```ignore
2441/// declare_family! {
2442///     root: pub VotingFamily,
2443///     child: [Phragmen, STV]
2444/// }
2445/// ```
2446///
2447/// Expands roughly to:
2448///
2449/// ```ignore
2450/// pub struct Phragmen;
2451/// pub struct STV;
2452///
2453/// pub trait VotingFamily<Input, Context, Output> {
2454///     type Phragmen: PurePluginModel<Input, Context, Output>;
2455///     type STV: PurePluginModel<Input, Context, Output>;
2456/// }
2457/// ```
2458///
2459/// Mutable family example:
2460///
2461/// ```ignore
2462/// declare_family! {
2463///     root: mut pub StorageFamily,
2464///     child: [Insert, Remove]
2465/// }
2466/// ```
2467///
2468/// Expands roughly to:
2469///
2470/// ```ignore
2471/// pub struct Insert;
2472/// pub struct Remove;
2473///
2474/// pub trait StorageFamily<Input, Context, Output> {
2475///     type Insert: MutablePluginModel<Input, Context, Output>;
2476///     type Remove: MutablePluginModel<Input, Context, Output>;
2477/// }
2478/// ```
2479#[macro_export]
2480macro_rules! declare_family {
2481    // Immutable Family
2482    (
2483        $(#[$meta:meta])*
2484        root: $vis:vis $Root:ident,
2485        child: [
2486            $(
2487                $(#[$child_meta:meta])*
2488                $Child:ident
2489            ),+ $(,)?
2490        ]
2491    ) => {
2492        $(
2493            $(#[$child_meta])*
2494            $vis struct $Child;
2495        )+
2496
2497        $(#[$meta])*
2498        $vis trait $Root<Input, Context, Output>{
2499            $(
2500                $(#[$child_meta])*
2501                type $Child: $crate::plugins::PurePluginModel<Input, Context, Output>;
2502            )+
2503        }
2504
2505    };
2506
2507    // Mutable Family
2508    (
2509        $(#[$meta:meta])*
2510        root: mut $vis:vis $Root:ident,
2511        child: [
2512            $(
2513                $(#[$child_meta:meta])*
2514                $Child:ident
2515            ),+ $(,)?
2516        ]
2517    ) => {
2518        $(
2519            $(#[$child_meta])*
2520            $vis struct $Child;
2521        )+
2522
2523        $(#[$meta])*
2524        $vis trait $Root<Input, Context, Output> {
2525            $(
2526                $(#[$child_meta])*
2527                type $Child: $crate::plugins::MutablePluginModel<Input, Context, Output>;
2528            )+
2529        }
2530
2531    };
2532}
2533
2534// ===============================================================================
2535// ```````````````````````````````` DEFINE FAMILY ````````````````````````````````
2536// ===============================================================================
2537
2538/// Declares a concrete **plugin family implementation** for a given family root.
2539///
2540/// This macro generates:
2541/// 1. A **family marker struct** representing a concrete implementation of a
2542///    plugin family.
2543/// 2. An implementation of the **family root trait** mapping each declared
2544///    child operation to a concrete plugin model.
2545///
2546/// The generated family struct is purely a **type-level marker** and contains
2547/// no runtime data. It is used to bind concrete plugin models to a specific
2548/// `(FamilyType, Child)` combination through associated types.
2549///
2550/// When `borrow` are specified, the generated family marker stores them
2551/// in `PhantomData` fields so the type system correctly tracks them
2552/// without affecting runtime behavior.
2553///
2554/// ## Syntax
2555///
2556/// ### Family With Context
2557///
2558/// ```ignore
2559/// define_family! {
2560///     root: FamilyRoot,             // Required: family root trait
2561///
2562///     family: pub MyFamily,         // Required: visibility and concrete family marker struct
2563///     borrow: ['a],                 // Optional: lifetime parameters for family marker
2564///
2565///     input: Input,                 // Required: input type parameter
2566///     output: Output,               // Optional: output type (defaults to input if omitted)
2567///
2568///     context: MyContext,           // Required: context type
2569///     marker: [T],                  // Optional: generic parameters for the context
2570///
2571///     bounds: [T: Clone],           // Optional: trait bounds for the generated impl
2572///
2573///     child: [                      // Required: child -> model mapping
2574///         OperationA => ModelA,
2575///         OperationB => ModelB,
2576///     ]
2577/// }
2578/// ```
2579///
2580/// ### Family Without Context
2581///
2582/// ```ignore
2583/// define_family! {
2584///     root: FamilyRoot,           // Required: family root trait
2585///
2586///     family: pub MyFamily,       // Required: visibility and concrete family marker struct
2587///     borrow: ['a],               // Optional: lifetime parameters for family marker
2588///
2589///     input: Input,               // Required: input type parameter
2590///     output: Output,             // Optional: output type (defaults to input if omitted)
2591///
2592///     bounds: [T: Clone],         // Optional: trait bounds for the generated impl
2593///
2594///     child: [                    // Required: child -> model mapping
2595///         OperationA => ModelA,
2596///         OperationB => ModelB,
2597///     ]
2598/// }
2599/// ```
2600///
2601/// In the second form, the context parameter of the root trait defaults to `()`.
2602///
2603/// ## Lifetimes and Generics
2604///
2605/// - `borrow` apply to the **family marker type**
2606///   - used to model execution-time borrowing
2607///   - stored via `PhantomData`
2608///
2609/// ```ignore
2610/// borrow: ['a]
2611/// ```
2612///
2613/// - `marker` apply only when a `context` is specified
2614///   - used to parameterize the **context type**
2615///   - introduced on the generated `impl`, not the family struct
2616///
2617/// ```ignore
2618/// context: MyContext,
2619/// marker: [T]
2620/// ```
2621///
2622/// When no `context` is provided:
2623///
2624/// - the context defaults to `()`
2625/// - `marker` is not used
2626///
2627/// ## Example
2628///
2629/// ```ignore
2630///
2631/// // ----- Crate A ------
2632///
2633/// declare_family! {
2634///     root: pub VotingFamily,
2635///     child: [Phragmen, STV]
2636/// }
2637///
2638/// // ----- Crate B ------
2639///
2640/// plugin_model! {
2641///     name: PhragmenModel,
2642///     ...
2643/// }
2644///
2645/// plugin_model! {
2646///     name: STVModel,
2647///     ...
2648/// }
2649///
2650/// define_family! {
2651///     root: VotingFamily,
2652///
2653///     family: pub RuntimeVoting,
2654///     input: AccountId,
2655///     output: Balance,
2656///     context: RuntimeContext,
2657///
2658///     child: [
2659///         Phragmen => PhragmenModel,
2660///         STV => STVModel,
2661///     ]
2662/// }
2663/// ```
2664///
2665/// This binds the `Phragmen` and `Approval` operations of the
2666/// `VotingFamily` root to concrete plugin models for the
2667/// `RuntimeVoting` family implementation.
2668#[macro_export]
2669macro_rules! define_family {
2670
2671    // Helper Rule: `@output_ty`
2672    (@output_ty $Input:tt) => { $Input };
2673    (@output_ty $Input:tt, $Output:tt) => { $Output };
2674
2675
2676    // With Context, Single Input, Single Output
2677    (
2678        root: $Root:ident,
2679        $(#[$meta:meta])*
2680        family: $vis:vis $Name:ident,
2681        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2682        input: $Input:ident,
2683        $(output: $Output:ident ,)?
2684        context: $Context:ty,
2685        $(marker: [$($marker_gen:ident),* $(,)?],)?
2686        $(bounds: [$($bounds:tt)*],)?
2687        child: [
2688            $($child:ident => $model:ty,)+
2689        $(,)? ] $(,)?
2690    ) => {
2691
2692        $crate::__phantom_struct!(
2693            $(#[$meta])*
2694            #[allow(unused)]
2695            $vis
2696            $Name
2697            [$($($borrow_lt),*)?]
2698            []
2699        );
2700
2701        impl<
2702            $($($borrow_lt,)*)?
2703            $($($marker_gen,)*)?
2704            $Input
2705            $(, $Output)?
2706        > $Root<
2707            $Input,
2708            $Context,
2709            $crate::define_family!(@output_ty $Input $(, $Output)?)
2710        >
2711        for $Name$(<
2712            $($borrow_lt,)*
2713        >)?
2714        $(where $($bounds)*)?
2715        {
2716            $(
2717                type $child = $model;
2718            )+
2719        }
2720    };
2721
2722    // With Context, Single Input, Tuple Output
2723    (
2724        root: $Root:ident,
2725        $(#[$meta:meta])*
2726        family: $vis:vis $Name:ident,
2727        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2728        input: $Input:ident,
2729        $(output: ($($Output:ident),+) ,)?
2730        context: $Context:ty,
2731        $(marker: [$($marker_gen:ident),* $(,)?],)?
2732        $(bounds: [$($bounds:tt)*],)?
2733        child: [
2734            $($child:ident => $model:ty,)+
2735        $(,)? ] $(,)?
2736    ) => {
2737
2738        $crate::__phantom_struct!(
2739            $(#[$meta])*
2740            #[allow(unused)]
2741            $vis
2742            $Name
2743            [$($($borrow_lt),*)?]
2744            []
2745        );
2746
2747        impl<
2748            $($($borrow_lt,)*)?
2749            $($($marker_gen,)*)?
2750            $Input
2751            $(, $($Output),+)?
2752        > $Root<
2753            $Input,
2754            $Context,
2755            $crate::define_family!(@output_ty $Input $(, ($($Output),+))?)
2756        >
2757        for $Name$(<
2758            $($borrow_lt,)*
2759        >)?
2760        $(where $($bounds)*)?
2761        {
2762            $(
2763                type $child = $model;
2764            )+
2765
2766        }
2767    };
2768
2769    // With Context, Tuple Input, Single Output
2770    (
2771        root: $Root:ident,
2772        $(#[$meta:meta])*
2773        family: $vis:vis $Name:ident,
2774        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2775        input: ($($Input:ident),+),
2776        $(output: $Output:ident ,)?
2777        context: $Context:ty,
2778        $(marker: [$($marker_gen:ident),* $(,)?],)?
2779        $(bounds: [$($bounds:tt)*],)?
2780        child: [
2781            $($child:ident => $model:ty,)+
2782        $(,)? ] $(,)?
2783    ) => {
2784
2785        $crate::__phantom_struct!(
2786            $(#[$meta])*
2787            #[allow(unused)]
2788            $vis
2789            $Name
2790            [$($($borrow_lt),*)?]
2791            []
2792        );
2793
2794        impl<
2795            $($($borrow_lt,)*)?
2796            $($($marker_gen,)*)?
2797            $($Input),+
2798            $(, $Output)?
2799        > $Root<
2800            ($($Input),+),
2801            $Context,
2802            $crate::define_family!(@output_ty ($($Input),+) $(, $Output)?)
2803        >
2804        for $Name$(<
2805            $($borrow_lt,)*
2806        >)?
2807        $(where $($bounds)*)?
2808        {
2809            $(
2810                type $child = $model;
2811            )+
2812
2813        }
2814    };
2815
2816    // With Context, Tuple Input, Tuple Output
2817    (
2818        root: $Root:ident,
2819        $(#[$meta:meta])*
2820        family: $vis:vis $Name:ident,
2821        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2822        input: ($($Input:ident),+),
2823        $(output: ($($Output:ident),+) ,)?
2824        context: $Context:ty,
2825        $(marker: [$($marker_gen:ident),* $(,)?],)?
2826        $(bounds: [$($bounds:tt)*],)?
2827        child: [
2828            $($child:ident => $model:ty,)+
2829        $(,)? ] $(,)?
2830    ) => {
2831
2832        $crate::__phantom_struct!(
2833            $(#[$meta])*
2834            #[allow(unused)]
2835            $vis
2836            $Name
2837            [$($($borrow_lt),*)?]
2838            []
2839        );
2840
2841        impl<
2842            $($($borrow_lt,)*)?
2843            $($($marker_gen,)*)?
2844            $($Input),+
2845            $(, $($Output),+)?
2846        > $Root<
2847            ($($Input),+),
2848            $Context,
2849            $crate::define_family!(@output_ty ($($Input),+) $(, ($($Output),+))?)
2850        >
2851        for $Name$(<
2852            $($borrow_lt,)*
2853        >)?
2854        $(where $($bounds)*)?
2855        {
2856            $(
2857                type $child = $model;
2858            )+
2859
2860        }
2861    };
2862
2863    // No Context, Single Input, Single Output
2864    (
2865        root: $Root:ident,
2866        $(#[$meta:meta])*
2867        family: $vis:vis $Name:ident,
2868        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2869        input: $Input:ident,
2870        $(output: $Output:ident ,)?
2871        $(bounds: [$($bounds:tt)*],)?
2872        child: [
2873            $($child:ident => $model:ty,)+
2874        $(,)? ] $(,)?
2875    ) => {
2876
2877        $crate::__phantom_struct!(
2878            $(#[$meta])*
2879            #[allow(unused)]
2880            $vis
2881            $Name
2882            [$($($borrow_lt),*)?]
2883            []
2884        );
2885
2886        impl<
2887            $($($borrow_lt,)*)?
2888            $Input
2889            $(, $Output)?
2890        > $Root<
2891            $Input,
2892            (),
2893            $crate::define_family!(@output_ty $Input $(, $Output)?)
2894        >
2895        for $Name$(<
2896            $($borrow_lt,)*
2897        >)?
2898        $(where $($bounds)*)?
2899        {
2900            $(
2901                type $child = $model;
2902            )+
2903        }
2904    };
2905
2906    // No Context, Single Input, Tuple Output
2907    (
2908        root: $Root:ident,
2909        $(#[$meta:meta])*
2910        family: $vis:vis $Name:ident,
2911        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2912        input: $Input:ident,
2913        $(output: ($($Output:ident),+) ,)?
2914        $(bounds: [$($bounds:tt)*],)?
2915        child: [
2916            $($child:ident => $model:ty,)+
2917        $(,)? ] $(,)?
2918    ) => {
2919
2920        $crate::__phantom_struct!(
2921            $(#[$meta])*
2922            #[allow(unused)]
2923            $vis
2924            $Name
2925            [$($($borrow_lt),*)?]
2926            []
2927        );
2928
2929        impl<
2930            $($($borrow_lt,)*)?
2931            $Input
2932            $(, $($Output),+)?
2933        > $Root<
2934            $Input,
2935            (),
2936            $crate::define_family!(@output_ty $Input $(, ($($Output),+))?)
2937        >
2938        for $Name$(<
2939            $($borrow_lt,)*
2940        >)?
2941        $(where $($bounds)*)?
2942        {
2943            $(
2944                type $child = $model;
2945            )+
2946        }
2947    };
2948
2949    // No Context, Tuple Input, Single Output
2950    (
2951        root: $Root:ident,
2952        $(#[$meta:meta])*
2953        family: $vis:vis $Name:ident,
2954        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2955        input: ($($Input:ident),+),
2956        $(output: $Output:ident ,)?
2957        $(bounds: [$($bounds:tt)*],)?
2958        child: [
2959            $($child:ident => $model:ty,)+
2960        $(,)? ] $(,)?
2961    ) => {
2962
2963        $crate::__phantom_struct!(
2964            $(#[$meta])*
2965            #[allow(unused)]
2966            $vis
2967            $Name
2968            [$($($borrow_lt),*)?]
2969            []
2970        );
2971
2972        impl<
2973            $($($borrow_lt,)*)?
2974            $($Input),+
2975            $(, $Output)?
2976        > $Root<
2977            ($($Input),+),
2978            (),
2979            $crate::define_family!(@output_ty ($($Input),+) $(, $Output)?)
2980        >
2981        for $Name$(<
2982            $($borrow_lt,)*
2983        >)?
2984        $(where $($bounds)*)?
2985        {
2986            $(
2987                type $child = $model;
2988            )+
2989        }
2990    };
2991
2992    // No Context, Tuple Input, Tuple Output
2993    (
2994        root: $Root:ident,
2995        $(#[$meta:meta])*
2996        family: $vis:vis $Name:ident,
2997        $(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
2998        input: ($($Input:ident),+),
2999        $(output: ($($Output:ident),+) ,)?
3000        $(bounds: [$($bounds:tt)*],)?
3001        child: [
3002            $($child:ident => $model:ty,)+
3003        $(,)? ] $(,)?
3004    ) => {
3005
3006        $crate::__phantom_struct!(
3007            $(#[$meta])*
3008            #[allow(unused)]
3009            $vis
3010            $Name
3011            [$($($borrow_lt),*)?]
3012            []
3013        );
3014
3015        impl<
3016            $($($borrow_lt,)*)?
3017            $($Input),+
3018            $(, $($Output),+)?
3019        > $Root<
3020            ($($Input),+),
3021            (),
3022            $crate::define_family!(@output_ty ($($Input),+) $(, ($($Output),+))?)
3023        >
3024        for $Name$(<
3025            $($borrow_lt,)*
3026        >)?
3027        $(where $($bounds)*)?
3028        {
3029            $(
3030                type $child = $model;
3031            )+
3032        }
3033    };
3034
3035}
3036
3037// ===============================================================================
3038// ```````````````````````````````` HELPER MACROS ````````````````````````````````
3039// ===============================================================================
3040
3041/// Generates a zero-sized or PhantomData-backed marker struct.
3042///
3043/// This is an internal helper used by `plugin_context`, `define_family`,
3044/// and other macros that need to produce marker structs which may carry
3045/// lifetime or type parameters purely at the type level without any
3046/// runtime storage.
3047///
3048/// ## Syntax
3049///
3050/// ```ignore
3051/// __phantom_struct!(
3052///     #[attributes]   // optional
3053///     VISIBILITY      // pub, pub(crate), or empty
3054///     NAME            // struct identifier
3055///     [LIFETIMES]     // e.g. ['a, 'b] or []
3056///     [GENERICS]      // e.g. [T, U]   or []
3057/// )
3058/// ```
3059///
3060/// ## Variants
3061///
3062/// | Lifetimes | Generics | Generated struct                               |
3063/// |-----------|----------|------------------------------------------------|
3064/// | `[]`      | `[]`     | `struct Foo;`                                  |
3065/// | `['a]`    | `[]`     | `struct Foo<'a>(PhantomData<(&'a (),)>)`       |
3066/// | `[]`      | `[T]`    | `struct Foo<T>(PhantomData<(T,)>)`             |
3067/// | `['a]`    | `[T]`    | `struct Foo<'a, T>(PhantomData<(T, &'a ())>)`  |
3068///
3069#[macro_export]
3070macro_rules! __phantom_struct {
3071
3072    // Arm 1: No lifetimes, no generics -> plain unit struct.
3073    (
3074        $(#[$meta:meta])*
3075        $vis:vis
3076        $Name:ident
3077        []
3078        []
3079    ) => {
3080        $(#[$meta])*
3081        $vis struct $Name;
3082    };
3083
3084    // Arm 2: Lifetimes only -> struct with a PhantomData reference tuple
3085    // that is covariant over each declared lifetime independently.
3086    (
3087        $(#[$meta:meta])*
3088        $vis:vis
3089        $Name:ident
3090        [$($lt:lifetime),+ $(,)?]
3091        []
3092    ) => {
3093        $(#[$meta])*
3094        $vis struct $Name<$($lt),*>(
3095            core::marker::PhantomData<($(&$lt (),)*)>
3096        );
3097    };
3098
3099    // Arm 3: Generics only -> struct with a PhantomData tuple field that
3100    // tracks each type parameter independently.
3101    (
3102        $(#[$meta:meta])*
3103        $vis:vis
3104        $Name:ident
3105        []
3106        [$($gen:ident),+ $(,)?]
3107    ) => {
3108        $(#[$meta])*
3109        $vis struct $Name<$($gen),*>(
3110            core::marker::PhantomData<($($gen,)*)>
3111        );
3112    };
3113
3114    // Arm 4: Both lifetimes and generics -> single PhantomData tuple field
3115    // combining both, so the struct has one field instead of two and the
3116    // variance of each parameter remains independent.
3117    (
3118        $(#[$meta:meta])*
3119        $vis:vis
3120        $Name:ident
3121        [$($lt:lifetime),+ $(,)?]
3122        [$($gen:ident),+ $(,)?]
3123    ) => {
3124        $(#[$meta])*
3125        $vis struct $Name<$($lt),*, $($gen),*>(
3126            core::marker::PhantomData<($($gen,)* $(&$lt (),)*)>
3127        );
3128    };
3129}
3130
3131// ===============================================================================
3132// `````````````````````````````````` MOCK TEST ``````````````````````````````````
3133// ===============================================================================
3134
3135#[cfg(test)]
3136#[allow(unused)]
3137mod tests {
3138
3139    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3140    // ``````````````````````````````````` IMPORTS ```````````````````````````````````
3141    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3142
3143    // --- Local crate imports ---
3144    use super::*;
3145
3146    // --- Core / Std ---
3147    use core::marker::PhantomData;
3148    use std::mem::take;
3149
3150    // --- Substrate primitives ---
3151    use sp_arithmetic::traits::AtLeast8BitUnsigned;
3152
3153    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3154    // ``````````````````````````````````` STRUCTS ```````````````````````````````````
3155    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3156
3157    //--- Mock structs ---
3158
3159    #[derive(Debug, Clone, PartialEq, Eq)]
3160    pub struct BasicConfig {
3161        value: u8,
3162    }
3163
3164    #[derive(Debug, Clone, PartialEq, Eq)]
3165    pub struct GenericConfig<T> {
3166        value: T,
3167    }
3168
3169    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3170    // ``````````````````````````````` PLUGIN CONTEXT ````````````````````````````````
3171    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3172
3173    //--- Basic context form ---
3174
3175    plugin_context! {
3176        name: pub BasicConfigProvider,
3177        context: BasicConfig,
3178        value: BasicConfig {value: 10}
3179    }
3180
3181    #[test]
3182    fn plugin_context_basic_form_returns_expected_context() {
3183        let ctx = <BasicConfigProvider as ModelContext>::context();
3184        assert_eq!(ctx, BasicConfig { value: 10 });
3185    }
3186
3187    //--- Generic marker form ---
3188
3189    plugin_context! {
3190        name: GenericConfigProvider,
3191        context: GenericConfig<T>,
3192        marker: [T],
3193        bounds: [T: AtLeast8BitUnsigned + Default],
3194        value: GenericConfig {value: T::default()}
3195    }
3196
3197    #[test]
3198    fn plugin_context_marker_form_returns_expected_context() {
3199        let ctx = <GenericConfigProvider<u8> as ModelContext>::context();
3200        assert_eq!(ctx, GenericConfig { value: 0u8 });
3201    }
3202
3203    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3204    // ```````````````````````````````` PLUGIN MODEL `````````````````````````````````
3205    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3206
3207    //--- Variant 1: No Context, Single Input, Single Output ---
3208
3209    plugin_model! {
3210        name: pub PureNoCtxSingleSingle,
3211        input: Input,
3212        output: Output,
3213        bounds: [Input: Into<u8>, Output: From<u8>],
3214        compute: |input, _ctx| {
3215            let x = input.into();
3216            Output::from(x + 1)
3217        }
3218    }
3219
3220    plugin_test! {
3221        model: PureNoCtxSingleSingle,
3222        input: u8,
3223        output: u8,
3224        cases: {
3225            (pure_no_ctx_single_single_case1, 10, 11),
3226            (pure_no_ctx_single_single_case2, 0, 1),
3227        }
3228    }
3229
3230    plugin_test! {
3231        model: PureNoCtxSingleSingle,
3232        input: u8,
3233        cases: {
3234            (pure_no_ctx_single_single_case3, 99, 100),
3235            (pure_no_ctx_single_single_case4, 24, 25),
3236        }
3237    }
3238
3239    //--- Variant 2: No Context, Single Input, Tuple Output ---
3240
3241    plugin_model! {
3242        name: pub PureNoCtxSingleTuple,
3243        input: Input,
3244        output: (OutA, OutB),
3245        bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
3246        compute: |input, _ctx| {
3247            let x = input.into();
3248            (OutA::from(x), OutB::from(x + 1))
3249        }
3250    }
3251
3252    plugin_test! {
3253        model: PureNoCtxSingleTuple,
3254        input: u8,
3255        output: (u8, u8),
3256        cases: {
3257            (pure_no_ctx_single_tuple_case1, 10, (10, 11)),
3258            (pure_no_ctx_single_tuple_case2, 0, (0, 1)),
3259        }
3260    }
3261
3262    //--- Variant 3: No Context, Tuple Input, Single Output ---
3263
3264    plugin_model! {
3265        name: pub PureNoCtxTupleSingle,
3266        input: (InpA, InpB),
3267        output: Output,
3268        bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
3269        compute: |input, _ctx| {
3270            let (a, b) = input;
3271            Output::from(a.into() + b.into())
3272        }
3273    }
3274
3275    plugin_test! {
3276        model: PureNoCtxTupleSingle,
3277        input: (u8, u8),
3278        output: u8,
3279        cases: {
3280            (pure_no_ctx_tuple_single_case1, (10, 11), 21),
3281            (pure_no_ctx_tuple_single_case2, (0, 5), 5),
3282        }
3283    }
3284
3285    //--- Variant 4: No Context, Tuple Input, Tuple Output ---
3286
3287    plugin_model! {
3288        name: pub PureNoCtxTupleTuple,
3289        input: (InpA, InpB),
3290        output: (OutA, OutB),
3291        bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
3292        compute: |input, _ctx| {
3293            let (a, b) = input;
3294            (OutA::from(a.into() * 10), OutB::from(b.into() * 10))
3295        }
3296    }
3297
3298    plugin_test! {
3299        model: PureNoCtxTupleTuple,
3300        input: (u8, u8),
3301        output: (u8, u8),
3302        cases: {
3303            (pure_no_ctx_tuple_tuple_case1, (5, 10), (50, 100)),
3304            (pure_no_ctx_tuple_tuple_case2, (1, 0), (10, 0)),
3305        }
3306    }
3307
3308    // --- Variant 5: Context, Single Input, Single Output ---
3309
3310    plugin_model! {
3311        name: pub PureCtxSingleSingle,
3312        input: Input,
3313        output: Output,
3314        context: BasicConfig,
3315        bounds: [Input: Into<u8>, Output: From<u8>],
3316        compute: |input, ctx| {
3317            let v = ctx.value;
3318            Output::from(input.into() + v)
3319        }
3320    }
3321
3322    plugin_test! {
3323        model: PureCtxSingleSingle,
3324        input: u8,
3325        output: u8,
3326        context: BasicConfig,
3327        value: BasicConfig{ value: 10 },
3328        cases: {
3329            (pure_ctx_single_single_case1, 10, 20),
3330            (pure_ctx_single_single_case2, 1, 11),
3331        }
3332    }
3333
3334    plugin_test! {
3335        model: PureCtxSingleSingle,
3336        input: u8,
3337        context: BasicConfig,
3338        value: BasicConfig{ value: 10 },
3339        cases: {
3340            (pure_ctx_single_single_case3, 90, 100),
3341            (pure_ctx_single_single_case4, 0, 10),
3342        }
3343    }
3344
3345    //--- Variant 6: Context, Single Input, Tuple Output ---
3346
3347    plugin_model! {
3348        name: pub PureCtxSingleTuple,
3349        input: Input,
3350        output: (OutA, OutB),
3351        context: BasicConfig,
3352        bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
3353        compute: |input, ctx| {
3354            let x = input.into();
3355            let v = ctx.value;
3356            (OutA::from(x), OutB::from(x + v))
3357        }
3358    }
3359
3360    plugin_test! {
3361        model: PureCtxSingleTuple,
3362        input: u8,
3363        output: (u8, u8),
3364        context: BasicConfig,
3365        value: BasicConfig{ value: 1 },
3366        cases: {
3367            (pure_ctx_single_tuple_case1, 5, (5, 6)),
3368            (pure_ctx_single_tuple_case2, 1, (1, 2)),
3369        }
3370    }
3371
3372    //--- Variant 7: Context, Tuple Input, Single Output ---
3373
3374    plugin_model! {
3375        name: pub PureCtxTupleSingle,
3376        input: (InpA, InpB),
3377        output: Output,
3378        context: BasicConfig,
3379        bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
3380        compute: |input, ctx| {
3381            let (a, b) = input;
3382            let v = ctx.value;
3383            Output::from(a.into() + b.into() + v)
3384        }
3385    }
3386
3387    plugin_test! {
3388        model: PureCtxTupleSingle,
3389        input: (u8, u8),
3390        output: u8,
3391        context: BasicConfig,
3392        value: BasicConfig { value: 10},
3393        cases: {
3394            (pure_ctx_tuple_single_case1, (10, 10), 30),
3395            (pure_ctx_tuple_single_case2, (5, 30), 45),
3396        }
3397    }
3398
3399    //--- Variant 8: Context, Tuple Input, Tuple Output ---
3400
3401    plugin_model! {
3402        name: pub PureCtxTupleTuple,
3403        input: (InpA, InpB),
3404        output: (OutA, OutB),
3405        context: BasicConfig,
3406        bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
3407        compute: |input, ctx| {
3408            let (a, b) = input;
3409            let v = ctx.value;
3410            (OutA::from(a.into() + v), OutB::from(b.into() + v))
3411        }
3412    }
3413
3414    plugin_test! {
3415        model: PureCtxTupleTuple,
3416        input: (u8, u8),
3417        output: (u8, u8),
3418        context: BasicConfig,
3419        value: BasicConfig { value: 5 },
3420        cases: {
3421            (pure_ctx_tuple_tuple_case1, (5, 10), (10, 15)),
3422            (pure_ctx_tuple_tuple_case2, (1, 0), (6, 5)),
3423        }
3424    }
3425
3426    //--- Variant 9: No Context, Single Input, Single Output (MUTABLE) ---
3427
3428    plugin_model! {
3429        name: pub MutNoCtxSingleSingle,
3430        input: mut Input,
3431        output: Output,
3432        bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, Output: From<usize>],
3433        compute: |input, _ctx| {
3434            let mut v: Vec<u8> = take(input).into();
3435            v.push(1);
3436            let len = v.len();
3437            *input = Input::from(v);
3438            Output::from(len)
3439        }
3440    }
3441
3442    plugin_test! {
3443        model: MutNoCtxSingleSingle,
3444        input: mut Vec<u8>,
3445        output: usize,
3446        cases: {
3447            (mut_no_ctx_single_single_case1, vec![1, 2], 3usize, vec![1, 2, 1]),
3448            (mut_no_ctx_single_single_case2, vec![5, 4, 3, 2], 5usize, vec![5, 4, 3, 2, 1]),
3449        }
3450    }
3451
3452    //--- Variant 10: No Context, Single Input, Tuple Output (MUTABLE) ---
3453
3454    plugin_model! {
3455        name: pub MutNoCtxSingleTuple,
3456        input: mut Input,
3457        output: (OutA, OutB),
3458        bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, OutA: From<usize>, OutB: From<u8>],
3459        compute: |input, _ctx| {
3460            let mut v:  Vec<u8> = take(input).into();
3461            v.push(1);
3462            v.push(0);
3463            let len = v.len();
3464            let last = *v.last().unwrap();
3465            *input = Input::from(v);
3466            (OutA::from(len), OutB::from(last))
3467        }
3468    }
3469
3470    plugin_test! {
3471        model: MutNoCtxSingleTuple,
3472        input: mut Vec<u8>,
3473        output: (usize, u8),
3474        cases: {
3475            (mut_no_ctx_single_tuple_case1, vec![1, 0], (4usize, 0), vec![1, 0, 1, 0]),
3476            (mut_no_ctx_single_tuple_case2, vec![5, 4, 3, 2], (6usize, 0)),
3477        }
3478    }
3479
3480    //--- Variant 11: No Context, Tuple Input, Single Output (MUTABLE) ---
3481
3482    plugin_model! {
3483        name: pub MutNoCtxTupleSingle,
3484        input: mut (InpA, InpB),
3485        output: Output,
3486        bounds: [InpA: From<u8> + Into<u8> + Copy, InpB: From<u8> + Into<u8> + Copy, Output: From<u8>],
3487        compute: |input, _ctx| {
3488            input.0 = InpA::from(input.0.into() + 1);
3489            input.1 = InpB::from(input.1.into() + 1);
3490            Output::from(input.0.into() + input.1.into())
3491        }
3492    }
3493
3494    plugin_test! {
3495        model: MutNoCtxTupleSingle,
3496        input: mut (u8, u8),
3497        output: u8,
3498        cases: {
3499            (mut_no_ctx_tuple_single_case1, (11, 12), 25, (12, 13)),
3500            (mut_no_ctx_tuple_single_case2, (0, 0), 2, (1, 1)),
3501
3502        }
3503    }
3504
3505    //--- Variant 12: No Context, Tuple Input, Tuple Output (MUTABLE) ---
3506
3507    plugin_model! {
3508        name: pub MutNoCtxTupleTuple,
3509        input: mut (A, B),
3510        output: (OutA, OutB),
3511        bounds: [A: From<u8> + Into<u8> + Copy, B: From<u8> + Into<u8> + Copy, OutA: From<u8>, OutB: From<u8>],
3512        compute: |input, _ctx| {
3513            input.0 = A::from(input.0.into() * 10);
3514            input.1 = B::from(input.1.into() * 0);
3515            (OutA::from(input.0.into()), OutB::from(input.1.into()))
3516        }
3517    }
3518
3519    plugin_test! {
3520        model: MutNoCtxTupleTuple,
3521        input: mut (u8, u8),
3522        output: (u8, u8),
3523        cases: {
3524            (mut_no_ctx_tuple_tuple_case1, (10, 10), (100, 0), (100, 0)),
3525            (mut_no_ctx_tuple_tuple_case2, (20, 35), (200, 0)),
3526        }
3527    }
3528
3529    plugin_test! {
3530        model: MutNoCtxTupleTuple,
3531        input: mut (u8, u8),
3532        cases: {
3533            (mut_no_ctx_tuple_tuple_case3, (1, 10), (10, 0), (10, 0)),
3534            (mut_no_ctx_tuple_tuple_case4, (0, 0), (0, 0)),
3535        }
3536    }
3537
3538    //--- Variant 13: Context, Single Input, Single Output (MUTABLE) ---
3539
3540    plugin_model! {
3541        name: pub MutCtxSingleSingle,
3542        input: mut Input,
3543        output: Output,
3544        context: BasicConfig,
3545        bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, Output: From<usize>],
3546        compute: |input, ctx| {
3547            let mut v: Vec<u8> = take(input).into();
3548            v.push(ctx.value);
3549            let len = v.len();
3550            *input = Input::from(v);
3551            Output::from(len)
3552        }
3553    }
3554
3555    plugin_test! {
3556        model: MutCtxSingleSingle,
3557        input: mut Vec<u8>,
3558        output: usize,
3559        context: BasicConfig,
3560        value: BasicConfig { value: 0 },
3561        cases: {
3562            (mut_ctx_single_single_case1, vec![1], 2usize, vec![1, 0]),
3563            (mut_ctx_single_single_case2, vec![1, 5, 3], 4usize, vec![1, 5, 3, 0]),
3564
3565        }
3566    }
3567
3568    //--- Variant 14: Context, Single Input, Tuple Output (MUTABLE) --
3569
3570    plugin_model! {
3571        name: pub MutCtxSingleTuple,
3572        input: mut Input,
3573        output: (OutA, OutB),
3574        context: BasicConfig,
3575        bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, OutA: From<usize>, OutB: From<u8>],
3576        compute: |input, ctx| {
3577            let mut v: Vec<u8> = take(input).into();
3578            v.push(ctx.value);
3579            let len = v.len();
3580            let last = *v.last().unwrap();
3581            *input = Input::from(v);
3582            (OutA::from(len), OutB::from(last))
3583        }
3584    }
3585
3586    plugin_test! {
3587        model: MutCtxSingleTuple,
3588        input: mut Vec<u8>,
3589        output: (usize, u8),
3590        context: BasicConfig,
3591        value: BasicConfig{value: 4},
3592        cases: {
3593            (mut_ctx_single_tuple_case1, vec![2, 3], (3usize, 4), vec![2, 3, 4]),
3594            (mut_ctx_single_tuple_case2, vec![20, 16, 12, 8], (5usize, 4), vec![20, 16, 12, 8, 4]),
3595        }
3596    }
3597
3598    //--- Variant 15: Context, Tuple Input, Single Output (MUTABLE) ---
3599
3600    plugin_model! {
3601        name: pub MutCtxTupleSingle,
3602        input: mut (InpA, InpB),
3603        output: Output,
3604        context: BasicConfig,
3605        bounds: [InpA: From<u8> + Into<u8> + Copy, InpB: From<u8> + Into<u8> + Copy, Output: From<u8>],
3606        compute: |input, ctx| {
3607            input.0 = InpA::from(input.0.into() + ctx.value);
3608            input.1 = InpB::from(input.1.into() + ctx.value);
3609            Output::from(input.0.into() + input.1.into())
3610        }
3611    }
3612
3613    plugin_test! {
3614        model: MutCtxTupleSingle,
3615        input: mut (u8, u8),
3616        output: u8,
3617        context: BasicConfig,
3618        value: BasicConfig{value: 2},
3619        cases: {
3620            (mut_ctx_tuple_single_case1, (1, 2), 7, (3, 4)),
3621            (mut_ctx_tuple_single_case2, (8, 8), 20, (10, 10)),
3622        }
3623    }
3624
3625    //--- Variant 16: Context, Tuple Input, Tuple Output (MUTABLE) ---
3626
3627    plugin_model! {
3628        name: pub MutCtxTupleTuple,
3629        input: mut (A, B),
3630        output: (OutA, OutB),
3631        context: BasicConfig,
3632        bounds: [A: From<u8> + Into<u8> + Copy, B: From<u8> + Into<u8> + Copy, OutA: From<u8>, OutB: From<u8>],
3633        compute: |input, ctx| {
3634            input.0 = A::from(input.0.into() + ctx.value);
3635            input.1 = B::from(input.1.into() + ctx.value + 1);
3636            (OutA::from(input.0.into()), OutB::from(input.1.into()))
3637        }
3638    }
3639
3640    plugin_test! {
3641        model: MutCtxTupleTuple,
3642        input: mut (u8, u8),
3643        output: (u8, u8),
3644        context: BasicConfig,
3645        value: BasicConfig{value: 2},
3646        cases: {
3647            (mut_ctx_tuple_tuple_case1, (5, 6), (7, 9), (7, 9)),
3648            (mut_ctx_tuple_tuple_case2, (0, 0), (2, 3), (2, 3)),
3649        }
3650    }
3651
3652    plugin_test! {
3653        model: MutCtxTupleTuple,
3654        input: mut (u8, u8),
3655        context: BasicConfig,
3656        value: BasicConfig{value: 2},
3657        cases: {
3658            (mut_ctx_tuple_tuple_case3, (8, 7), (10, 10), (10, 10)),
3659            (mut_ctx_tuple_tuple_case4, (1, 1), (3, 4), (3, 4)),
3660        }
3661    }
3662
3663    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3664    // ````````````````````````````````` PLUGIN TYPES ````````````````````````````````
3665    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3666
3667    plugin_context! {
3668        name: UnitContextProvider,
3669        context: (),
3670        value: ()
3671    }
3672
3673    //--- Variant 1: Immutable concrete model arm ---
3674
3675    trait ImmutablePluginTrait {
3676        plugin_types! {
3677            input: u8,
3678            output: u8,
3679            model: Model,
3680            context: Context,
3681        }
3682    }
3683
3684    struct ImmutableHost;
3685
3686    impl ImmutablePluginTrait for ImmutableHost {
3687        type Model = PureNoCtxSingleSingle;
3688        type Context = UnitContextProvider;
3689    }
3690
3691    fn run_immutable_plugin<T: ImmutablePluginTrait>(input: u8) -> u8 {
3692        let model = T::Model::default();
3693        let ctx = <T::Context as ModelContext>::context();
3694
3695        <T::Model as PurePluginModel<u8, <T::Context as ModelContext>::Context, u8>>::compute(
3696            &model, input, &ctx,
3697        )
3698    }
3699
3700    #[test]
3701    fn plugin_types_immutable_model_arm_works() {
3702        assert_eq!(run_immutable_plugin::<ImmutableHost>(10), 11);
3703        assert_eq!(run_immutable_plugin::<ImmutableHost>(0), 1);
3704    }
3705
3706    //--- Variant 2: Mutable concrete model arm ---
3707
3708    trait MutablePluginTrait {
3709        plugin_types! {
3710            input: mut Vec<u8>,
3711            output: usize,
3712            model: Model,
3713            context: Context,
3714        }
3715    }
3716
3717    struct MutableHost;
3718
3719    impl MutablePluginTrait for MutableHost {
3720        type Model = MutNoCtxSingleSingle;
3721        type Context = UnitContextProvider;
3722    }
3723
3724    fn run_mutable_plugin<T: MutablePluginTrait>(mut input: Vec<u8>) -> (Vec<u8>, usize) {
3725        let model = T::Model::default();
3726        let ctx = <T::Context as ModelContext>::context();
3727
3728        let out = <T::Model as MutablePluginModel<
3729            Vec<u8>,
3730            <T::Context as ModelContext>::Context,
3731            usize,
3732        >>::compute_mut(&model, &mut input, &ctx);
3733
3734        (input, out)
3735    }
3736
3737    #[test]
3738    fn plugin_types_mutable_model_arm_works() {
3739        let (input, out) = run_mutable_plugin::<MutableHost>(vec![1, 2]);
3740        assert_eq!(input, vec![1, 2, 1]);
3741        assert_eq!(out, 3);
3742
3743        let (input, out) = run_mutable_plugin::<MutableHost>(vec![5, 4, 3, 2]);
3744        assert_eq!(input, vec![5, 4, 3, 2, 1]);
3745        assert_eq!(out, 5);
3746    }
3747
3748    //--- Variant 3: Family arm ---
3749
3750    trait SimpleFamilyRoot<Input, Context, Output> {
3751        type Op: PurePluginModel<Input, Context, Output> + Default;
3752    }
3753
3754    struct SimpleFamily;
3755
3756    impl SimpleFamilyRoot<u8, (), u8> for SimpleFamily {
3757        type Op = PureNoCtxSingleSingle;
3758    }
3759
3760    trait FamilyPluginTrait {
3761        plugin_types! {
3762            input: u8,
3763            output: u8,
3764            root: SimpleFamilyRoot,
3765            family: Family,
3766            context: Context,
3767        }
3768    }
3769
3770    struct FamilyHost;
3771
3772    impl FamilyPluginTrait for FamilyHost {
3773        type Family = SimpleFamily;
3774        type Context = UnitContextProvider;
3775    }
3776
3777    fn run_family_plugin<T: FamilyPluginTrait>(input: u8) -> u8 {
3778        let model = <T::Family as SimpleFamilyRoot<
3779            u8,
3780            <T::Context as ModelContext>::Context,
3781            u8,
3782        >>::Op::default();
3783
3784        let ctx = <T::Context as ModelContext>::context();
3785
3786        <<T::Family as SimpleFamilyRoot<
3787            u8,
3788            <T::Context as ModelContext>::Context,
3789            u8
3790        >>::Op as PurePluginModel<
3791            u8,
3792            <T::Context as ModelContext>::Context,
3793            u8
3794        >>::compute(&model, input, &ctx)
3795    }
3796
3797    #[test]
3798    fn plugin_types_family_arm_works() {
3799        assert_eq!(run_family_plugin::<FamilyHost>(10), 11);
3800        assert_eq!(run_family_plugin::<FamilyHost>(0), 1);
3801    }
3802
3803    //--- Varaint 4: Family arm with `provides` ---
3804
3805    trait ProvidedFamilyRoot<Input, Context, Output> {
3806        type Op: PurePluginModel<Input, Context, Output> + Default;
3807    }
3808
3809    struct ProvidedFamily;
3810
3811    impl ProvidedFamilyRoot<u8, BasicConfig, u8> for ProvidedFamily {
3812        type Op = PureCtxSingleSingle;
3813    }
3814
3815    trait ProvidedFamilyPluginTrait {
3816        plugin_types! {
3817            input: u8,
3818            output: u8,
3819            root: ProvidedFamilyRoot,
3820            family: Family,
3821            context: Context,
3822            provides: [Send + Sync + 'static],
3823        }
3824    }
3825
3826    struct ThreadSafeConfigProvider;
3827
3828    impl ModelContext for ThreadSafeConfigProvider {
3829        type Context = BasicConfig;
3830
3831        fn context() -> Self::Context {
3832            BasicConfig { value: 10 }
3833        }
3834    }
3835
3836    struct ProvidedFamilyHost;
3837
3838    impl ProvidedFamilyPluginTrait for ProvidedFamilyHost {
3839        type Family = ProvidedFamily;
3840        type Context = ThreadSafeConfigProvider;
3841    }
3842
3843    fn run_family_with_provides<T: ProvidedFamilyPluginTrait>(input: u8) -> u8 {
3844        let model = <T::Family as ProvidedFamilyRoot<
3845            u8,
3846            <T::Context as ModelContext>::Context,
3847            u8,
3848        >>::Op::default();
3849
3850        let ctx = <T::Context as ModelContext>::context();
3851
3852        <<T::Family as ProvidedFamilyRoot<
3853            u8,
3854            <T::Context as ModelContext>::Context,
3855            u8
3856        >>::Op as PurePluginModel<
3857            u8,
3858            <T::Context as ModelContext>::Context,
3859            u8
3860        >>::compute(&model, input, &ctx)
3861    }
3862
3863    #[test]
3864    fn plugin_types_family_arm_with_provides_works() {
3865        assert_eq!(run_family_with_provides::<ProvidedFamilyHost>(10), 20);
3866        assert_eq!(run_family_with_provides::<ProvidedFamilyHost>(1), 11);
3867    }
3868
3869    //--- Variant 5: Family arm with `borrow`
3870
3871    #[derive(Default)]
3872    struct BorrowIdentityModel;
3873
3874    impl<'a> PurePluginModel<&'a [u8], (), &'a [u8]> for BorrowIdentityModel {
3875        fn compute(&self, input: &'a [u8], _context: &()) -> &'a [u8] {
3876            input
3877        }
3878    }
3879
3880    trait BorrowFamilyRoot<Input, Context, Output> {
3881        type Op: PurePluginModel<Input, Context, Output> + Default;
3882    }
3883
3884    struct BorrowFamily<'a>(PhantomData<&'a ()>);
3885
3886    impl<'a> BorrowFamilyRoot<&'a [u8], (), &'a [u8]> for BorrowFamily<'a> {
3887        type Op = BorrowIdentityModel;
3888    }
3889
3890    trait BorrowedFamilyPluginTrait {
3891        plugin_types! {
3892            input: &'a [u8],
3893            output: &'a [u8],
3894            borrow: ['a],
3895            root: BorrowFamilyRoot,
3896            family: Family,
3897            context: Context,
3898        }
3899    }
3900
3901    struct BorrowedFamilyHost;
3902
3903    impl BorrowedFamilyPluginTrait for BorrowedFamilyHost {
3904        type Family<'a> = BorrowFamily<'a>;
3905        type Context = UnitContextProvider;
3906    }
3907
3908    fn run_borrowed_family_plugin<'a, T: BorrowedFamilyPluginTrait>(input: &'a [u8]) -> &'a [u8] {
3909        let model = <T::Family<'a> as BorrowFamilyRoot<
3910            &'a [u8],
3911            <T::Context as ModelContext>::Context,
3912            &'a [u8],
3913        >>::Op::default();
3914
3915        let ctx = <T::Context as ModelContext>::context();
3916
3917        <<T::Family<'a> as BorrowFamilyRoot<
3918            &'a [u8],
3919            <T::Context as ModelContext>::Context,
3920            &'a [u8]
3921        >>::Op as PurePluginModel<
3922            &'a [u8],
3923            <T::Context as ModelContext>::Context,
3924            &'a [u8]
3925        >>::compute(&model, input, &ctx)
3926    }
3927
3928    #[test]
3929    fn plugin_types_family_arm_with_borrow_works() {
3930        let data = [1u8, 2, 3];
3931        assert_eq!(
3932            run_borrowed_family_plugin::<BorrowedFamilyHost>(&data),
3933            &data
3934        );
3935    }
3936
3937    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3938    // ```````````````````````````````` PLUGIN OUTPUT ````````````````````````````````
3939    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3940
3941    // Variant 1: Immutable concrete model arm
3942
3943    struct OutputPureModelRunner;
3944
3945    impl OutputPureModelRunner {
3946        plugin_output! {
3947            pub fn run_pure_model,
3948            input: u8,
3949            output: u8,
3950            model: PureCtxSingleSingle,
3951            context: BasicConfigProvider,
3952        }
3953    }
3954
3955    #[test]
3956    fn plugin_output_immutable_model_arm_works() {
3957        assert_eq!(OutputPureModelRunner::run_pure_model(10), 20);
3958        assert_eq!(OutputPureModelRunner::run_pure_model(0), 10);
3959    }
3960
3961    // Variant 2: concrete model arm
3962
3963    struct OutputMutableModelRunner;
3964
3965    impl OutputMutableModelRunner {
3966        plugin_output! {
3967            pub fn run_mutable_model,
3968            input: mut Vec<u8>,
3969            output: usize,
3970            model: MutNoCtxSingleSingle,
3971            context: UnitContextProvider,
3972        }
3973    }
3974
3975    #[test]
3976    fn plugin_output_mutable_model_arm_works() {
3977        let mut input = vec![1, 2];
3978        let out = OutputMutableModelRunner::run_mutable_model(&mut input);
3979
3980        assert_eq!(out, 3);
3981        assert_eq!(input, vec![1, 2, 1]);
3982
3983        let mut input = vec![5, 4, 3, 2];
3984        let out = OutputMutableModelRunner::run_mutable_model(&mut input);
3985
3986        assert_eq!(out, 5);
3987        assert_eq!(input, vec![5, 4, 3, 2, 1]);
3988    }
3989
3990    // Variant 3: Immutable family-selected model arm
3991
3992    declare_family! {
3993        root: pub OutputFamilyRoot,
3994        child: [Run]
3995    }
3996
3997    define_family! {
3998        root: OutputFamilyRoot,
3999        family: OutputFamily,
4000        input: Input,
4001        output: Output,
4002        context: (),
4003        bounds: [
4004            Input: Into<u8>,
4005            Output: From<u8>,
4006        ],
4007        child: [
4008            Run => PureNoCtxSingleSingle,
4009        ],
4010    }
4011
4012    struct OutputFamilyRunner;
4013
4014    impl OutputFamilyRunner {
4015        plugin_output! {
4016            pub fn run_family_model,
4017            input: u8,
4018            output: u8,
4019            root: OutputFamilyRoot,
4020            family: OutputFamily,
4021            child: Run,
4022            context: UnitContextProvider,
4023        }
4024    }
4025
4026    #[test]
4027    fn plugin_output_immutable_family_arm_works() {
4028        assert_eq!(OutputFamilyRunner::run_family_model(10), 11);
4029        assert_eq!(OutputFamilyRunner::run_family_model(0), 1);
4030    }
4031
4032    // Variant 4: Mutable family-selected model arm
4033
4034    declare_family! {
4035        root: mut pub OutputMutFamilyRoot,
4036        child: [RunMut]
4037    }
4038
4039    define_family! {
4040        root: OutputMutFamilyRoot,
4041        family: OutputMutFamily,
4042        input: Input,
4043        output: Output,
4044        context: (),
4045        bounds: [
4046            Input: From<Vec<u8>> + Into<Vec<u8>> + Default,
4047            Output: From<usize>,
4048        ],
4049        child: [
4050            RunMut => MutNoCtxSingleSingle,
4051        ],
4052    }
4053
4054    struct OutputMutFamilyRunner;
4055
4056    impl OutputMutFamilyRunner {
4057        plugin_output! {
4058            pub fn run_mut_family_model,
4059            input: mut Vec<u8>,
4060            output: usize,
4061            root: OutputMutFamilyRoot,
4062            family: OutputMutFamily,
4063            child: RunMut,
4064            context: UnitContextProvider,
4065        }
4066    }
4067
4068    #[test]
4069    fn plugin_output_mutable_family_arm_works() {
4070        let mut input = vec![1, 2];
4071        let out = OutputMutFamilyRunner::run_mut_family_model(&mut input);
4072
4073        assert_eq!(out, 3);
4074        assert_eq!(input, vec![1, 2, 1]);
4075
4076        let mut input = vec![9];
4077        let out = OutputMutFamilyRunner::run_mut_family_model(&mut input);
4078
4079        assert_eq!(out, 2);
4080        assert_eq!(input, vec![9, 1]);
4081    }
4082
4083    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4084    // ``````````````````````````````` DECLARE FAMILY ````````````````````````````````
4085    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4086
4087    //--- Variant 1: Immutable Family ---
4088
4089    declare_family! {
4090        root: pub ImmutableDeclaredRoot,
4091        child: [DeclaredRun, DeclaredEcho]
4092    }
4093
4094    struct ImmutableDeclaredFamily;
4095
4096    impl ImmutableDeclaredRoot<u8, (), u8> for ImmutableDeclaredFamily {
4097        type DeclaredRun = PureNoCtxSingleSingle;
4098        type DeclaredEcho = PureNoCtxSingleSingle;
4099    }
4100
4101    fn run_declared_immutable_family(input: u8) -> u8 {
4102        let model =
4103            <ImmutableDeclaredFamily as ImmutableDeclaredRoot<u8, (), u8>>::DeclaredRun::default();
4104        let context = ();
4105
4106        <<ImmutableDeclaredFamily as ImmutableDeclaredRoot<u8, (), u8>>::DeclaredRun
4107            as PurePluginModel<u8, (), u8>>::compute(&model, input, &context)
4108    }
4109
4110    #[test]
4111    fn declare_family_immutable_arm_creates_root_and_children() {
4112        assert_eq!(run_declared_immutable_family(10), 11);
4113        assert_eq!(run_declared_immutable_family(0), 1);
4114    }
4115
4116    #[test]
4117    fn declare_family_immutable_arm_child_markers_exist() {
4118        let _run = DeclaredRun;
4119        let _echo = DeclaredEcho;
4120    }
4121
4122    //--- Variant 2: Mutable Family ---
4123
4124    declare_family! {
4125        root: mut pub MutableDeclaredRoot,
4126        child: [DeclaredRunMut, DeclaredNormalize]
4127    }
4128
4129    struct MutableDeclaredFamily;
4130
4131    impl MutableDeclaredRoot<Vec<u8>, (), usize> for MutableDeclaredFamily {
4132        type DeclaredRunMut = MutNoCtxSingleSingle;
4133        type DeclaredNormalize = MutNoCtxSingleSingle;
4134    }
4135
4136    fn run_declared_mutable_family(mut input: Vec<u8>) -> (Vec<u8>, usize) {
4137        let model =
4138            <MutableDeclaredFamily as MutableDeclaredRoot<Vec<u8>, (), usize>>::DeclaredRunMut::default();
4139        let context = ();
4140
4141        let out =
4142            <<MutableDeclaredFamily as MutableDeclaredRoot<Vec<u8>, (), usize>>::DeclaredRunMut
4143                as MutablePluginModel<Vec<u8>, (), usize>>::compute_mut(
4144                    &model,
4145                    &mut input,
4146                    &context,
4147                );
4148
4149        (input, out)
4150    }
4151
4152    #[test]
4153    fn declare_family_mutable_arm_creates_root_and_children() {
4154        let (input, out) = run_declared_mutable_family(vec![1, 2]);
4155        assert_eq!(input, vec![1, 2, 1]);
4156        assert_eq!(out, 3);
4157    }
4158
4159    #[test]
4160    fn declare_family_mutable_arm_child_markers_exist() {
4161        let _run = DeclaredRunMut;
4162        let _normalize = DeclaredNormalize;
4163    }
4164
4165    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4166    // ```````````````````````````````` DEFINE FAMILY ````````````````````````````````
4167    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4168
4169    //--- With Context, Single Input, Single Output ---
4170
4171    declare_family! {
4172        root: pub DefFamCtxSingleSingleRoot,
4173        child: [DefFamCtxSingleSingleChild]
4174    }
4175
4176    define_family! {
4177        root: DefFamCtxSingleSingleRoot,
4178        family: DefFamCtxSingleSingleFamily,
4179        input: Input,
4180        output: Output,
4181        context: BasicConfig,
4182        bounds: [Input: Into<u8>, Output: From<u8>],
4183        child: [
4184            DefFamCtxSingleSingleChild => PureCtxSingleSingle,
4185        ],
4186    }
4187
4188    fn run_define_family_ctx_single_single(input: u8) -> u8 {
4189        let model = <DefFamCtxSingleSingleFamily as DefFamCtxSingleSingleRoot<
4190            u8,
4191            BasicConfig,
4192            u8,
4193        >>::DefFamCtxSingleSingleChild::default();
4194
4195        let ctx = BasicConfig { value: 10 };
4196
4197        <<DefFamCtxSingleSingleFamily as DefFamCtxSingleSingleRoot<u8, BasicConfig, u8>>
4198            ::DefFamCtxSingleSingleChild as PurePluginModel<u8, BasicConfig, u8>>
4199            ::compute(&model, input, &ctx)
4200    }
4201
4202    #[test]
4203    fn define_family_with_context_single_input_single_output_works() {
4204        assert_eq!(run_define_family_ctx_single_single(10), 20);
4205        assert_eq!(run_define_family_ctx_single_single(1), 11);
4206    }
4207
4208    //--- With Context, Single Input, Tuple Output ---
4209
4210    declare_family! {
4211        root: pub DefFamCtxSingleTupleRoot,
4212        child: [DefFamCtxSingleTupleChild]
4213    }
4214
4215    define_family! {
4216        root: DefFamCtxSingleTupleRoot,
4217        family: DefFamCtxSingleTupleFamily,
4218        input: Input,
4219        output: (OutA, OutB),
4220        context: BasicConfig,
4221        bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
4222        child: [
4223            DefFamCtxSingleTupleChild => PureCtxSingleTuple,
4224        ],
4225    }
4226
4227    fn run_define_family_ctx_single_tuple(input: u8) -> (u8, u8) {
4228        let model = <DefFamCtxSingleTupleFamily as DefFamCtxSingleTupleRoot<
4229            u8,
4230            BasicConfig,
4231            (u8, u8),
4232        >>::DefFamCtxSingleTupleChild::default();
4233
4234        let ctx = BasicConfig { value: 1 };
4235
4236        <<DefFamCtxSingleTupleFamily as DefFamCtxSingleTupleRoot<u8, BasicConfig, (u8, u8)>>
4237            ::DefFamCtxSingleTupleChild as PurePluginModel<u8, BasicConfig, (u8, u8)>>
4238            ::compute(&model, input, &ctx)
4239    }
4240
4241    #[test]
4242    fn define_family_with_context_single_input_tuple_output_works() {
4243        assert_eq!(run_define_family_ctx_single_tuple(5), (5, 6));
4244        assert_eq!(run_define_family_ctx_single_tuple(1), (1, 2));
4245    }
4246
4247    // With Context, Tuple Input, Single Output
4248
4249    declare_family! {
4250        root: pub DefFamCtxTupleSingleRoot,
4251        child: [DefFamCtxTupleSingleChild]
4252    }
4253
4254    define_family! {
4255        root: DefFamCtxTupleSingleRoot,
4256        family: DefFamCtxTupleSingleFamily,
4257        input: (InpA, InpB),
4258        output: Output,
4259        context: BasicConfig,
4260        bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
4261        child: [
4262            DefFamCtxTupleSingleChild => PureCtxTupleSingle,
4263        ],
4264    }
4265
4266    fn run_define_family_ctx_tuple_single(input: (u8, u8)) -> u8 {
4267        let model = <DefFamCtxTupleSingleFamily as DefFamCtxTupleSingleRoot<
4268            (u8, u8),
4269            BasicConfig,
4270            u8,
4271        >>::DefFamCtxTupleSingleChild::default();
4272
4273        let ctx = BasicConfig { value: 10 };
4274
4275        <<DefFamCtxTupleSingleFamily as DefFamCtxTupleSingleRoot<(u8, u8), BasicConfig, u8>>
4276            ::DefFamCtxTupleSingleChild as PurePluginModel<(u8, u8), BasicConfig, u8>>
4277            ::compute(&model, input, &ctx)
4278    }
4279
4280    #[test]
4281    fn define_family_with_context_tuple_input_single_output_works() {
4282        assert_eq!(run_define_family_ctx_tuple_single((10, 10)), 30);
4283        assert_eq!(run_define_family_ctx_tuple_single((5, 30)), 45);
4284    }
4285
4286    //--- With Context, Tuple Input, Tuple Output ---
4287
4288    declare_family! {
4289        root: pub DefFamCtxTupleTupleRoot,
4290        child: [DefFamCtxTupleTupleChild]
4291    }
4292
4293    define_family! {
4294        root: DefFamCtxTupleTupleRoot,
4295        family: DefFamCtxTupleTupleFamily,
4296        input: (InpA, InpB),
4297        output: (OutA, OutB),
4298        context: BasicConfig,
4299        bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
4300        child: [
4301            DefFamCtxTupleTupleChild => PureCtxTupleTuple,
4302        ],
4303    }
4304
4305    fn run_define_family_ctx_tuple_tuple(input: (u8, u8)) -> (u8, u8) {
4306        let model = <DefFamCtxTupleTupleFamily as DefFamCtxTupleTupleRoot<
4307            (u8, u8),
4308            BasicConfig,
4309            (u8, u8),
4310        >>::DefFamCtxTupleTupleChild::default();
4311
4312        let ctx = BasicConfig { value: 5 };
4313
4314        <<DefFamCtxTupleTupleFamily as DefFamCtxTupleTupleRoot<(u8, u8), BasicConfig, (u8, u8)>>
4315            ::DefFamCtxTupleTupleChild as PurePluginModel<(u8, u8), BasicConfig, (u8, u8)>>
4316            ::compute(&model, input, &ctx)
4317    }
4318
4319    #[test]
4320    fn define_family_with_context_tuple_input_tuple_output_works() {
4321        assert_eq!(run_define_family_ctx_tuple_tuple((5, 10)), (10, 15));
4322        assert_eq!(run_define_family_ctx_tuple_tuple((1, 0)), (6, 5));
4323    }
4324
4325    //--- No Context, Single Input, Single Output ---
4326
4327    declare_family! {
4328        root: pub DefFamNoCtxSingleSingleRoot,
4329        child: [DefFamNoCtxSingleSingleChild]
4330    }
4331
4332    define_family! {
4333        root: DefFamNoCtxSingleSingleRoot,
4334        family: DefFamNoCtxSingleSingleFamily,
4335        input: Input,
4336        output: Output,
4337        bounds: [Input: Into<u8>, Output: From<u8>],
4338        child: [
4339            DefFamNoCtxSingleSingleChild => PureNoCtxSingleSingle,
4340        ],
4341    }
4342
4343    fn run_define_family_no_ctx_single_single(input: u8) -> u8 {
4344        let model =
4345            <DefFamNoCtxSingleSingleFamily as DefFamNoCtxSingleSingleRoot<u8, (), u8>>
4346                ::DefFamNoCtxSingleSingleChild::default();
4347
4348        let ctx = ();
4349
4350        <<DefFamNoCtxSingleSingleFamily as DefFamNoCtxSingleSingleRoot<u8, (), u8>>
4351            ::DefFamNoCtxSingleSingleChild as PurePluginModel<u8, (), u8>>
4352            ::compute(&model, input, &ctx)
4353    }
4354
4355    #[test]
4356    fn define_family_no_context_single_input_single_output_works() {
4357        assert_eq!(run_define_family_no_ctx_single_single(10), 11);
4358        assert_eq!(run_define_family_no_ctx_single_single(0), 1);
4359    }
4360
4361    //--- No Context, Single Input, Tuple Output ---
4362
4363    declare_family! {
4364        root: pub DefFamNoCtxSingleTupleRoot,
4365        child: [DefFamNoCtxSingleTupleChild]
4366    }
4367
4368    define_family! {
4369        root: DefFamNoCtxSingleTupleRoot,
4370        family: DefFamNoCtxSingleTupleFamily,
4371        input: Input,
4372        output: (OutA, OutB),
4373        bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
4374        child: [
4375            DefFamNoCtxSingleTupleChild => PureNoCtxSingleTuple,
4376        ],
4377    }
4378
4379    fn run_define_family_no_ctx_single_tuple(input: u8) -> (u8, u8) {
4380        let model = <DefFamNoCtxSingleTupleFamily as DefFamNoCtxSingleTupleRoot<
4381            u8,
4382            (),
4383            (u8, u8),
4384        >>::DefFamNoCtxSingleTupleChild::default();
4385
4386        let ctx = ();
4387
4388        <<DefFamNoCtxSingleTupleFamily as DefFamNoCtxSingleTupleRoot<u8, (), (u8, u8)>>
4389            ::DefFamNoCtxSingleTupleChild as PurePluginModel<u8, (), (u8, u8)>>
4390            ::compute(&model, input, &ctx)
4391    }
4392
4393    #[test]
4394    fn define_family_no_context_single_input_tuple_output_works() {
4395        assert_eq!(run_define_family_no_ctx_single_tuple(10), (10, 11));
4396        assert_eq!(run_define_family_no_ctx_single_tuple(0), (0, 1));
4397    }
4398
4399    //--- No Context, Tuple Input, Single Output ---
4400
4401    declare_family! {
4402        root: pub DefFamNoCtxTupleSingleRoot,
4403        child: [DefFamNoCtxTupleSingleChild]
4404    }
4405
4406    define_family! {
4407        root: DefFamNoCtxTupleSingleRoot,
4408        family: DefFamNoCtxTupleSingleFamily,
4409        input: (InpA, InpB),
4410        output: Output,
4411        bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
4412        child: [
4413            DefFamNoCtxTupleSingleChild => PureNoCtxTupleSingle,
4414        ],
4415    }
4416
4417    fn run_define_family_no_ctx_tuple_single(input: (u8, u8)) -> u8 {
4418        let model = <DefFamNoCtxTupleSingleFamily as DefFamNoCtxTupleSingleRoot<
4419            (u8, u8),
4420            (),
4421            u8,
4422        >>::DefFamNoCtxTupleSingleChild::default();
4423
4424        let ctx = ();
4425
4426        <<DefFamNoCtxTupleSingleFamily as DefFamNoCtxTupleSingleRoot<(u8, u8), (), u8>>
4427            ::DefFamNoCtxTupleSingleChild as PurePluginModel<(u8, u8), (), u8>>
4428            ::compute(&model, input, &ctx)
4429    }
4430
4431    #[test]
4432    fn define_family_no_context_tuple_input_single_output_works() {
4433        assert_eq!(run_define_family_no_ctx_tuple_single((10, 11)), 21);
4434        assert_eq!(run_define_family_no_ctx_tuple_single((0, 5)), 5);
4435    }
4436
4437    //--- No Context, Tuple Input, Tuple Output ---
4438
4439    declare_family! {
4440        root: pub DefFamNoCtxTupleTupleRoot,
4441        child: [DefFamNoCtxTupleTupleChild]
4442    }
4443
4444    define_family! {
4445        root: DefFamNoCtxTupleTupleRoot,
4446        family: DefFamNoCtxTupleTupleFamily,
4447        input: (InpA, InpB),
4448        output: (OutA, OutB),
4449        bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
4450        child: [
4451            DefFamNoCtxTupleTupleChild => PureNoCtxTupleTuple,
4452        ],
4453    }
4454
4455    fn run_define_family_no_ctx_tuple_tuple(input: (u8, u8)) -> (u8, u8) {
4456        let model = <DefFamNoCtxTupleTupleFamily as DefFamNoCtxTupleTupleRoot<
4457            (u8, u8),
4458            (),
4459            (u8, u8),
4460        >>::DefFamNoCtxTupleTupleChild::default();
4461
4462        let ctx = ();
4463
4464        <<DefFamNoCtxTupleTupleFamily as DefFamNoCtxTupleTupleRoot<(u8, u8), (), (u8, u8)>>
4465            ::DefFamNoCtxTupleTupleChild as PurePluginModel<(u8, u8), (), (u8, u8)>>
4466            ::compute(&model, input, &ctx)
4467    }
4468
4469    #[test]
4470    fn define_family_no_context_tuple_input_tuple_output_works() {
4471        assert_eq!(run_define_family_no_ctx_tuple_tuple((5, 10)), (50, 100));
4472        assert_eq!(run_define_family_no_ctx_tuple_tuple((1, 0)), (10, 0));
4473    }
4474
4475    //--- With Context + marker ---
4476
4477    plugin_model! {
4478        name: pub PureGenericCtxSingleSingle,
4479        input: Input,
4480        output: Output,
4481        others: [T],
4482        context: GenericConfig<T>,
4483        bounds: [Input: Into<u8>, Output: From<u8>, T: Into<u8> + Clone],
4484        compute: |input, ctx| {
4485            Output::from(input.into() + ctx.value.clone().into())
4486        },
4487    }
4488
4489    declare_family! {
4490        root: pub DefFamCtxMarkerRoot,
4491        child: [DefFamCtxMarkerChild]
4492    }
4493
4494    define_family! {
4495        root: DefFamCtxMarkerRoot,
4496        family: DefFamCtxMarkerFamily,
4497        input: Input,
4498        output: Output,
4499        context: GenericConfig<T>,
4500        marker: [T],
4501        bounds: [Input: Into<u8>, Output: From<u8>, T: Into<u8> + Clone],
4502        child: [
4503            DefFamCtxMarkerChild => PureGenericCtxSingleSingle,
4504        ],
4505    }
4506
4507    fn run_define_family_ctx_marker(input: u8) -> u8 {
4508        let model =
4509            <DefFamCtxMarkerFamily as DefFamCtxMarkerRoot<u8, GenericConfig<u8>, u8>>
4510                ::DefFamCtxMarkerChild::default();
4511
4512        let ctx = GenericConfig { value: 7u8 };
4513
4514        <<DefFamCtxMarkerFamily as DefFamCtxMarkerRoot<u8, GenericConfig<u8>, u8>>
4515            ::DefFamCtxMarkerChild as PurePluginModel<u8, GenericConfig<u8>, u8>>
4516            ::compute(&model, input, &ctx)
4517    }
4518
4519    #[test]
4520    fn define_family_with_context_marker_works() {
4521        assert_eq!(run_define_family_ctx_marker(10), 17);
4522        assert_eq!(run_define_family_ctx_marker(0), 7);
4523    }
4524
4525    //--- With Context + borrow + marker ---
4526
4527    plugin_model! {
4528        name: pub PureGenericBorrowCtx,
4529        input: Input,
4530        output: Output,
4531        others: [T],
4532        context: GenericConfig<T>,
4533        bounds: [Input: AsRef<[u8]>, Output: From<usize>, T: Clone],
4534        compute: |input, _ctx| {
4535            Output::from(input.as_ref().len())
4536        },
4537    }
4538
4539    declare_family! {
4540        root: pub DefFamCtxBorrowMarkerRoot,
4541        child: [DefFamCtxBorrowMarkerChild]
4542    }
4543
4544    define_family! {
4545        root: DefFamCtxBorrowMarkerRoot,
4546        family: DefFamCtxBorrowMarkerFamily,
4547        borrow: ['a],
4548        input: Input,
4549        output: Output,
4550        context: GenericConfig<T>,
4551        marker: [T],
4552        bounds: [Input: AsRef<[u8]> + 'a, Output: From<usize>, T: Clone],
4553        child: [
4554            DefFamCtxBorrowMarkerChild => PureGenericBorrowCtx,
4555        ],
4556    }
4557
4558    fn run_define_family_ctx_borrow_marker<'a>(input: &'a [u8]) -> usize {
4559        let model = <DefFamCtxBorrowMarkerFamily<'a> as DefFamCtxBorrowMarkerRoot<
4560            &'a [u8],
4561            GenericConfig<u8>,
4562            usize,
4563        >>::DefFamCtxBorrowMarkerChild::default();
4564
4565        let ctx = GenericConfig { value: 99u8 };
4566
4567        <<DefFamCtxBorrowMarkerFamily<'a> as DefFamCtxBorrowMarkerRoot<&'a [u8], GenericConfig<u8>, usize>>
4568            ::DefFamCtxBorrowMarkerChild as PurePluginModel<&'a [u8], GenericConfig<u8>, usize>>
4569            ::compute(&model, input, &ctx)
4570    }
4571
4572    #[test]
4573    fn define_family_with_context_borrow_and_marker_works() {
4574        let data = [1u8, 2, 3, 4];
4575        assert_eq!(run_define_family_ctx_borrow_marker(&data), 4);
4576
4577        let data = [9u8];
4578        assert_eq!(run_define_family_ctx_borrow_marker(&data), 1);
4579    }
4580
4581    //--- No Context + multiple children ---
4582
4583    declare_family! {
4584        root: pub DefFamNoCtxMultiChildRoot,
4585        child: [DefFamNoCtxMultiChildA, DefFamNoCtxMultiChildB]
4586    }
4587
4588    define_family! {
4589        root: DefFamNoCtxMultiChildRoot,
4590        family: DefFamNoCtxMultiChildFamily,
4591        input: Input,
4592        output: Output,
4593        bounds: [Input: Into<u8>, Output: From<u8>],
4594        child: [
4595            DefFamNoCtxMultiChildA => PureNoCtxSingleSingle,
4596            DefFamNoCtxMultiChildB => PureNoCtxSingleSingle,
4597        ],
4598    }
4599
4600    fn run_define_family_no_ctx_multi_child_a(input: u8) -> u8 {
4601        let model =
4602            <DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
4603                ::DefFamNoCtxMultiChildA::default();
4604
4605        let ctx = ();
4606
4607        <<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
4608            ::DefFamNoCtxMultiChildA as PurePluginModel<u8, (), u8>>
4609            ::compute(&model, input, &ctx)
4610    }
4611
4612    fn run_define_family_no_ctx_multi_child_b(input: u8) -> u8 {
4613        let model =
4614            <DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
4615                ::DefFamNoCtxMultiChildB::default();
4616
4617        let ctx = ();
4618
4619        <<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
4620            ::DefFamNoCtxMultiChildB as PurePluginModel<u8, (), u8>>
4621            ::compute(&model, input, &ctx)
4622    }
4623
4624    #[test]
4625    fn define_family_multiple_children_work() {
4626        assert_eq!(run_define_family_no_ctx_multi_child_a(10), 11);
4627        assert_eq!(run_define_family_no_ctx_multi_child_b(0), 1);
4628
4629        let _a = DefFamNoCtxMultiChildA;
4630        let _b = DefFamNoCtxMultiChildB;
4631    }
4632
4633    //--- No Context + multiple children with distinct models ---
4634
4635    plugin_model! {
4636        name: pub PureNoCtxSingleSingleDouble,
4637        input: Input,
4638        output: Output,
4639        bounds: [Input: Into<u8>, Output: From<u8>],
4640        compute: |input, _ctx| {
4641            let x = input.into();
4642            Output::from(x * 2)
4643        }
4644    }
4645
4646    declare_family! {
4647        root: pub DefFamNoCtxMultiChildDistinctRoot,
4648        child: [DefFamNoCtxMultiChildInc, DefFamNoCtxMultiChildDouble]
4649    }
4650
4651    define_family! {
4652        root: DefFamNoCtxMultiChildDistinctRoot,
4653        family: DefFamNoCtxMultiChildDistinctFamily,
4654        input: Input,
4655        output: Output,
4656        bounds: [Input: Into<u8>, Output: From<u8>],
4657        child: [
4658            DefFamNoCtxMultiChildInc => PureNoCtxSingleSingle,
4659            DefFamNoCtxMultiChildDouble => PureNoCtxSingleSingleDouble,
4660        ],
4661    }
4662
4663    fn run_define_family_no_ctx_multi_child_inc(input: u8) -> u8 {
4664        let model = <DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<
4665            u8,
4666            (),
4667            u8,
4668        >>::DefFamNoCtxMultiChildInc::default();
4669
4670        let ctx = ();
4671
4672        <<DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<u8, (), u8>>
4673            ::DefFamNoCtxMultiChildInc as PurePluginModel<u8, (), u8>>
4674            ::compute(&model, input, &ctx)
4675    }
4676
4677    fn run_define_family_no_ctx_multi_child_double(input: u8) -> u8 {
4678        let model = <DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<
4679            u8,
4680            (),
4681            u8,
4682        >>::DefFamNoCtxMultiChildDouble::default();
4683
4684        let ctx = ();
4685
4686        <<DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<u8, (), u8>>
4687            ::DefFamNoCtxMultiChildDouble as PurePluginModel<u8, (), u8>>
4688            ::compute(&model, input, &ctx)
4689    }
4690
4691    #[test]
4692    fn define_family_multiple_children_with_distinct_models_work() {
4693        assert_eq!(run_define_family_no_ctx_multi_child_inc(10), 11);
4694        assert_eq!(run_define_family_no_ctx_multi_child_inc(0), 1);
4695
4696        assert_eq!(run_define_family_no_ctx_multi_child_double(10), 20);
4697        assert_eq!(run_define_family_no_ctx_multi_child_double(3), 6);
4698
4699        let _inc = DefFamNoCtxMultiChildInc;
4700        let _double = DefFamNoCtxMultiChildDouble;
4701    }
4702        
4703    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4704    // ```````````````````````````````` HELPER MACROS ````````````````````````````````
4705    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4706
4707    #[test]
4708    fn phantom_struct_no_lifetime_no_generic_compiles() {
4709        __phantom_struct!(pub Plain [] []);
4710        let _x = Plain;
4711    }
4712
4713    #[test]
4714    fn phantom_struct_lifetime_only_compiles() {
4715        __phantom_struct!(pub WithLt ['a] []);
4716        let _x: WithLt<'static>;
4717    }
4718
4719    #[test]
4720    fn phantom_struct_generic_only_compiles() {
4721        __phantom_struct!(pub WithGen [] [T]);
4722        let _x: WithGen<u8>;
4723    }
4724
4725    #[test]
4726    fn phantom_struct_lifetime_and_generic_compiles() {
4727        __phantom_struct!(pub WithLtGen ['a] [T]);
4728        let _x: WithLtGen<'static, u8>;
4729    }
4730
4731    #[test]
4732    fn phantom_struct_generic_is_covariant() {
4733        __phantom_struct!(pub CovGen [] [T]);
4734        // covariance: Foo<&'static str> can be used where Foo<&'short str> is expected
4735        fn accepts<'a>(_: CovGen<&'a str>) {}
4736        let x: CovGen<&'static str> = CovGen(PhantomData);
4737        accepts(x);
4738    }
4739
4740    #[test]
4741    fn phantom_struct_lifetime_and_generic_is_covariant() {
4742        __phantom_struct!(pub CovLtGen ['a] [T]);
4743        fn accepts<'a>(_: CovLtGen<'a, &'a str>) {}
4744        let x: CovLtGen<'static, &'static str> = CovLtGen(PhantomData);
4745        accepts(x);
4746    }
4747
4748    #[test]
4749    fn phantom_struct_field_types_are_correct() {
4750        // Arm 2: PhantomData<(&'a (),)>
4751        __phantom_struct!(pub LtField ['a] []);
4752        let _: LtField<'static> = LtField(PhantomData::<(&'static (),)>);
4753
4754        // Arm 3: PhantomData<(T,)>
4755        __phantom_struct!(pub GenField [] [T]);
4756        let _: GenField<u8> = GenField(PhantomData::<(u8,)>);
4757
4758        // Arm 4: PhantomData<(T, &'a ())> generics first, then lifetime references
4759        __phantom_struct!(pub LtGenField ['a] [T]);
4760        let _: LtGenField<'static, u8> = LtGenField(PhantomData::<(u8, &'static ())>);
4761    }
4762}