/// For parsing impl blocks, /// passing the generic parameters unchanged to a callback macro. /// /// /// # Example /// /// ### Basic /// /// Basic examples of using this macro, and what it passes to a callback macro. /// /// For a more realistic example you can look [at the one below](#realistic-example) /// /// ```rust /// use core_extensions::impl_split; /// /// assert_eq!(hello(), "world"); /// /// // impl_split invokes `bar` here /// impl_split!{ /// crate::bar!{ /// // The first tokens passed to the `bar` macro /// hello "world" foo bar /// } /// ( /// #[foo] /// unsafe impl Trait for Type /// where U: Bar /// { /// fn hello(){} /// } /// ) /// } /// /// #[macro_export] /// macro_rules! bar { /// ( /// $fn_name:ident $returns:literal foo bar /// // the attributes /// (#[foo]) /// // the qualifiers (if `const impl` becomes a thing, i'll be included here) /// (unsafe) /// // the generic parameters /// (T: Foo) /// // the imlpemented trait. /// // If this not a trait impl, then `trait(....)` is not passed /// trait(Trait) /// // the type that this is an impl for /// type(Type) /// // inside the where clause, this always has a trailing comma /// (U: Bar,) /// // the body of the impl /// ({ fn hello() {} }) /// ) => { /// fn $fn_name() -> &'static str { /// $returns /// } /// } /// } /// /// ``` ///
/// /// ### More Realistic Example /// /// This only works in Rust 1.45.0 onwards. /// #[cfg_attr(not(feature = "rust_1_46"), doc = " ```ignore")] #[cfg_attr(feature = "rust_1_46", doc = " ```rust")] /// pub use core_extensions::{impl_split, rewrap_macro_parameters}; /// /// struct Wrapper(T, [u32; 3]); /// /// crate::constify_methods!{ /// impl Wrapper { /// pub fn get(&self) -> &T { /// &self.0 /// } /// pub fn sum(&self) -> u32 { /// let [a, b, c] = self.1; /// a + b + c /// } /// } /// } /// /// const SUM: u32 = Wrapper((), [3, 5, 8]).sum(); /// /// fn main() { /// assert_eq!(SUM, 16); /// } /// /// #[macro_export] /// macro_rules! constify_methods { /// ($impl:item) => { /// $crate::impl_split!{ /// $crate::__priv_constify_methods!{@parse_impl} /// ($impl) /// } /// } /// } /// /// #[doc(hidden)] /// #[macro_export] /// macro_rules! __priv_constify_methods{ /// ( /// @parse_impl /// ($(#[$impl_attr:meta])*) /// ($($qualifiers:tt)*) // Can be `unsafe` (maybe `const` in the future) /// ($($generics:tt)*) /// $( trait($($trait:tt)*) )? /// type ($($type:tt)*) /// ($($where:tt)*) /// ({ $($item:item)* }) /// ) => { /// $(#[$impl_attr])* /// $($qualifiers)* impl<$($generics)*> $($($trait)* for )? $($type)* /// where /// $($where)* /// { /// $crate::rewrap_macro_parameters!{$( /// $crate::__priv_constify_methods!{ /// @method /// $item /// ~$item /// } /// )*} /// } /// }; /// ( /// @method $item:item ( /// $(#[$attr:meta])* /// $vis:vis /// $(unsafe $(@$unsafe:tt@)?)? /// fn /// $($rem:tt)* /// ) /// ) => { /// $(#[$attr])* /// $vis const $(unsafe $(@$unsafe@)?)? fn /// $($rem)* /// }; /// (@method $item:item $paren:tt) => { /// $item /// }; /// } /// /// /// /// ``` /// #[cfg_attr(feature = "docsrs", doc(cfg(feature = "item_parsing")))] #[macro_export] macro_rules! impl_split { ($($args:tt)*) => { $crate::__coerce_item!{ $crate::__validate_macro_then_parentheses!{ ($($args)*) $crate::__::__priv_split_impl!{ $($args)* } } } }; } /// For parsing impl blocks, /// transforming the generic parameters to a form easily parsable by the callback macro. /// /// /// # Example /// /// ### Basic /// /// Basic examples of using this macro, and what it passes to a callback macro. /// /// For a more realistic example you can look [at the one below](#realistic-example) /// /// ```rust /// use core_extensions::impl_parse_generics; /// /// assert_eq!(hello(), "world"); /// /// // impl_parse_generics invokes `bar` here /// impl_parse_generics!{ /// crate::bar!{ /// // The first tokens passed to the `bar` macro /// hello "world" foo bar /// } /// ( /// #[foo] /// unsafe impl<'a: 'b, T: Foo, U, const X: usize> Trait for Type /// where U: Bar /// { /// fn hello(){} /// } /// ) /// } /// /// #[macro_export] /// macro_rules! bar { /// ( /// $fn_name:ident $returns:literal foo bar /// // the attributes /// (#[foo]) /// // the qualifiers (if `const impl` becomes a thing, i'll be included here) /// (unsafe) /// // The generic parameters are classified by kind /// // Bounds always have a trailing `+`` /// // Generic parameters always have a trailing `,` /// ( /// ('a:('b +),) // lifetimes /// (T:(Foo +), U:(),) // types /// (X: $const_ty:ty,) // constants /// ) /// // the imlpemented trait. /// // If this not a trait impl, then `trait(....)` is not passed /// trait(Trait) /// // the type that this is an impl for /// type(Type) /// // inside the where clause, this always has a trailing comma /// (U: Bar,) /// // the body of the impl /// ({ fn hello() {} }) /// ) => { /// fn $fn_name() -> &'static str { /// $returns /// } /// }; /// } /// /// ``` ///
/// /// ### More Realistic Example /// /// This example demonstrates a macro to avoid having to repeat generic parameters and bounds. /// /// /// ```rust /// use std::ops::Index; /// /// fn main() { /// let foo = Foo([3, 5], vec![8, 13, 21]); /// /// assert_eq!(foo.get(), [3, 5]); /// assert_eq!(foo[0], 8); /// assert_eq!(foo[1], 13); /// assert_eq!(foo[2], 21); /// } /// /// struct Foo(T, U); /// /// repeat_generics!{ /// impl Foo /// where /// U: IntoIterator; /// /// impl Self { /// fn get(&self) -> T { /// self.0.clone() /// } /// } /// /// impl Index for Self /// where /// U: Index /// { /// type Output = U::Output; /// /// fn index(&self, index: V) -> &U::Output { /// &self.1[index] /// } /// } /// } /// /// /// /// #[macro_export] /// macro_rules! repeat_generics { /// ($($tokens:tt)*)=>{ /// $crate::__::impl_parse_generics!{ /// $crate::__priv_inner_repeat_generics!{@process} /// ($($tokens)*) /// } /// } /// } /// /// #[doc(hidden)] /// #[macro_export] /// macro_rules! __priv_inner_repeat_generics { /// ( /// @process /// $attrs:tt /// () /// ( /// ($($lt:lifetime :($($lt_bound:tt)*),)*) /// ($($ty:ident :($($ty_bound:tt)*),)*) /// ($($const:ident: $const_ty:ty,)*) /// ) /// $(trait $trait:tt)? /// type $Self:tt /// $where_preds:tt /// ( ; $($items:tt)* ) /// ) => { /// $( /// $crate::__::compile_error!{concat!( /// "cannot implement a trait in the impl without a body: ", /// stringify!($trait), /// )} /// )? /// /// $crate::__priv_inner_repeat_generics!{ /// @iterate /// ( /// $attrs /// ( /// ($($lt: $($lt_bound)*,)*) /// ($($ty: $($ty_bound)*,)*) /// ($(const $const: $const_ty,)*) /// ) /// $Self /// $where_preds /// ) /// $($items)* /// } /// }; /// ( @iterate $params:tt $($item:item)* )=>{ /// $( /// $crate::__::impl_parse_generics!{ /// $crate::__priv_inner_repeat_generics!{@inner $params} /// ($item) /// } /// )* /// }; /// ( /// @inner /// ( /// ($($out_attrs:tt)*) /// ( ($($out_lt:tt)*) ($($out_ty:tt)*) ($($out_const:tt)*) ) /// ($Self:ty) /// ($($outer_where:tt)*) /// ) /// /// ($($in_attrs:tt)*) /// ($($qualifiers:tt)*) /// ( /// ($($lt:lifetime :($($lt_bound:tt)*),)*) /// ($($ty:ident :($($ty_bound:tt)*),)*) /// ($($const:ident: $const_ty:ty,)*) /// ) /// $(trait($trait:ty))? /// type(Self) /// ($($inner_where:tt)*) /// ({ $($items:tt)* }) /// ) => { /// $($out_attrs)* /// $($in_attrs)* /// $($qualifiers)* /// impl< /// $($out_lt)* $($lt: $($lt_bound)*,)* /// $($out_ty)* $($ty: $($ty_bound)*,)* /// $($out_const)* $(const $const: $const_ty,)* /// > $( $trait for )? $Self /// where /// $($outer_where)* /// $($inner_where)* /// { /// $($items)* /// } /// } /// } /// /// /// #[doc(hidden)] /// pub mod __ { /// pub use std::compile_error; /// /// pub use core_extensions::impl_parse_generics; /// } /// /// /// ``` #[cfg_attr(feature = "docsrs", doc(cfg(feature = "item_parsing")))] #[macro_export] macro_rules! impl_parse_generics { ( $(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ! $prefix:tt ($($tt:tt)*) ) => { $crate::impl_split!{ $crate::__ipg_unparsed_generics!{ ($(:: $(@$leading@)? )? $first $(:: $trailing)*) ! $prefix } ($($tt)*) } }; } #[doc(hidden)] #[macro_export] macro_rules! __ipg_unparsed_generics { ( $path:tt! $params:tt $attrs:tt $qualifiers:tt ($($generics:tt)*) $(trait $trait:tt)? type $type:tt $where_clause:tt $after_where:tt ) => { $crate::parse_split_generics!{ $crate::__ipg_parsed_generics!{ $path ! $params $attrs $qualifiers $(trait $trait)? type $type $where_clause $after_where } ($($generics)*) } } } #[doc(hidden)] #[macro_export] macro_rules! __ipg_parsed_generics { ( ($($path:tt)*)! {$($prefix:tt)*} $attrs:tt $qualifiers:tt $(trait $trait:tt)? type $type:tt $where_clause:tt $after_where:tt $gen_in_order:tt $gen_by_kind:tt ) => { $($path)* ! { $($prefix)* $attrs $qualifiers $gen_by_kind $(trait $trait)? type $type $where_clause $after_where } } }