#[macro_export]
macro_rules! urn_spec {
(
$(#[$meta:meta])*
$vis:vis $name:ident,
nid: $nid:literal,
nss_structure {
$($field:ident: { $($config:tt)* }),* $(,)?
}
$(, nss_format: $nss_format:literal)?
$(, transform: $transform_expr:expr)?
) => {
$(#[$meta])*
$vis struct $name;
impl $name {
fn spec_builder() -> $crate::utils::urn::UrnSpecBuilder {
let mut builder = $crate::utils::urn::UrnSpecBuilder::from($nid);
$(
builder = $crate::urn_spec!(@apply_field builder, $field, $($config)*);
)*
$(
builder = builder.nss_format($nss_format);
)?
builder
}
}
impl $crate::utils::urn::UrnSpec for $name {
const NID: &'static str = $nid;
$crate::urn_spec!(@generate_transform $($transform_expr)?);
fn validate<'a>(components: &dyn $crate::utils::urn::UrnComponents<'a>) -> Result<(), $crate::utils::urn::UrnValidationError> {
Self::spec_builder().validate(components)
}
fn build_nss<'a>(components: &dyn $crate::utils::urn::UrnComponents<'a>) -> Result<::std::borrow::Cow<'static, str>, $crate::utils::urn::UrnValidationError> {
let nss = Self::spec_builder().build_nss(components)?;
Ok(nss.into())
}
}
};
(@apply_field $builder:expr, $field:ident, $($config:tt)*) => {
$crate::urn_spec!(@parse_field_config $builder, $field, true, { $($config)* })
};
(@apply_required $builder:expr, $field:ident, $req:expr) => {
if $req {
$builder.field_required(stringify!($field))
} else {
$builder.field_optional(stringify!($field))
}
};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { required: true, $($rest:tt)* }) => {
$crate::urn_spec!(@parse_field_config $builder, $field, true, { $($rest)* })
};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { required: false, $($rest:tt)* }) => {
$crate::urn_spec!(@parse_field_config $builder, $field, false, { $($rest)* })
};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { value: $val:literal, $($rest:tt)* }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_const(stringify!($field), $val);
$crate::urn_spec!(@parse_field_config b, $field, $req, { $($rest)* })
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { value: $val:literal }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_const(stringify!($field), $val);
b
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { values: [$($opts:literal),+ $(,)?], $($rest:tt)* }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_oneof(stringify!($field), &[$($opts),+]);
$crate::urn_spec!(@parse_field_config b, $field, $req, { $($rest)* })
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { values: [$($opts:literal),+ $(,)?] }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_oneof(stringify!($field), &[$($opts),+]);
b
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { pattern: $pattern_expr:expr, $($rest:tt)* }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_pattern(stringify!($field), $pattern_expr);
$crate::urn_spec!(@parse_field_config b, $field, $req, { $($rest)* })
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { pattern: $pattern_expr:expr }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_pattern(stringify!($field), $pattern_expr);
b
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { sep: $sep:literal, $($rest:tt)* }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_nss_separator(stringify!($field), $sep);
$crate::urn_spec!(@parse_field_config b, $field, $req, { $($rest)* })
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { sep: $sep:literal }) => {{
let mut b = $crate::urn_spec!(@apply_required $builder, $field, $req);
b = b.field_nss_separator(stringify!($field), $sep);
b
}};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { required: true }) => {
$crate::urn_spec!(@apply_required $builder, $field, true)
};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { required: false }) => {
$crate::urn_spec!(@apply_required $builder, $field, false)
};
(@parse_field_config $builder:expr, $field:ident, $req:expr, { }) => {
$crate::urn_spec!(@apply_required $builder, $field, $req)
};
(@generate_transform $transform_expr:expr) => {
fn transform<'a>(components: &mut dyn $crate::utils::urn::UrnComponents<'a>) {
let closure: fn(&mut dyn $crate::utils::urn::UrnComponents<'a>) = $transform_expr;
closure(components);
}
};
(@generate_transform) => {
};
}