pub trait PurePluginModel<Input, Context, Output>: Default {
fn compute(&self, input: Input, context: &Context) -> Output;
}
pub trait MutablePluginModel<Mutate, Context, Output>: Default {
fn compute_mut(&self, input: &mut Mutate, context: &Context) -> Output;
}
pub trait ModelContext {
type Context;
fn context() -> Self::Context;
}
impl ModelContext for () {
type Context = ();
fn context() -> () {
()
}
}
#[macro_export]
macro_rules! plugin_types {
(
input: $InputTy:ty,
output: $OutputTy:ty,
$(#[$model_meta:meta])*
model: $ModelAssoc:ident,
$(#[$ctx_meta:meta])*
context: $ContextAssoc:ident $(,)?
) => {
$(#[$model_meta])*
type $ModelAssoc: $crate::plugins::PurePluginModel<
$InputTy,
<Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
$OutputTy,
> + Default;
$(#[$ctx_meta])*
type $ContextAssoc:
$crate::plugins::ModelContext;
};
(
input: mut $MutateTy:ty,
output: $OutputTy:ty,
$(#[$model_meta:meta])*
model: $ModelAssoc:ident,
$(#[$ctx_meta:meta])*
context: $ContextAssoc:ident $(,)?
) => {
$(#[$model_meta])*
type $ModelAssoc: $crate::plugins::MutablePluginModel<
$MutateTy,
<Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
$OutputTy,
> + Default;
$(#[$ctx_meta])*
type $ContextAssoc:
$crate::plugins::ModelContext;
};
(
input: $(mut)? $InputTy:ty,
output: $OutputTy:ty,
$(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
root: $Root:ident,
$(#[$model_meta:meta])*
family: $FamilyAssoc:ident,
$(#[$ctx_meta:meta])*
context: $ContextAssoc:ident
$(, provides: [$($provider:tt)*])? $(,)?
) => {
$(#[$model_meta])*
type $FamilyAssoc $(<$($borrow_lt)*>)? : $Root<
$InputTy,
<Self::$ContextAssoc as $crate::plugins::ModelContext>::Context,
$OutputTy,
>;
$(#[$ctx_meta])*
type $ContextAssoc:
$crate::plugins::ModelContext$(<Context: $($provider)*>)?;
};
}
#[macro_export]
macro_rules! plugin_context {
(
$(#[$meta:meta])*
name: $vis:vis $Name:ident,
context: $ContextType:ty,
$(marker: [$($marker_gen:ident),* $(,)?],)?
$(bounds: [$($bounds:tt)*],)?
value: $ContextLiteral:expr $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[]
[$($($marker_gen),*)?]
);
impl $(< $($marker_gen,)* >)?
$crate::plugins::ModelContext
for $Name $(< $($marker_gen,)* >)?
$(where $($bounds)*)?
{
type Context = $ContextType;
fn context() -> Self::Context {
$ContextLiteral
}
}
};
}
#[macro_export]
macro_rules! plugin_output {
(
$(#[$meta:meta])*
$vis:vis fn $name:ident,
input: $Input:ty,
output: $Output:ty,
model: $ModelType:ty,
context: $ContextType:ty $(,)?
) => {
$(#[$meta])*
$vis fn $name (input: $Input) -> $Output
{
let model = <$ModelType>::default();
let context: <$ContextType as $crate::plugins::ModelContext>::Context =
<$ContextType as $crate::plugins::ModelContext>::context();
$crate::plugins::PurePluginModel::<_, _, _>::compute(&model, input, &context)
}
};
(
$(#[$meta:meta])*
$vis:vis fn $name:ident,
input: mut $Input:ty,
output: $Output:ty,
model: $ModelType:ty,
context: $ContextType:ty $(,)?
) => {
$(#[$meta])*
$vis fn $name(input: &mut $Input) -> $Output
{
let model = <$ModelType>::default();
let context: <$ContextType as $crate::plugins::ModelContext>::Context =
<$ContextType as $crate::plugins::ModelContext>::context();
$crate::plugins::MutablePluginModel::<_, _, _>::compute_mut(&model, input, &context)
}
};
(
$(#[$meta:meta])*
$vis:vis fn $name:ident,
input: $Input:ty,
output: $Output:ty,
$(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
root: $Root:ident,
family: $Family:ty,
child: $Child:ident,
context: $ContextType:ty $(,)?
) => {
#[doc = concat!(
"Plugin invocation pure-function for the child - [`",
stringify!($Child),
"`] of the plugin family - [`",
stringify!($Root),
"`]"
)]
$(#[$meta])*
$vis fn $name $(<$($borrow_lt)*>)? (input: $Input) -> $Output
{
let model =
<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
$Output>>::$Child::default();
let context =
<$ContextType as $crate::plugins::ModelContext>::context();
<<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
$Output>>::$Child
as $crate::plugins::PurePluginModel<
$Input,
<$ContextType as $crate::plugins::ModelContext>::Context,
$Output,
>>::compute(&model, input, &context)
}
};
(
$(#[$meta:meta])*
$vis:vis fn $name:ident,
input: mut $Input:ty,
output: $Output:ty,
$(borrow: [$($borrow_lt:lifetime)* $(,)?],)?
root: $Root:ident,
family: $Family:ty,
child: $Child:ident,
context: $ContextType:ty $(,)?
) => {
#[doc = concat!(
"Plugin invocation mutable-function for the child - [`",
stringify!($Child),
"`] of the plugin family - [`",
stringify!($Root),
"`]"
)]
$(#[$meta])*
$vis fn $name $(<$($borrow_lt)*>)? (input: &mut $Input) -> $Output
{
let model =
<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
$Output>>::$Child::default();
let context =
<$ContextType as $crate::plugins::ModelContext>::context();
<<$Family as $Root<$Input,<$ContextType as $crate::plugins::ModelContext>::Context,
$Output>>::$Child
as $crate::plugins::MutablePluginModel<
$Input,
<$ContextType as $crate::plugins::ModelContext>::Context,
$Output,
>>::compute_mut(&model, input, &context)
}
};
}
#[macro_export]
macro_rules! plugin_test {
(@output_ty $InputType:ty) => { $InputType };
(@output_ty $InputType:ty, $OutputType:ty) => { $OutputType };
(
model: $ModelName:ty,
input: $InputTy:ty,
output: $OutputTy:ty,
context: $ContextTy:ty,
value: $ContextExpr:expr,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
) => {
$(
#[test] fn $test_name() {
let model = <$ModelName>::default(); let context: $ContextTy = $ContextExpr; let input: $InputTy = $input_expr; let result: $OutputTy = <$ModelName as $crate::plugins::PurePluginModel<
$InputTy,
$ContextTy,
$OutputTy
>>::compute(&model, input, &context);
assert_eq!(result, $expected); }
)*
};
(
model: $ModelName:ty,
input: $InputTy:ty,
context: $ContextTy:ty,
value: $ContextExpr:expr,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
type Output = $InputTy;
let model = <$ModelName>::default();
let context: $ContextTy = $ContextExpr;
let input: $InputTy = $input_expr;
let result: Output =
<$ModelName as $crate::plugins::PurePluginModel<
$InputTy,
$ContextTy,
Output
>>::compute(&model, input, &context);
assert_eq!(result, $expected);
}
)*
};
(
model: $ModelName:ty,
input: $InputTy:ty,
output: $OutputTy:ty,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
let model = <$ModelName>::default();
let context: () = Default::default();
let input: $InputTy = $input_expr;
let result: $OutputTy =
<$ModelName as $crate::plugins::PurePluginModel<
$InputTy,
(),
$OutputTy
>>::compute(&model, input, &context);
assert_eq!(result, $expected);
}
)*
};
(
model: $ModelName:ty,
input: $InputTy:ty,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
type Output = $InputTy;
let model = <$ModelName>::default();
let context: () = Default::default();
let input: $InputTy = $input_expr;
let result: Output =
<$ModelName as $crate::plugins::PurePluginModel<
$InputTy,
(),
Output
>>::compute(&model, input, &context);
assert_eq!(result, $expected);
}
)*
};
(
model: $ModelName:ty,
input: mut $InputTy:ty,
output: $OutputTy:ty,
context: $ContextTy:ty,
value: $ContextExpr:expr,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
let model = <$ModelName>::default();
let context: $ContextTy = $ContextExpr;
let mut input: $InputTy = $input_expr;
let result: $OutputTy =
<$ModelName as $crate::plugins::MutablePluginModel<
$InputTy,
$ContextTy,
$OutputTy
>>::compute_mut(&model, &mut input, &context);
assert_eq!(result, $expected);
$(
assert_eq!(input, $expected_input);
)?
}
)*
};
(
model: $ModelName:ty,
input: mut $InputTy:ty,
context: $ContextTy:ty,
value: $ContextExpr:expr,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
type Output = $InputTy;
let model = <$ModelName>::default();
let context: $ContextTy = $ContextExpr;
let mut input: $InputTy = $input_expr;
let result: Output =
<$ModelName as $crate::plugins::MutablePluginModel<
$InputTy,
$ContextTy,
Output
>>::compute_mut(&model, &mut input, &context);
assert_eq!(result, $expected);
$(
assert_eq!(input, $expected_input);
)?
}
)*
};
(
model: $ModelName:ty,
input: mut $InputTy:ty,
output: $OutputTy:ty,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
let model = <$ModelName>::default();
let context: () = Default::default();
let mut input: $InputTy = $input_expr;
let result: $OutputTy =
<$ModelName as $crate::plugins::MutablePluginModel<
$InputTy,
(),
$OutputTy
>>::compute_mut(&model, &mut input, &context);
assert_eq!(result, $expected);
$(
assert_eq!(input, $expected_input);
)?
}
)*
};
(
model: $ModelName:ty,
input: mut $InputTy:ty,
cases: { $(($test_name:ident, $input_expr:expr, $expected:expr $(, $expected_input:expr)?)),* $(,)? }
) => {
$(
#[test]
fn $test_name() {
type Output = $InputTy;
let model = <$ModelName>::default();
let context: () = Default::default();
let mut input: $InputTy = $input_expr;
let result: Output =
<$ModelName as $crate::plugins::MutablePluginModel<
$InputTy,
(),
Output
>>::compute_mut(&model, &mut input, &context);
assert_eq!(result, $expected);
$(
assert_eq!(input, $expected_input);
)?
}
)*
};
}
#[macro_export]
macro_rules! plugin_model {
(@output_ty $Input:tt) => { $Input };
(@output_ty $Input:tt, $Output:tt) => { $Output };
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $Output)?
> $crate::plugins::PurePluginModel<
$Input,
(),
$crate::plugin_model!(@output_ty $Input $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: $Input,
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $($Output),+)?
> $crate::plugins::PurePluginModel<
$Input,
(),
$crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: $Input,
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $Output)?
> $crate::plugins::PurePluginModel<
($($Input),+),
(),
$crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: ($($Input),+),
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $($Output),+)?
> $crate::plugins::PurePluginModel<
($($Input),+),
(),
$crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: ($($Input),+),
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $Output)?
> $crate::plugins::PurePluginModel<
$Input,
$Context,
$crate::plugin_model!(@output_ty $Input $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: $Input,
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $($Output),+)?
> $crate::plugins::PurePluginModel<
$Input,
$Context,
$crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: $Input,
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $Output)?
> $crate::plugins::PurePluginModel<
($($Input),+),
$Context,
$crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: ($($Input),+),
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $($Output),+)?
> $crate::plugins::PurePluginModel<
($($Input),+),
$Context,
$crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute(
&self,
$input_arg: ($($Input),+),
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $Output)?
> $crate::plugins::MutablePluginModel<
$Input,
(),
$crate::plugin_model!(@output_ty $Input $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut $Input,
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $($Output),+)?
> $crate::plugins::MutablePluginModel<
$Input,
(),
$crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut $Input,
$ctx_arg: &()
) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $Output)?
> $crate::plugins::MutablePluginModel<
($($Input),+),
(),
$crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut ($($Input),+),
$ctx_arg: &(),
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $($Output),+)?
> $crate::plugins::MutablePluginModel<
($($Input),+),
(),
$crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut ($($Input),+),
$ctx_arg: &(),
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $Output)?
> $crate::plugins::MutablePluginModel<
$Input,
$Context,
$crate::plugin_model!(@output_ty $Input $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut $Input,
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty $Input $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$Input
$(, $($Output),+)?
> $crate::plugins::MutablePluginModel<
$Input,
$Context,
$crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut $Input,
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty $Input $(, ($($Output),+))?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: $Output:ident ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $Output)?
> $crate::plugins::MutablePluginModel<
($($Input),+),
$Context,
$crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut ($($Input),+),
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, $Output)?) {
$body
}
}
};
(
$(#[$name_meta:meta])*
name: $vis:vis $ModelName:ident,
input: mut ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(others: [$($other_gen:tt),* $(,)? ] ,)?
context: $Context:ty,
bounds: [$($bounds:tt)*],
$(#[$compute_meta:meta])*
compute: |$input_arg:ident, $ctx_arg:ident| $body:block $(,)?
) => {
#[derive(Debug, Default)]
$(#[$name_meta])*
$vis struct $ModelName;
impl<
$($($other_gen ,)*)?
$($Input),+
$(, $($Output),+)?
> $crate::plugins::MutablePluginModel<
($($Input),+),
$Context,
$crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?)
> for $ModelName
where
$($bounds)*
{
$(#[$compute_meta])*
fn compute_mut(
&self,
$input_arg: &mut ($($Input),+),
$ctx_arg: &$Context
) -> $crate::plugin_model!(@output_ty ($($Input),+) $(, ($($Output),+))?) {
$body
}
}
};
}
#[macro_export]
macro_rules! declare_family {
(
$(#[$meta:meta])*
root: $vis:vis $Root:ident,
child: [
$(
$(#[$child_meta:meta])*
$Child:ident
),+ $(,)?
]
) => {
$(
$(#[$child_meta])*
$vis struct $Child;
)+
$(#[$meta])*
$vis trait $Root<Input, Context, Output>{
$(
$(#[$child_meta])*
type $Child: $crate::plugins::PurePluginModel<Input, Context, Output>;
)+
}
};
(
$(#[$meta:meta])*
root: mut $vis:vis $Root:ident,
child: [
$(
$(#[$child_meta:meta])*
$Child:ident
),+ $(,)?
]
) => {
$(
$(#[$child_meta])*
$vis struct $Child;
)+
$(#[$meta])*
$vis trait $Root<Input, Context, Output> {
$(
$(#[$child_meta])*
type $Child: $crate::plugins::MutablePluginModel<Input, Context, Output>;
)+
}
};
}
#[macro_export]
macro_rules! define_family {
(@output_ty $Input:tt) => { $Input };
(@output_ty $Input:tt, $Output:tt) => { $Output };
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: $Input:ident,
$(output: $Output:ident ,)?
context: $Context:ty,
$(marker: [$($marker_gen:ident),* $(,)?],)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($($marker_gen,)*)?
$Input
$(, $Output)?
> $Root<
$Input,
$Context,
$crate::define_family!(@output_ty $Input $(, $Output)?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
context: $Context:ty,
$(marker: [$($marker_gen:ident),* $(,)?],)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($($marker_gen,)*)?
$Input
$(, $($Output),+)?
> $Root<
$Input,
$Context,
$crate::define_family!(@output_ty $Input $(, ($($Output),+))?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
context: $Context:ty,
$(marker: [$($marker_gen:ident),* $(,)?],)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($($marker_gen,)*)?
$($Input),+
$(, $Output)?
> $Root<
($($Input),+),
$Context,
$crate::define_family!(@output_ty ($($Input),+) $(, $Output)?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
context: $Context:ty,
$(marker: [$($marker_gen:ident),* $(,)?],)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($($marker_gen,)*)?
$($Input),+
$(, $($Output),+)?
> $Root<
($($Input),+),
$Context,
$crate::define_family!(@output_ty ($($Input),+) $(, ($($Output),+))?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: $Input:ident,
$(output: $Output:ident ,)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$Input
$(, $Output)?
> $Root<
$Input,
(),
$crate::define_family!(@output_ty $Input $(, $Output)?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: $Input:ident,
$(output: ($($Output:ident),+) ,)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$Input
$(, $($Output),+)?
> $Root<
$Input,
(),
$crate::define_family!(@output_ty $Input $(, ($($Output),+))?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: ($($Input:ident),+),
$(output: $Output:ident ,)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($Input),+
$(, $Output)?
> $Root<
($($Input),+),
(),
$crate::define_family!(@output_ty ($($Input),+) $(, $Output)?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
(
root: $Root:ident,
$(#[$meta:meta])*
family: $vis:vis $Name:ident,
$(borrow: [$($borrow_lt:lifetime),* $(,)?],)?
input: ($($Input:ident),+),
$(output: ($($Output:ident),+) ,)?
$(bounds: [$($bounds:tt)*],)?
child: [
$($child:ident => $model:ty,)+
$(,)? ] $(,)?
) => {
$crate::__phantom_struct!(
$(#[$meta])*
#[allow(unused)]
$vis
$Name
[$($($borrow_lt),*)?]
[]
);
impl<
$($($borrow_lt,)*)?
$($Input),+
$(, $($Output),+)?
> $Root<
($($Input),+),
(),
$crate::define_family!(@output_ty ($($Input),+) $(, ($($Output),+))?)
>
for $Name$(<
$($borrow_lt,)*
>)?
$(where $($bounds)*)?
{
$(
type $child = $model;
)+
}
};
}
#[macro_export]
macro_rules! __phantom_struct {
(
$(#[$meta:meta])*
$vis:vis
$Name:ident
[]
[]
) => {
$(#[$meta])*
$vis struct $Name;
};
// Arm 2: Lifetimes only -> struct with a PhantomData reference tuple
(
$(#[$meta:meta])*
$vis:vis
$Name:ident
[$($lt:lifetime),+ $(,)?]
[]
) => {
$(#[$meta])*
$vis struct $Name<$($lt),*>(
core::marker::PhantomData<($(&$lt (),)*)>
);
};
(
$(#[$meta:meta])*
$vis:vis
$Name:ident
[]
[$($gen:ident),+ $(,)?]
) => {
$(#[$meta])*
$vis struct $Name<$($gen),*>(
core::marker::PhantomData<($($gen,)*)>
);
};
(
$(#[$meta:meta])*
$vis:vis
$Name:ident
[$($lt:lifetime),+ $(,)?]
[$($gen:ident),+ $(,)?]
) => {
$(#[$meta])*
$vis struct $Name<$($lt),*, $($gen),*>(
core::marker::PhantomData<($($gen,)* $(&$lt (),)*)>
);
};
}
#[cfg(test)]
#[allow(unused)]
mod tests {
use super::*;
use core::marker::PhantomData;
use std::mem::take;
use sp_arithmetic::traits::AtLeast8BitUnsigned;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BasicConfig {
value: u8,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GenericConfig<T> {
value: T,
}
plugin_context! {
name: pub BasicConfigProvider,
context: BasicConfig,
value: BasicConfig {value: 10}
}
#[test]
fn plugin_context_basic_form_returns_expected_context() {
let ctx = <BasicConfigProvider as ModelContext>::context();
assert_eq!(ctx, BasicConfig { value: 10 });
}
plugin_context! {
name: GenericConfigProvider,
context: GenericConfig<T>,
marker: [T],
bounds: [T: AtLeast8BitUnsigned + Default],
value: GenericConfig {value: T::default()}
}
#[test]
fn plugin_context_marker_form_returns_expected_context() {
let ctx = <GenericConfigProvider<u8> as ModelContext>::context();
assert_eq!(ctx, GenericConfig { value: 0u8 });
}
plugin_model! {
name: pub PureNoCtxSingleSingle,
input: Input,
output: Output,
bounds: [Input: Into<u8>, Output: From<u8>],
compute: |input, _ctx| {
let x = input.into();
Output::from(x + 1)
}
}
plugin_test! {
model: PureNoCtxSingleSingle,
input: u8,
output: u8,
cases: {
(pure_no_ctx_single_single_case1, 10, 11),
(pure_no_ctx_single_single_case2, 0, 1),
}
}
plugin_test! {
model: PureNoCtxSingleSingle,
input: u8,
cases: {
(pure_no_ctx_single_single_case3, 99, 100),
(pure_no_ctx_single_single_case4, 24, 25),
}
}
plugin_model! {
name: pub PureNoCtxSingleTuple,
input: Input,
output: (OutA, OutB),
bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
compute: |input, _ctx| {
let x = input.into();
(OutA::from(x), OutB::from(x + 1))
}
}
plugin_test! {
model: PureNoCtxSingleTuple,
input: u8,
output: (u8, u8),
cases: {
(pure_no_ctx_single_tuple_case1, 10, (10, 11)),
(pure_no_ctx_single_tuple_case2, 0, (0, 1)),
}
}
plugin_model! {
name: pub PureNoCtxTupleSingle,
input: (InpA, InpB),
output: Output,
bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
compute: |input, _ctx| {
let (a, b) = input;
Output::from(a.into() + b.into())
}
}
plugin_test! {
model: PureNoCtxTupleSingle,
input: (u8, u8),
output: u8,
cases: {
(pure_no_ctx_tuple_single_case1, (10, 11), 21),
(pure_no_ctx_tuple_single_case2, (0, 5), 5),
}
}
plugin_model! {
name: pub PureNoCtxTupleTuple,
input: (InpA, InpB),
output: (OutA, OutB),
bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
compute: |input, _ctx| {
let (a, b) = input;
(OutA::from(a.into() * 10), OutB::from(b.into() * 10))
}
}
plugin_test! {
model: PureNoCtxTupleTuple,
input: (u8, u8),
output: (u8, u8),
cases: {
(pure_no_ctx_tuple_tuple_case1, (5, 10), (50, 100)),
(pure_no_ctx_tuple_tuple_case2, (1, 0), (10, 0)),
}
}
plugin_model! {
name: pub PureCtxSingleSingle,
input: Input,
output: Output,
context: BasicConfig,
bounds: [Input: Into<u8>, Output: From<u8>],
compute: |input, ctx| {
let v = ctx.value;
Output::from(input.into() + v)
}
}
plugin_test! {
model: PureCtxSingleSingle,
input: u8,
output: u8,
context: BasicConfig,
value: BasicConfig{ value: 10 },
cases: {
(pure_ctx_single_single_case1, 10, 20),
(pure_ctx_single_single_case2, 1, 11),
}
}
plugin_test! {
model: PureCtxSingleSingle,
input: u8,
context: BasicConfig,
value: BasicConfig{ value: 10 },
cases: {
(pure_ctx_single_single_case3, 90, 100),
(pure_ctx_single_single_case4, 0, 10),
}
}
plugin_model! {
name: pub PureCtxSingleTuple,
input: Input,
output: (OutA, OutB),
context: BasicConfig,
bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
compute: |input, ctx| {
let x = input.into();
let v = ctx.value;
(OutA::from(x), OutB::from(x + v))
}
}
plugin_test! {
model: PureCtxSingleTuple,
input: u8,
output: (u8, u8),
context: BasicConfig,
value: BasicConfig{ value: 1 },
cases: {
(pure_ctx_single_tuple_case1, 5, (5, 6)),
(pure_ctx_single_tuple_case2, 1, (1, 2)),
}
}
plugin_model! {
name: pub PureCtxTupleSingle,
input: (InpA, InpB),
output: Output,
context: BasicConfig,
bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
compute: |input, ctx| {
let (a, b) = input;
let v = ctx.value;
Output::from(a.into() + b.into() + v)
}
}
plugin_test! {
model: PureCtxTupleSingle,
input: (u8, u8),
output: u8,
context: BasicConfig,
value: BasicConfig { value: 10},
cases: {
(pure_ctx_tuple_single_case1, (10, 10), 30),
(pure_ctx_tuple_single_case2, (5, 30), 45),
}
}
plugin_model! {
name: pub PureCtxTupleTuple,
input: (InpA, InpB),
output: (OutA, OutB),
context: BasicConfig,
bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
compute: |input, ctx| {
let (a, b) = input;
let v = ctx.value;
(OutA::from(a.into() + v), OutB::from(b.into() + v))
}
}
plugin_test! {
model: PureCtxTupleTuple,
input: (u8, u8),
output: (u8, u8),
context: BasicConfig,
value: BasicConfig { value: 5 },
cases: {
(pure_ctx_tuple_tuple_case1, (5, 10), (10, 15)),
(pure_ctx_tuple_tuple_case2, (1, 0), (6, 5)),
}
}
plugin_model! {
name: pub MutNoCtxSingleSingle,
input: mut Input,
output: Output,
bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, Output: From<usize>],
compute: |input, _ctx| {
let mut v: Vec<u8> = take(input).into();
v.push(1);
let len = v.len();
*input = Input::from(v);
Output::from(len)
}
}
plugin_test! {
model: MutNoCtxSingleSingle,
input: mut Vec<u8>,
output: usize,
cases: {
(mut_no_ctx_single_single_case1, vec![1, 2], 3usize, vec![1, 2, 1]),
(mut_no_ctx_single_single_case2, vec![5, 4, 3, 2], 5usize, vec![5, 4, 3, 2, 1]),
}
}
plugin_model! {
name: pub MutNoCtxSingleTuple,
input: mut Input,
output: (OutA, OutB),
bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, OutA: From<usize>, OutB: From<u8>],
compute: |input, _ctx| {
let mut v: Vec<u8> = take(input).into();
v.push(1);
v.push(0);
let len = v.len();
let last = *v.last().unwrap();
*input = Input::from(v);
(OutA::from(len), OutB::from(last))
}
}
plugin_test! {
model: MutNoCtxSingleTuple,
input: mut Vec<u8>,
output: (usize, u8),
cases: {
(mut_no_ctx_single_tuple_case1, vec![1, 0], (4usize, 0), vec![1, 0, 1, 0]),
(mut_no_ctx_single_tuple_case2, vec![5, 4, 3, 2], (6usize, 0)),
}
}
plugin_model! {
name: pub MutNoCtxTupleSingle,
input: mut (InpA, InpB),
output: Output,
bounds: [InpA: From<u8> + Into<u8> + Copy, InpB: From<u8> + Into<u8> + Copy, Output: From<u8>],
compute: |input, _ctx| {
input.0 = InpA::from(input.0.into() + 1);
input.1 = InpB::from(input.1.into() + 1);
Output::from(input.0.into() + input.1.into())
}
}
plugin_test! {
model: MutNoCtxTupleSingle,
input: mut (u8, u8),
output: u8,
cases: {
(mut_no_ctx_tuple_single_case1, (11, 12), 25, (12, 13)),
(mut_no_ctx_tuple_single_case2, (0, 0), 2, (1, 1)),
}
}
plugin_model! {
name: pub MutNoCtxTupleTuple,
input: mut (A, B),
output: (OutA, OutB),
bounds: [A: From<u8> + Into<u8> + Copy, B: From<u8> + Into<u8> + Copy, OutA: From<u8>, OutB: From<u8>],
compute: |input, _ctx| {
input.0 = A::from(input.0.into() * 10);
input.1 = B::from(input.1.into() * 0);
(OutA::from(input.0.into()), OutB::from(input.1.into()))
}
}
plugin_test! {
model: MutNoCtxTupleTuple,
input: mut (u8, u8),
output: (u8, u8),
cases: {
(mut_no_ctx_tuple_tuple_case1, (10, 10), (100, 0), (100, 0)),
(mut_no_ctx_tuple_tuple_case2, (20, 35), (200, 0)),
}
}
plugin_test! {
model: MutNoCtxTupleTuple,
input: mut (u8, u8),
cases: {
(mut_no_ctx_tuple_tuple_case3, (1, 10), (10, 0), (10, 0)),
(mut_no_ctx_tuple_tuple_case4, (0, 0), (0, 0)),
}
}
plugin_model! {
name: pub MutCtxSingleSingle,
input: mut Input,
output: Output,
context: BasicConfig,
bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, Output: From<usize>],
compute: |input, ctx| {
let mut v: Vec<u8> = take(input).into();
v.push(ctx.value);
let len = v.len();
*input = Input::from(v);
Output::from(len)
}
}
plugin_test! {
model: MutCtxSingleSingle,
input: mut Vec<u8>,
output: usize,
context: BasicConfig,
value: BasicConfig { value: 0 },
cases: {
(mut_ctx_single_single_case1, vec![1], 2usize, vec![1, 0]),
(mut_ctx_single_single_case2, vec![1, 5, 3], 4usize, vec![1, 5, 3, 0]),
}
}
plugin_model! {
name: pub MutCtxSingleTuple,
input: mut Input,
output: (OutA, OutB),
context: BasicConfig,
bounds: [Input: From<Vec<u8>> + Into<Vec<u8>> + Default, OutA: From<usize>, OutB: From<u8>],
compute: |input, ctx| {
let mut v: Vec<u8> = take(input).into();
v.push(ctx.value);
let len = v.len();
let last = *v.last().unwrap();
*input = Input::from(v);
(OutA::from(len), OutB::from(last))
}
}
plugin_test! {
model: MutCtxSingleTuple,
input: mut Vec<u8>,
output: (usize, u8),
context: BasicConfig,
value: BasicConfig{value: 4},
cases: {
(mut_ctx_single_tuple_case1, vec![2, 3], (3usize, 4), vec![2, 3, 4]),
(mut_ctx_single_tuple_case2, vec![20, 16, 12, 8], (5usize, 4), vec![20, 16, 12, 8, 4]),
}
}
plugin_model! {
name: pub MutCtxTupleSingle,
input: mut (InpA, InpB),
output: Output,
context: BasicConfig,
bounds: [InpA: From<u8> + Into<u8> + Copy, InpB: From<u8> + Into<u8> + Copy, Output: From<u8>],
compute: |input, ctx| {
input.0 = InpA::from(input.0.into() + ctx.value);
input.1 = InpB::from(input.1.into() + ctx.value);
Output::from(input.0.into() + input.1.into())
}
}
plugin_test! {
model: MutCtxTupleSingle,
input: mut (u8, u8),
output: u8,
context: BasicConfig,
value: BasicConfig{value: 2},
cases: {
(mut_ctx_tuple_single_case1, (1, 2), 7, (3, 4)),
(mut_ctx_tuple_single_case2, (8, 8), 20, (10, 10)),
}
}
plugin_model! {
name: pub MutCtxTupleTuple,
input: mut (A, B),
output: (OutA, OutB),
context: BasicConfig,
bounds: [A: From<u8> + Into<u8> + Copy, B: From<u8> + Into<u8> + Copy, OutA: From<u8>, OutB: From<u8>],
compute: |input, ctx| {
input.0 = A::from(input.0.into() + ctx.value);
input.1 = B::from(input.1.into() + ctx.value + 1);
(OutA::from(input.0.into()), OutB::from(input.1.into()))
}
}
plugin_test! {
model: MutCtxTupleTuple,
input: mut (u8, u8),
output: (u8, u8),
context: BasicConfig,
value: BasicConfig{value: 2},
cases: {
(mut_ctx_tuple_tuple_case1, (5, 6), (7, 9), (7, 9)),
(mut_ctx_tuple_tuple_case2, (0, 0), (2, 3), (2, 3)),
}
}
plugin_test! {
model: MutCtxTupleTuple,
input: mut (u8, u8),
context: BasicConfig,
value: BasicConfig{value: 2},
cases: {
(mut_ctx_tuple_tuple_case3, (8, 7), (10, 10), (10, 10)),
(mut_ctx_tuple_tuple_case4, (1, 1), (3, 4), (3, 4)),
}
}
plugin_context! {
name: UnitContextProvider,
context: (),
value: ()
}
trait ImmutablePluginTrait {
plugin_types! {
input: u8,
output: u8,
model: Model,
context: Context,
}
}
struct ImmutableHost;
impl ImmutablePluginTrait for ImmutableHost {
type Model = PureNoCtxSingleSingle;
type Context = UnitContextProvider;
}
fn run_immutable_plugin<T: ImmutablePluginTrait>(input: u8) -> u8 {
let model = T::Model::default();
let ctx = <T::Context as ModelContext>::context();
<T::Model as PurePluginModel<u8, <T::Context as ModelContext>::Context, u8>>::compute(
&model, input, &ctx,
)
}
#[test]
fn plugin_types_immutable_model_arm_works() {
assert_eq!(run_immutable_plugin::<ImmutableHost>(10), 11);
assert_eq!(run_immutable_plugin::<ImmutableHost>(0), 1);
}
trait MutablePluginTrait {
plugin_types! {
input: mut Vec<u8>,
output: usize,
model: Model,
context: Context,
}
}
struct MutableHost;
impl MutablePluginTrait for MutableHost {
type Model = MutNoCtxSingleSingle;
type Context = UnitContextProvider;
}
fn run_mutable_plugin<T: MutablePluginTrait>(mut input: Vec<u8>) -> (Vec<u8>, usize) {
let model = T::Model::default();
let ctx = <T::Context as ModelContext>::context();
let out = <T::Model as MutablePluginModel<
Vec<u8>,
<T::Context as ModelContext>::Context,
usize,
>>::compute_mut(&model, &mut input, &ctx);
(input, out)
}
#[test]
fn plugin_types_mutable_model_arm_works() {
let (input, out) = run_mutable_plugin::<MutableHost>(vec![1, 2]);
assert_eq!(input, vec![1, 2, 1]);
assert_eq!(out, 3);
let (input, out) = run_mutable_plugin::<MutableHost>(vec![5, 4, 3, 2]);
assert_eq!(input, vec![5, 4, 3, 2, 1]);
assert_eq!(out, 5);
}
trait SimpleFamilyRoot<Input, Context, Output> {
type Op: PurePluginModel<Input, Context, Output> + Default;
}
struct SimpleFamily;
impl SimpleFamilyRoot<u8, (), u8> for SimpleFamily {
type Op = PureNoCtxSingleSingle;
}
trait FamilyPluginTrait {
plugin_types! {
input: u8,
output: u8,
root: SimpleFamilyRoot,
family: Family,
context: Context,
}
}
struct FamilyHost;
impl FamilyPluginTrait for FamilyHost {
type Family = SimpleFamily;
type Context = UnitContextProvider;
}
fn run_family_plugin<T: FamilyPluginTrait>(input: u8) -> u8 {
let model = <T::Family as SimpleFamilyRoot<
u8,
<T::Context as ModelContext>::Context,
u8,
>>::Op::default();
let ctx = <T::Context as ModelContext>::context();
<<T::Family as SimpleFamilyRoot<
u8,
<T::Context as ModelContext>::Context,
u8
>>::Op as PurePluginModel<
u8,
<T::Context as ModelContext>::Context,
u8
>>::compute(&model, input, &ctx)
}
#[test]
fn plugin_types_family_arm_works() {
assert_eq!(run_family_plugin::<FamilyHost>(10), 11);
assert_eq!(run_family_plugin::<FamilyHost>(0), 1);
}
trait ProvidedFamilyRoot<Input, Context, Output> {
type Op: PurePluginModel<Input, Context, Output> + Default;
}
struct ProvidedFamily;
impl ProvidedFamilyRoot<u8, BasicConfig, u8> for ProvidedFamily {
type Op = PureCtxSingleSingle;
}
trait ProvidedFamilyPluginTrait {
plugin_types! {
input: u8,
output: u8,
root: ProvidedFamilyRoot,
family: Family,
context: Context,
provides: [Send + Sync + 'static],
}
}
struct ThreadSafeConfigProvider;
impl ModelContext for ThreadSafeConfigProvider {
type Context = BasicConfig;
fn context() -> Self::Context {
BasicConfig { value: 10 }
}
}
struct ProvidedFamilyHost;
impl ProvidedFamilyPluginTrait for ProvidedFamilyHost {
type Family = ProvidedFamily;
type Context = ThreadSafeConfigProvider;
}
fn run_family_with_provides<T: ProvidedFamilyPluginTrait>(input: u8) -> u8 {
let model = <T::Family as ProvidedFamilyRoot<
u8,
<T::Context as ModelContext>::Context,
u8,
>>::Op::default();
let ctx = <T::Context as ModelContext>::context();
<<T::Family as ProvidedFamilyRoot<
u8,
<T::Context as ModelContext>::Context,
u8
>>::Op as PurePluginModel<
u8,
<T::Context as ModelContext>::Context,
u8
>>::compute(&model, input, &ctx)
}
#[test]
fn plugin_types_family_arm_with_provides_works() {
assert_eq!(run_family_with_provides::<ProvidedFamilyHost>(10), 20);
assert_eq!(run_family_with_provides::<ProvidedFamilyHost>(1), 11);
}
#[derive(Default)]
struct BorrowIdentityModel;
impl<'a> PurePluginModel<&'a [u8], (), &'a [u8]> for BorrowIdentityModel {
fn compute(&self, input: &'a [u8], _context: &()) -> &'a [u8] {
input
}
}
trait BorrowFamilyRoot<Input, Context, Output> {
type Op: PurePluginModel<Input, Context, Output> + Default;
}
struct BorrowFamily<'a>(PhantomData<&'a ()>);
impl<'a> BorrowFamilyRoot<&'a [u8], (), &'a [u8]> for BorrowFamily<'a> {
type Op = BorrowIdentityModel;
}
trait BorrowedFamilyPluginTrait {
plugin_types! {
input: &'a [u8],
output: &'a [u8],
borrow: ['a],
root: BorrowFamilyRoot,
family: Family,
context: Context,
}
}
struct BorrowedFamilyHost;
impl BorrowedFamilyPluginTrait for BorrowedFamilyHost {
type Family<'a> = BorrowFamily<'a>;
type Context = UnitContextProvider;
}
fn run_borrowed_family_plugin<'a, T: BorrowedFamilyPluginTrait>(input: &'a [u8]) -> &'a [u8] {
let model = <T::Family<'a> as BorrowFamilyRoot<
&'a [u8],
<T::Context as ModelContext>::Context,
&'a [u8],
>>::Op::default();
let ctx = <T::Context as ModelContext>::context();
<<T::Family<'a> as BorrowFamilyRoot<
&'a [u8],
<T::Context as ModelContext>::Context,
&'a [u8]
>>::Op as PurePluginModel<
&'a [u8],
<T::Context as ModelContext>::Context,
&'a [u8]
>>::compute(&model, input, &ctx)
}
#[test]
fn plugin_types_family_arm_with_borrow_works() {
let data = [1u8, 2, 3];
assert_eq!(
run_borrowed_family_plugin::<BorrowedFamilyHost>(&data),
&data
);
}
struct OutputPureModelRunner;
impl OutputPureModelRunner {
plugin_output! {
pub fn run_pure_model,
input: u8,
output: u8,
model: PureCtxSingleSingle,
context: BasicConfigProvider,
}
}
#[test]
fn plugin_output_immutable_model_arm_works() {
assert_eq!(OutputPureModelRunner::run_pure_model(10), 20);
assert_eq!(OutputPureModelRunner::run_pure_model(0), 10);
}
struct OutputMutableModelRunner;
impl OutputMutableModelRunner {
plugin_output! {
pub fn run_mutable_model,
input: mut Vec<u8>,
output: usize,
model: MutNoCtxSingleSingle,
context: UnitContextProvider,
}
}
#[test]
fn plugin_output_mutable_model_arm_works() {
let mut input = vec![1, 2];
let out = OutputMutableModelRunner::run_mutable_model(&mut input);
assert_eq!(out, 3);
assert_eq!(input, vec![1, 2, 1]);
let mut input = vec![5, 4, 3, 2];
let out = OutputMutableModelRunner::run_mutable_model(&mut input);
assert_eq!(out, 5);
assert_eq!(input, vec![5, 4, 3, 2, 1]);
}
declare_family! {
root: pub OutputFamilyRoot,
child: [Run]
}
define_family! {
root: OutputFamilyRoot,
family: OutputFamily,
input: Input,
output: Output,
context: (),
bounds: [
Input: Into<u8>,
Output: From<u8>,
],
child: [
Run => PureNoCtxSingleSingle,
],
}
struct OutputFamilyRunner;
impl OutputFamilyRunner {
plugin_output! {
pub fn run_family_model,
input: u8,
output: u8,
root: OutputFamilyRoot,
family: OutputFamily,
child: Run,
context: UnitContextProvider,
}
}
#[test]
fn plugin_output_immutable_family_arm_works() {
assert_eq!(OutputFamilyRunner::run_family_model(10), 11);
assert_eq!(OutputFamilyRunner::run_family_model(0), 1);
}
declare_family! {
root: mut pub OutputMutFamilyRoot,
child: [RunMut]
}
define_family! {
root: OutputMutFamilyRoot,
family: OutputMutFamily,
input: Input,
output: Output,
context: (),
bounds: [
Input: From<Vec<u8>> + Into<Vec<u8>> + Default,
Output: From<usize>,
],
child: [
RunMut => MutNoCtxSingleSingle,
],
}
struct OutputMutFamilyRunner;
impl OutputMutFamilyRunner {
plugin_output! {
pub fn run_mut_family_model,
input: mut Vec<u8>,
output: usize,
root: OutputMutFamilyRoot,
family: OutputMutFamily,
child: RunMut,
context: UnitContextProvider,
}
}
#[test]
fn plugin_output_mutable_family_arm_works() {
let mut input = vec![1, 2];
let out = OutputMutFamilyRunner::run_mut_family_model(&mut input);
assert_eq!(out, 3);
assert_eq!(input, vec![1, 2, 1]);
let mut input = vec![9];
let out = OutputMutFamilyRunner::run_mut_family_model(&mut input);
assert_eq!(out, 2);
assert_eq!(input, vec![9, 1]);
}
declare_family! {
root: pub ImmutableDeclaredRoot,
child: [DeclaredRun, DeclaredEcho]
}
struct ImmutableDeclaredFamily;
impl ImmutableDeclaredRoot<u8, (), u8> for ImmutableDeclaredFamily {
type DeclaredRun = PureNoCtxSingleSingle;
type DeclaredEcho = PureNoCtxSingleSingle;
}
fn run_declared_immutable_family(input: u8) -> u8 {
let model =
<ImmutableDeclaredFamily as ImmutableDeclaredRoot<u8, (), u8>>::DeclaredRun::default();
let context = ();
<<ImmutableDeclaredFamily as ImmutableDeclaredRoot<u8, (), u8>>::DeclaredRun
as PurePluginModel<u8, (), u8>>::compute(&model, input, &context)
}
#[test]
fn declare_family_immutable_arm_creates_root_and_children() {
assert_eq!(run_declared_immutable_family(10), 11);
assert_eq!(run_declared_immutable_family(0), 1);
}
#[test]
fn declare_family_immutable_arm_child_markers_exist() {
let _run = DeclaredRun;
let _echo = DeclaredEcho;
}
declare_family! {
root: mut pub MutableDeclaredRoot,
child: [DeclaredRunMut, DeclaredNormalize]
}
struct MutableDeclaredFamily;
impl MutableDeclaredRoot<Vec<u8>, (), usize> for MutableDeclaredFamily {
type DeclaredRunMut = MutNoCtxSingleSingle;
type DeclaredNormalize = MutNoCtxSingleSingle;
}
fn run_declared_mutable_family(mut input: Vec<u8>) -> (Vec<u8>, usize) {
let model =
<MutableDeclaredFamily as MutableDeclaredRoot<Vec<u8>, (), usize>>::DeclaredRunMut::default();
let context = ();
let out =
<<MutableDeclaredFamily as MutableDeclaredRoot<Vec<u8>, (), usize>>::DeclaredRunMut
as MutablePluginModel<Vec<u8>, (), usize>>::compute_mut(
&model,
&mut input,
&context,
);
(input, out)
}
#[test]
fn declare_family_mutable_arm_creates_root_and_children() {
let (input, out) = run_declared_mutable_family(vec![1, 2]);
assert_eq!(input, vec![1, 2, 1]);
assert_eq!(out, 3);
}
#[test]
fn declare_family_mutable_arm_child_markers_exist() {
let _run = DeclaredRunMut;
let _normalize = DeclaredNormalize;
}
declare_family! {
root: pub DefFamCtxSingleSingleRoot,
child: [DefFamCtxSingleSingleChild]
}
define_family! {
root: DefFamCtxSingleSingleRoot,
family: DefFamCtxSingleSingleFamily,
input: Input,
output: Output,
context: BasicConfig,
bounds: [Input: Into<u8>, Output: From<u8>],
child: [
DefFamCtxSingleSingleChild => PureCtxSingleSingle,
],
}
fn run_define_family_ctx_single_single(input: u8) -> u8 {
let model = <DefFamCtxSingleSingleFamily as DefFamCtxSingleSingleRoot<
u8,
BasicConfig,
u8,
>>::DefFamCtxSingleSingleChild::default();
let ctx = BasicConfig { value: 10 };
<<DefFamCtxSingleSingleFamily as DefFamCtxSingleSingleRoot<u8, BasicConfig, u8>>
::DefFamCtxSingleSingleChild as PurePluginModel<u8, BasicConfig, u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_single_input_single_output_works() {
assert_eq!(run_define_family_ctx_single_single(10), 20);
assert_eq!(run_define_family_ctx_single_single(1), 11);
}
declare_family! {
root: pub DefFamCtxSingleTupleRoot,
child: [DefFamCtxSingleTupleChild]
}
define_family! {
root: DefFamCtxSingleTupleRoot,
family: DefFamCtxSingleTupleFamily,
input: Input,
output: (OutA, OutB),
context: BasicConfig,
bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
child: [
DefFamCtxSingleTupleChild => PureCtxSingleTuple,
],
}
fn run_define_family_ctx_single_tuple(input: u8) -> (u8, u8) {
let model = <DefFamCtxSingleTupleFamily as DefFamCtxSingleTupleRoot<
u8,
BasicConfig,
(u8, u8),
>>::DefFamCtxSingleTupleChild::default();
let ctx = BasicConfig { value: 1 };
<<DefFamCtxSingleTupleFamily as DefFamCtxSingleTupleRoot<u8, BasicConfig, (u8, u8)>>
::DefFamCtxSingleTupleChild as PurePluginModel<u8, BasicConfig, (u8, u8)>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_single_input_tuple_output_works() {
assert_eq!(run_define_family_ctx_single_tuple(5), (5, 6));
assert_eq!(run_define_family_ctx_single_tuple(1), (1, 2));
}
declare_family! {
root: pub DefFamCtxTupleSingleRoot,
child: [DefFamCtxTupleSingleChild]
}
define_family! {
root: DefFamCtxTupleSingleRoot,
family: DefFamCtxTupleSingleFamily,
input: (InpA, InpB),
output: Output,
context: BasicConfig,
bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
child: [
DefFamCtxTupleSingleChild => PureCtxTupleSingle,
],
}
fn run_define_family_ctx_tuple_single(input: (u8, u8)) -> u8 {
let model = <DefFamCtxTupleSingleFamily as DefFamCtxTupleSingleRoot<
(u8, u8),
BasicConfig,
u8,
>>::DefFamCtxTupleSingleChild::default();
let ctx = BasicConfig { value: 10 };
<<DefFamCtxTupleSingleFamily as DefFamCtxTupleSingleRoot<(u8, u8), BasicConfig, u8>>
::DefFamCtxTupleSingleChild as PurePluginModel<(u8, u8), BasicConfig, u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_tuple_input_single_output_works() {
assert_eq!(run_define_family_ctx_tuple_single((10, 10)), 30);
assert_eq!(run_define_family_ctx_tuple_single((5, 30)), 45);
}
declare_family! {
root: pub DefFamCtxTupleTupleRoot,
child: [DefFamCtxTupleTupleChild]
}
define_family! {
root: DefFamCtxTupleTupleRoot,
family: DefFamCtxTupleTupleFamily,
input: (InpA, InpB),
output: (OutA, OutB),
context: BasicConfig,
bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
child: [
DefFamCtxTupleTupleChild => PureCtxTupleTuple,
],
}
fn run_define_family_ctx_tuple_tuple(input: (u8, u8)) -> (u8, u8) {
let model = <DefFamCtxTupleTupleFamily as DefFamCtxTupleTupleRoot<
(u8, u8),
BasicConfig,
(u8, u8),
>>::DefFamCtxTupleTupleChild::default();
let ctx = BasicConfig { value: 5 };
<<DefFamCtxTupleTupleFamily as DefFamCtxTupleTupleRoot<(u8, u8), BasicConfig, (u8, u8)>>
::DefFamCtxTupleTupleChild as PurePluginModel<(u8, u8), BasicConfig, (u8, u8)>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_tuple_input_tuple_output_works() {
assert_eq!(run_define_family_ctx_tuple_tuple((5, 10)), (10, 15));
assert_eq!(run_define_family_ctx_tuple_tuple((1, 0)), (6, 5));
}
declare_family! {
root: pub DefFamNoCtxSingleSingleRoot,
child: [DefFamNoCtxSingleSingleChild]
}
define_family! {
root: DefFamNoCtxSingleSingleRoot,
family: DefFamNoCtxSingleSingleFamily,
input: Input,
output: Output,
bounds: [Input: Into<u8>, Output: From<u8>],
child: [
DefFamNoCtxSingleSingleChild => PureNoCtxSingleSingle,
],
}
fn run_define_family_no_ctx_single_single(input: u8) -> u8 {
let model =
<DefFamNoCtxSingleSingleFamily as DefFamNoCtxSingleSingleRoot<u8, (), u8>>
::DefFamNoCtxSingleSingleChild::default();
let ctx = ();
<<DefFamNoCtxSingleSingleFamily as DefFamNoCtxSingleSingleRoot<u8, (), u8>>
::DefFamNoCtxSingleSingleChild as PurePluginModel<u8, (), u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_no_context_single_input_single_output_works() {
assert_eq!(run_define_family_no_ctx_single_single(10), 11);
assert_eq!(run_define_family_no_ctx_single_single(0), 1);
}
declare_family! {
root: pub DefFamNoCtxSingleTupleRoot,
child: [DefFamNoCtxSingleTupleChild]
}
define_family! {
root: DefFamNoCtxSingleTupleRoot,
family: DefFamNoCtxSingleTupleFamily,
input: Input,
output: (OutA, OutB),
bounds: [Input: Into<u8>, OutA: From<u8>, OutB: From<u8>],
child: [
DefFamNoCtxSingleTupleChild => PureNoCtxSingleTuple,
],
}
fn run_define_family_no_ctx_single_tuple(input: u8) -> (u8, u8) {
let model = <DefFamNoCtxSingleTupleFamily as DefFamNoCtxSingleTupleRoot<
u8,
(),
(u8, u8),
>>::DefFamNoCtxSingleTupleChild::default();
let ctx = ();
<<DefFamNoCtxSingleTupleFamily as DefFamNoCtxSingleTupleRoot<u8, (), (u8, u8)>>
::DefFamNoCtxSingleTupleChild as PurePluginModel<u8, (), (u8, u8)>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_no_context_single_input_tuple_output_works() {
assert_eq!(run_define_family_no_ctx_single_tuple(10), (10, 11));
assert_eq!(run_define_family_no_ctx_single_tuple(0), (0, 1));
}
declare_family! {
root: pub DefFamNoCtxTupleSingleRoot,
child: [DefFamNoCtxTupleSingleChild]
}
define_family! {
root: DefFamNoCtxTupleSingleRoot,
family: DefFamNoCtxTupleSingleFamily,
input: (InpA, InpB),
output: Output,
bounds: [InpA: Into<u8>, InpB: Into<u8>, Output: From<u8>],
child: [
DefFamNoCtxTupleSingleChild => PureNoCtxTupleSingle,
],
}
fn run_define_family_no_ctx_tuple_single(input: (u8, u8)) -> u8 {
let model = <DefFamNoCtxTupleSingleFamily as DefFamNoCtxTupleSingleRoot<
(u8, u8),
(),
u8,
>>::DefFamNoCtxTupleSingleChild::default();
let ctx = ();
<<DefFamNoCtxTupleSingleFamily as DefFamNoCtxTupleSingleRoot<(u8, u8), (), u8>>
::DefFamNoCtxTupleSingleChild as PurePluginModel<(u8, u8), (), u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_no_context_tuple_input_single_output_works() {
assert_eq!(run_define_family_no_ctx_tuple_single((10, 11)), 21);
assert_eq!(run_define_family_no_ctx_tuple_single((0, 5)), 5);
}
declare_family! {
root: pub DefFamNoCtxTupleTupleRoot,
child: [DefFamNoCtxTupleTupleChild]
}
define_family! {
root: DefFamNoCtxTupleTupleRoot,
family: DefFamNoCtxTupleTupleFamily,
input: (InpA, InpB),
output: (OutA, OutB),
bounds: [InpA: Into<u8>, InpB: Into<u8>, OutA: From<u8>, OutB: From<u8>],
child: [
DefFamNoCtxTupleTupleChild => PureNoCtxTupleTuple,
],
}
fn run_define_family_no_ctx_tuple_tuple(input: (u8, u8)) -> (u8, u8) {
let model = <DefFamNoCtxTupleTupleFamily as DefFamNoCtxTupleTupleRoot<
(u8, u8),
(),
(u8, u8),
>>::DefFamNoCtxTupleTupleChild::default();
let ctx = ();
<<DefFamNoCtxTupleTupleFamily as DefFamNoCtxTupleTupleRoot<(u8, u8), (), (u8, u8)>>
::DefFamNoCtxTupleTupleChild as PurePluginModel<(u8, u8), (), (u8, u8)>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_no_context_tuple_input_tuple_output_works() {
assert_eq!(run_define_family_no_ctx_tuple_tuple((5, 10)), (50, 100));
assert_eq!(run_define_family_no_ctx_tuple_tuple((1, 0)), (10, 0));
}
plugin_model! {
name: pub PureGenericCtxSingleSingle,
input: Input,
output: Output,
others: [T],
context: GenericConfig<T>,
bounds: [Input: Into<u8>, Output: From<u8>, T: Into<u8> + Clone],
compute: |input, ctx| {
Output::from(input.into() + ctx.value.clone().into())
},
}
declare_family! {
root: pub DefFamCtxMarkerRoot,
child: [DefFamCtxMarkerChild]
}
define_family! {
root: DefFamCtxMarkerRoot,
family: DefFamCtxMarkerFamily,
input: Input,
output: Output,
context: GenericConfig<T>,
marker: [T],
bounds: [Input: Into<u8>, Output: From<u8>, T: Into<u8> + Clone],
child: [
DefFamCtxMarkerChild => PureGenericCtxSingleSingle,
],
}
fn run_define_family_ctx_marker(input: u8) -> u8 {
let model =
<DefFamCtxMarkerFamily as DefFamCtxMarkerRoot<u8, GenericConfig<u8>, u8>>
::DefFamCtxMarkerChild::default();
let ctx = GenericConfig { value: 7u8 };
<<DefFamCtxMarkerFamily as DefFamCtxMarkerRoot<u8, GenericConfig<u8>, u8>>
::DefFamCtxMarkerChild as PurePluginModel<u8, GenericConfig<u8>, u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_marker_works() {
assert_eq!(run_define_family_ctx_marker(10), 17);
assert_eq!(run_define_family_ctx_marker(0), 7);
}
plugin_model! {
name: pub PureGenericBorrowCtx,
input: Input,
output: Output,
others: [T],
context: GenericConfig<T>,
bounds: [Input: AsRef<[u8]>, Output: From<usize>, T: Clone],
compute: |input, _ctx| {
Output::from(input.as_ref().len())
},
}
declare_family! {
root: pub DefFamCtxBorrowMarkerRoot,
child: [DefFamCtxBorrowMarkerChild]
}
define_family! {
root: DefFamCtxBorrowMarkerRoot,
family: DefFamCtxBorrowMarkerFamily,
borrow: ['a],
input: Input,
output: Output,
context: GenericConfig<T>,
marker: [T],
bounds: [Input: AsRef<[u8]> + 'a, Output: From<usize>, T: Clone],
child: [
DefFamCtxBorrowMarkerChild => PureGenericBorrowCtx,
],
}
fn run_define_family_ctx_borrow_marker<'a>(input: &'a [u8]) -> usize {
let model = <DefFamCtxBorrowMarkerFamily<'a> as DefFamCtxBorrowMarkerRoot<
&'a [u8],
GenericConfig<u8>,
usize,
>>::DefFamCtxBorrowMarkerChild::default();
let ctx = GenericConfig { value: 99u8 };
<<DefFamCtxBorrowMarkerFamily<'a> as DefFamCtxBorrowMarkerRoot<&'a [u8], GenericConfig<u8>, usize>>
::DefFamCtxBorrowMarkerChild as PurePluginModel<&'a [u8], GenericConfig<u8>, usize>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_with_context_borrow_and_marker_works() {
let data = [1u8, 2, 3, 4];
assert_eq!(run_define_family_ctx_borrow_marker(&data), 4);
let data = [9u8];
assert_eq!(run_define_family_ctx_borrow_marker(&data), 1);
}
declare_family! {
root: pub DefFamNoCtxMultiChildRoot,
child: [DefFamNoCtxMultiChildA, DefFamNoCtxMultiChildB]
}
define_family! {
root: DefFamNoCtxMultiChildRoot,
family: DefFamNoCtxMultiChildFamily,
input: Input,
output: Output,
bounds: [Input: Into<u8>, Output: From<u8>],
child: [
DefFamNoCtxMultiChildA => PureNoCtxSingleSingle,
DefFamNoCtxMultiChildB => PureNoCtxSingleSingle,
],
}
fn run_define_family_no_ctx_multi_child_a(input: u8) -> u8 {
let model =
<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
::DefFamNoCtxMultiChildA::default();
let ctx = ();
<<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
::DefFamNoCtxMultiChildA as PurePluginModel<u8, (), u8>>
::compute(&model, input, &ctx)
}
fn run_define_family_no_ctx_multi_child_b(input: u8) -> u8 {
let model =
<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
::DefFamNoCtxMultiChildB::default();
let ctx = ();
<<DefFamNoCtxMultiChildFamily as DefFamNoCtxMultiChildRoot<u8, (), u8>>
::DefFamNoCtxMultiChildB as PurePluginModel<u8, (), u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_multiple_children_work() {
assert_eq!(run_define_family_no_ctx_multi_child_a(10), 11);
assert_eq!(run_define_family_no_ctx_multi_child_b(0), 1);
let _a = DefFamNoCtxMultiChildA;
let _b = DefFamNoCtxMultiChildB;
}
plugin_model! {
name: pub PureNoCtxSingleSingleDouble,
input: Input,
output: Output,
bounds: [Input: Into<u8>, Output: From<u8>],
compute: |input, _ctx| {
let x = input.into();
Output::from(x * 2)
}
}
declare_family! {
root: pub DefFamNoCtxMultiChildDistinctRoot,
child: [DefFamNoCtxMultiChildInc, DefFamNoCtxMultiChildDouble]
}
define_family! {
root: DefFamNoCtxMultiChildDistinctRoot,
family: DefFamNoCtxMultiChildDistinctFamily,
input: Input,
output: Output,
bounds: [Input: Into<u8>, Output: From<u8>],
child: [
DefFamNoCtxMultiChildInc => PureNoCtxSingleSingle,
DefFamNoCtxMultiChildDouble => PureNoCtxSingleSingleDouble,
],
}
fn run_define_family_no_ctx_multi_child_inc(input: u8) -> u8 {
let model = <DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<
u8,
(),
u8,
>>::DefFamNoCtxMultiChildInc::default();
let ctx = ();
<<DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<u8, (), u8>>
::DefFamNoCtxMultiChildInc as PurePluginModel<u8, (), u8>>
::compute(&model, input, &ctx)
}
fn run_define_family_no_ctx_multi_child_double(input: u8) -> u8 {
let model = <DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<
u8,
(),
u8,
>>::DefFamNoCtxMultiChildDouble::default();
let ctx = ();
<<DefFamNoCtxMultiChildDistinctFamily as DefFamNoCtxMultiChildDistinctRoot<u8, (), u8>>
::DefFamNoCtxMultiChildDouble as PurePluginModel<u8, (), u8>>
::compute(&model, input, &ctx)
}
#[test]
fn define_family_multiple_children_with_distinct_models_work() {
assert_eq!(run_define_family_no_ctx_multi_child_inc(10), 11);
assert_eq!(run_define_family_no_ctx_multi_child_inc(0), 1);
assert_eq!(run_define_family_no_ctx_multi_child_double(10), 20);
assert_eq!(run_define_family_no_ctx_multi_child_double(3), 6);
let _inc = DefFamNoCtxMultiChildInc;
let _double = DefFamNoCtxMultiChildDouble;
}
#[test]
fn phantom_struct_no_lifetime_no_generic_compiles() {
__phantom_struct!(pub Plain [] []);
let _x = Plain;
}
#[test]
fn phantom_struct_lifetime_only_compiles() {
__phantom_struct!(pub WithLt ['a] []);
let _x: WithLt<'static>;
}
#[test]
fn phantom_struct_generic_only_compiles() {
__phantom_struct!(pub WithGen [] [T]);
let _x: WithGen<u8>;
}
#[test]
fn phantom_struct_lifetime_and_generic_compiles() {
__phantom_struct!(pub WithLtGen ['a] [T]);
let _x: WithLtGen<'static, u8>;
}
#[test]
fn phantom_struct_generic_is_covariant() {
__phantom_struct!(pub CovGen [] [T]);
fn accepts<'a>(_: CovGen<&'a str>) {}
let x: CovGen<&'static str> = CovGen(PhantomData);
accepts(x);
}
#[test]
fn phantom_struct_lifetime_and_generic_is_covariant() {
__phantom_struct!(pub CovLtGen ['a] [T]);
fn accepts<'a>(_: CovLtGen<'a, &'a str>) {}
let x: CovLtGen<'static, &'static str> = CovLtGen(PhantomData);
accepts(x);
}
#[test]
fn phantom_struct_field_types_are_correct() {
__phantom_struct!(pub LtField ['a] []);
let _: LtField<'static> = LtField(PhantomData::<(&'static (),)>);
__phantom_struct!(pub GenField [] [T]);
let _: GenField<u8> = GenField(PhantomData::<(u8,)>);
__phantom_struct!(pub LtGenField ['a] [T]);
let _: LtGenField<'static, u8> = LtGenField(PhantomData::<(u8, &'static ())>);
}
}