use std::borrow::Cow;
use specta::datatype::DataType;
#[macro_export]
macro_rules! branded {
(
$(#[$attr:meta])*
$vis:vis struct $ident:ident<$($generic:ident),+ $(,)?> ( $ty:ty ) $(as $ts_name:literal)?
) => {
$(#[$attr])*
$vis struct $ident<$($generic),+>($ty);
impl<$($generic: specta::Type),+> specta::Type for $ident<$($generic),+> {
fn definition(types: &mut specta::Types) -> specta::datatype::DataType {
let ty = <$ty as specta::Type>::definition(types);
let brand: &'static str = branded!(@brand $ident $( $ts_name )?);
specta::datatype::DataType::Reference(
specta::datatype::Reference::opaque(
$crate::Branded::new(std::borrow::Cow::Borrowed(brand), ty)
)
)
}
}
};
(
$(#[$attr:meta])*
$vis:vis struct $ident:ident ( $ty:ty ) $(as $ts_name:literal)?
) => {
$(#[$attr])*
$vis struct $ident($ty);
impl specta::Type for $ident {
fn definition(types: &mut specta::Types) -> specta::datatype::DataType {
let ty = <$ty as specta::Type>::definition(types);
let brand: &'static str = branded!(@brand $ident $( $ts_name )?);
specta::datatype::DataType::Reference(
specta::datatype::Reference::opaque(
$crate::Branded::new(std::borrow::Cow::Borrowed(brand), ty)
)
)
}
}
};
(@brand $ident:ident $ts_name:literal) => {
$ts_name
};
(@brand $ident:ident) => {
stringify!($ident)
};
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Branded {
brand: Cow<'static, str>,
ty: DataType,
}
impl Branded {
pub fn new(brand: impl Into<Cow<'static, str>>, ty: DataType) -> Self {
Self {
brand: brand.into(),
ty,
}
}
pub fn brand(&self) -> &Cow<'static, str> {
&self.brand
}
pub fn ty(&self) -> &DataType {
&self.ty
}
}