#[doc = crate::_tags!(code construction)]
#[doc = crate::_doc_location!("code/util")]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! impl_trait {
(FromStr<$err:ty> for
$( $type:ident $([$($decl:tt)+][$($args:tt)+ ])? $(where $($bounded:ident),+ )? );+
| $s:ident | $expr:expr) => {
$(
impl< $($($decl)*)? > $crate::FromStr for $type $(<$($args)*>)?
$(where $($bounded: $crate::FromStr,)+ )? {
type Err = $err;
fn from_str($s: &str) -> $crate::Result<Self, Self::Err> { $expr }
}
)+
};
(Hash for
$( $type:ident $([$($decl:tt)+][$($args:tt)+ ])? $(where $($bounded:ident),+ )?);+
| $self:ident, $state:ident | $expr:expr) => {
$(
impl< $($($decl)*)? > $crate::Hash for $type $(<$($args)*>)?
$(where $($bounded: $crate::Hash,)+ )? {
fn hash<__H: $crate::Hasher>(&$self, $state: &mut __H) { $expr }
}
)+
};
(PartialEq for
$( $type:ident $([$($decl:tt)+][$($args:tt)+ ])? $(where $($bounded:ident),+ )?);+
| $self:ident, $other:ident | $expr:expr) => {
$(
impl< $($($decl)*)? > $crate::PartialEq for $type $(<$($args)*>)?
$(where $($bounded: $crate::PartialEq,)+ )? {
fn eq(&$self, $other: &Self) -> bool { $expr }
}
)+
};
(fmt::Display+Error for
$( $type:ident $([$($decl:tt)+][$($args:tt)+ ])? $(where $($bounded:ident),+ )? );+
| $self:ident, $f:ident | $expr:expr) => {
$(
impl< $($($decl)*)? > $crate::Display for $type $(<$($args)*>)?
$(where $($bounded: $crate::Display,)+ )? {
fn fmt(&$self, $f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> { $expr }
}
impl< $($($decl)*)? > $crate::Error for $type $(<$($args)*>)? {}
)+
};
(fmt::$trait:ident for
$( $type:ident $([$($decl:tt)+][$($args:tt)+ ])? $(where $($bounded:ident),+ )? );+
| $self:ident, $f:ident | $expr:expr) => {
$(
impl< $($($decl)*)? > $crate::$trait for $type $(<$($args)*>)?
$(where $($bounded: $crate::$trait,)+ )? {
fn fmt(&$self, $f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> { $expr }
}
)+
};
}
#[doc(inline)]
pub use impl_trait;
#[cfg(test)]
#[rustfmt::skip]
mod tests {
use crate::{format_buf, ParseIntError, PhantomData};
struct S1 { v: i32 }
struct S2 { v: i32 }
struct GS1<T, U> { v1: T, v2: U }
struct GS2<'a, T, U, V> { v1: T, v2: U, _v3: PhantomData<&'a V> }
struct CGS3<T: Copy, const N: usize>([T; N]);
impl_trait!(FromStr<ParseIntError> for S1; S2 |s| Ok(Self { v : i32::from_str(s)? }) );
impl_trait!(PartialEq for S1; S2 |self, o| self.v == o.v);
impl_trait!(Hash for S1; S2 |self, s| self.v.hash(s));
impl_trait!(fmt::Debug for S1; S2 |self, f| {
write!(f, "S? {{ v: {:?} }}", self.v)
});
impl_trait!(fmt::Debug for
GS1[T, U][T, U] where T, U;
GS2['a, T, U, V]['a, T, U, V] where T, U |self, f| {
write!(f, "GS? {{ v1: {:?}, v2: {:?} }}", self.v1, self.v2)
});
impl_trait!(fmt::Debug for CGS3[T: Copy, const N: usize][T, N] where T |self, f| {
write!(f, "CGS3({:?})", self.0)
});
#[test]
fn impl_non_generic_debug() {
let s1 = S1 { v: 42 };
let s2 = S2 { v: 84 };
let mut buf = [0; 64];
assert_eq!(format_buf!(&mut buf, "{:?}", s1).unwrap(), "S? { v: 42 }");
assert_eq!(format_buf!(&mut buf, "{:?}", s2).unwrap(), "S? { v: 84 }");
}
#[test]
fn impl_generic_debug() {
let g1 = GS1 { v1: "hi", v2: "ho" };
let g2 = GS2 { v1: 3.14, v2: 159, _v3: PhantomData::<&'_ i32> };
let cg3 = CGS3(['a'; 2]);
let mut buf = [0; 64];
assert_eq!(format_buf!(&mut buf, "{:?}", g1).unwrap(), "GS? { v1: \"hi\", v2: \"ho\" }");
assert_eq!(format_buf!(&mut buf, "{:?}", g2).unwrap(), "GS? { v1: 3.14, v2: 159 }");
assert_eq!(format_buf!(&mut buf, "{:?}", cg3).unwrap(), "CGS3(['a', 'a'])");
}
}