pub trait AsPart<T> {
fn as_part(&self) -> &T;
fn as_part_mut(&mut self) -> &mut T;
}
pub trait TryAsPart<T> {
fn try_as_part(&self) -> Option<&T>;
fn try_as_part_mut(&mut self) -> Option<&mut T>;
}
impl<T, X> TryAsPart<X> for T
where
T: AsPart<X>,
{
fn try_as_part(&self) -> Option<&X> {
Some(self.as_part())
}
fn try_as_part_mut(&mut self) -> Option<&mut X> {
Some(self.as_part_mut())
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! enable_if_part {
{(part) {$($b:tt)*}} => {$($b)*};
{() {$($b:tt)*}} => {};
}
#[macro_export]
macro_rules! compose {
{
$(#[$($meta_code:tt)*])?
$v:vis struct $name:ident {
$(
$(#[$attr:ident])? $vi:vis $field:ident: $field_type:ty
),*$(,)?
}
} => {
$(#[$($meta_code)*])?
$v struct $name {
$($vi $field: $field_type),*
}
$($crate::enable_if_part!{($($attr)?) {
impl $crate::compose::AsPart<$field_type> for $name {
fn as_part(&self) -> &$field_type {
&self.$field
}
fn as_part_mut(&mut self) -> &mut $field_type {
&mut self.$field
}
}
}})*
};
{
$(#[$($meta_code:tt)*])?
$v:vis enum $name:ident {
$($(#[$attr:ident])? $variant:ident$(($variant_type:ty))?),*$(,)?
}
} => {
$(#[$($meta_code)*])?
$v enum $name {
$($variant$(($variant_type))?),*
}
$($crate::enable_if_part!{($($attr)?) {
impl $crate::compose::TryAsPart<$($variant_type)?> for $name {
fn try_as_part(&self) -> Option<&$($variant_type)?> {
match self {
Self::$variant(value) => Some(value),
#[allow(unreachable_patterns)]
_ => None
}
}
fn try_as_part_mut(&mut self) -> Option<&mut $($variant_type)?> {
match self {
Self::$variant(value) => Some(value),
#[allow(unreachable_patterns)]
_ => None
}
}
}
}})*
};
}