use derive_deftly::{define_derive_deftly, define_derive_deftly_module};
define_derive_deftly! {
export Constructor for struct, meta_quoted rigorous, beta_deftly:
${define CONSTRUCTOR_NAME $<$tname Constructor>}
${define CONSTRUCTOR $<$ttype Constructor>}
${defcond F_DEFAULT_EXPR fmeta(constructor(default))}
${defcond F_DEFAULT_TRAIT not(fmeta(constructor))}
${defcond F_REQUIRED not(any(F_DEFAULT_EXPR, F_DEFAULT_TRAIT))}
${for fields {
${loop_exactly_1 "need a `__non_exhaustive` field (instead of `#[non_exhaustive]`"}
${when all(
approx_equal($fname, __non_exhaustive),
approx_equal({}, ${tattrs non_exhaustive}),
)}
}}
$ $ $ $ $ $ $ $ $ $ $ $ $ ${for fields { ${when any(fmeta(constructor(default)), not(fmeta(constructor)))}
$ }}
$ ${for fields { ${when not(any(fmeta(constructor(default)), not(fmeta(constructor))))}
$ }}
$ $ $ #[allow(clippy::exhaustive_structs)]
$tvis struct $CONSTRUCTOR_NAME<$tdefgens> where $twheres { $(
${when F_REQUIRED}
${fattrs doc}
$fdefvis $fname: $ftype,
) }
impl<$tgens> $CONSTRUCTOR where $twheres {
$ $ $ $ $tvis fn construct(self) -> $ttype {
$tname { $(
$fname: ${select1
F_REQUIRED {
self.$fname
}
F_DEFAULT_TRAIT {
<$ftype as ::std::default::Default>::default()
}
F_DEFAULT_EXPR {
${fmeta(constructor(default)) as expr}
}
},
) }
}
}
impl<$tgens> From<$CONSTRUCTOR> for $ttype where $twheres {
fn from(constructor: $CONSTRUCTOR) -> $ttype {
constructor.construct()
}
}
}
define_derive_deftly! {
export ConstantString for struct, beta_deftly, meta_quoted retain:
${define LET_CONSTANT {
let constant: &str = ${tmeta(constant_string) as expr};
}}
${define FMT { ::std::fmt} }
${define ERR { $crate::ExpectedConstantString } }
impl<$tgens> $FMT::Display for $ttype where $twheres {
fn fmt(&self, f: &mut $FMT::Formatter) -> $FMT::Result {
$LET_CONSTANT
$FMT::Display::fmt(constant, f)
}
}
impl<$tgens> ::std::str::FromStr for $ttype where $twheres {
type Err = $ERR;
fn from_str(s: &str) -> ::std::result::Result<Self, $ERR> {
$LET_CONSTANT
if s == constant {
Ok(::std::default::Default::default())
} else {
Err($ERR {
got: s.to_string(),
expected: constant,
})
}
}
}
impl<$tgens> $crate::NormalItemArgument for $ttype where $twheres {}
}
#[macro_export]
macro_rules! define_constant_string {
{
$( #[ $($attr:tt)* ] )*
$name:ident = $string:expr;
} => {
$( #[ $($attr)* ] )*
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive($crate::derive_deftly::Deftly)]
#[derive_deftly(ConstantString)]
#[deftly(constant_string = ($string))]
#[allow(clippy::exhaustive_structs)]
pub struct $name;
};
}
/// Macro to help check that netdoc items in a derive input are in the right order
#[doc(hidden)]
#[macro_export]
macro_rules! netdoc_ordering_check {
{ } => { compile_error!("netdoc must have an intro item so cannot be empty"); };
{ $k0:ident $f0:ident $k1:ident $f1:ident $($rest:tt)* } => {
$crate::netdoc_ordering_check! { <=? $k0 $k1 $f1 }
$crate::netdoc_ordering_check! { $k1 $f1 $($rest)* }
};
{ $k0:ident $f0:ident } => {};
{ <=? intro $any:ident $f1:ident } => {};
{ <=? normal normal $f1:ident } => {};
{ <=? normal subdoc $f1:ident } => {};
{ <=? subdoc subdoc $f1:ident } => {};
{ <=? $k0:ident $k1:ident $f1:ident } => {
compile_error!(concat!(
"in netdoc, ", stringify!($k1)," field ", stringify!($f1),
" may not come after ", stringify!($k0),
));
};
}
define_derive_deftly_module! {
NetdocDeriveAnyCommon beta_deftly:
${define EMIT_DEBUG_PLACEHOLDER {
${if tmeta(netdoc(debug)) {
use std::io::Write as _;
writeln!(
std::io::stderr().lock(),
${concat "#[deftly(netdoc(debug))] applied to " $tname},
).expect("write to stderr failed");
}}
}}
${define DOC_DEBUG_PLACEHOLDER {
}}
}
define_derive_deftly_module! {
NetdocSomeItemsDeriveCommon beta_deftly:
${defcond F_FLATTEN fmeta(netdoc(flatten))}
${defcond F_SKIP fmeta(netdoc(skip))}
${defcond F_NORMAL not(any(F_SIGNATURE, F_INTRO, F_FLATTEN, F_SUBDOC, F_SKIP))}
${define F_KEYWORD_STR { ${concat
${if any(F_FLATTEN, F_SUBDOC, F_SKIP) {
${if F_INTRO {
${error "#[deftly(netdoc(subdoc))] (flatten) and (skip) not supported for intro items"}
} else {
${error "internal error, subdoc or skip KeywordRef"}
}}
}}
${fmeta(netdoc(keyword)) as str,
default ${concat ${kebab_case $fname}}}
}}}
${define F_KEYWORD_REPORT ${concat
${if any(F_FLATTEN, F_SUBDOC, F_SKIP) { $fname }
else { $F_KEYWORD_STR }}
}}
${define F_KEYWORD { (KeywordRef::new_const($F_KEYWORD_STR)) }}
}
define_derive_deftly_module! {
NetdocEntireDeriveCommon beta_deftly:
${defcond T_SIGNATURES false}
${defcond F_INTRO approx_equal($findex, 0)}
${defcond F_SUBDOC fmeta(netdoc(subdoc))}
${defcond F_SIGNATURE T_SIGNATURES}
${define FIELD_ORDERING_CHECK {
${if not(T_SIGNATURES) { netdoc_ordering_check! {
$(
${when not(F_SKIP)}
${select1
F_INTRO { intro }
F_NORMAL { normal }
F_FLATTEN { normal }
F_SUBDOC { subdoc }
}
$fname
)
}
}}
}}
}
define_derive_deftly_module! {
NetdocFieldsDeriveCommon beta_deftly:
${defcond F_INTRO false}
${defcond F_SUBDOC false}
${defcond F_SIGNATURE false}
${define DOC_NETDOC_FIELDS_DERIVE_SUPPORTED {
}}
}
define_derive_deftly_module! {
NetdocItemDeriveCommon beta_deftly:
${defcond F_REST fmeta(netdoc(rest))}
${defcond F_OBJECT fmeta(netdoc(object))}
${defcond F_SKIP fmeta(netdoc(skip))}
${defcond F_NORMAL not(any(F_REST, F_OBJECT, F_SKIP))}
${defcond T_IS_SIGNATURE tmeta(netdoc(signature))}
}