use crate::data::{DataKind, FromData, IntoData};
use crate::error::Result;
use super::DevCtx;
#[macro_export]
macro_rules! dev_def {
() => {
};
}
#[macro_export]
macro_rules! command_def {
( @build: () -> { $($output:tt)* } ) => {
CommandDef {
$($output)*
}
};
( @build: (name: $value:literal $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* name: ::std::borrow::Cow::Borrowed($value), })
};
( @build: (name: $value:expr $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* name: $value.into(), })
};
( @build: (in_description: $value:literal $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* in_description: ::std::borrow::Cow::Borrowed($value), })
};
( @build: (in_description: $value:expr $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* in_description: $value.into(), })
};
( @build: (out_description: $value:literal $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* out_description: ::std::borrow::Cow::Borrowed($value), })
};
( @build: (out_description: $value:expr $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* out_description: $value.into(), })
};
( @build: (exec: $value:expr $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {
$crate::command_def!(@build: ($($($input)*)?) -> { $($output)* exec: $value, })
};
( @build: (exec ($($attr:ident),*): $value:expr $(,$($input:tt)*)?) -> { $($output:tt)* } ) => {{
$crate::command_def!(@build: ($($($input)*)?) -> {
$($output)*
in_kind: $crate::command_def!(@exec_check: ($($attr),*), $value, false),
out_kind: $crate::command_def!(@exec_check: ($($attr),*), $value, true),
exec: |ctx, name, input, output| {
Box::pin(async move {
let input = $crate::data::FromData::from_data(input) .map_err(|e| $crate::error::Error::new($crate::error::ErrorKind::InvalidData)
.with_append_description("Failed to parse input data of command")
.with_append_description(format!("{e}")))?;
let data = $crate::command_def!(@exec: ($($attr),*), $value, ctx, name, input)?;
*output = data;
Ok(())
})
},
})
}};
( @exec_check: (ref), $func:expr, $out:literal ) => {
$crate::server::macros::__command_def_check_ref($func, $out)
};
( @exec_check: (mut), $func:expr, $out:literal ) => {
$crate::server::macros::__command_def_check_mut($func, $out)
};
( @exec_check: (ref, ctx), $func:expr, $out:literal ) => {
$crate::server::macros::__command_def_check_ref_ctx($func, $out)
};
( @exec_check: (mut, ctx), $func:expr, $out:literal ) => {
$crate::server::macros::__command_def_check_mut_ctx($func, $out)
};
( @exec: (ref), $func:expr, $ctx:expr, $name:expr, $data:expr ) => {{
let model = $ctx.read_model().await;
let res = ($func)(&*model, $name, $data).await;
res.map(|res| $crate::data::IntoData::into_data(res).into_owned())
}};
( @exec: (mut), $func:expr, $ctx:expr, $name:expr, $data:expr ) => {{
let mut model = $ctx.write_model().await;
let res = ($func)(&mut *model, $name, $data).await;
res.map(|res| $crate::data::IntoData::into_data(res).into_owned())
}};
( @exec: (ref, ctx), $func:expr, $ctx:expr, $name:expr, $data:expr ) => {{
let model = $ctx.read_model().await;
let res = ($func)(&*model, $ctx, $name, $data).await;
res.map(|res| $crate::data::IntoData::into_data(res).into_owned())
}};
( @exec: (mut, ctx), $func:expr, $ctx:expr, $name:expr, $data:expr ) => {{
let mut model = $ctx.write_model().await;
let res = ($func)(&mut *model, $ctx, $name, $data).await;
res.map(|res| $crate::data::IntoData::into_data(res).into_owned())
}};
( $($input:tt)* ) => { $crate::command_def!(@build: ($($input)*) -> { }) };
}
#[doc(hidden)]
pub const fn __command_def_check_ref<'m, 'i, Model, I, O, F>(_func: fn(&'m Model, &'i str, I) -> F, out: bool) -> DataKind
where
I: FromData<'i>,
O: IntoData<'m>,
F: Future<Output = Result<O>> + 'm + 'i,
{
if out { O::DATA_KIND } else { I::DATA_KIND }
}
#[doc(hidden)]
pub const fn __command_def_check_mut<'m, 'i, Model, I, O, F>(_func: fn(&'m mut Model, &'i str, I) -> F, out: bool) -> DataKind
where
I: FromData<'i>,
O: IntoData<'m>,
F: Future<Output = Result<O>> + 'm + 'i,
{
if out { O::DATA_KIND } else { I::DATA_KIND }
}
#[doc(hidden)]
pub const fn __command_def_check_ref_ctx<'m, 'c, 'i, Model, I, O, F>(_func: fn(&'m Model, &'c DevCtx<Model>, &'i str, I) -> F, out: bool) -> DataKind
where
I: FromData<'i>,
O: IntoData<'m>,
F: Future<Output = Result<O>> + 'm + 'i + 'c,
{
if out { O::DATA_KIND } else { I::DATA_KIND }
}
#[doc(hidden)]
pub const fn __command_def_check_mut_ctx<'m, 'c, 'i, Model, I, O, F>(_func: fn(&'m mut Model, &'c DevCtx<Model>, &'i str, I) -> F, out: bool) -> DataKind
where
I: FromData<'i>,
O: IntoData<'m>,
F: Future<Output = Result<O>> + 'm + 'i + 'c,
{
if out { O::DATA_KIND } else { I::DATA_KIND }
}