trait_group/
lib.rs

1/// Create a new trait that acts like an alias or “group” of a bunch of
2/// traits.
3///
4/// The macro works by creating a new trait and making one blanket implementation
5/// of it for all types that implement the traits in the group. It
6/// replaces `Self` automatically in the impl.
7///
8/// The trait may be declared with `pub` or without.
9///
10/// # Examples
11///
12/// ```
13/// #[macro_use] extern crate trait_group;
14///
15/// use std::ops::Add;
16/// 
17/// trait_group! {
18///     /// You can document the trait here
19///     pub trait CanAdd : Add<Self, Output=Self> + Copy
20/// }
21/// 
22/// fn foo<T: CanAdd>(x: T) -> T { x + x }
23/// 
24/// fn main() { println!("{}", foo(2)); }
25/// 
26/// ```
27#[macro_export]
28macro_rules! trait_group {
29    (@as_items $($it:item)*) => ($($it)*);
30    (@replace_self with $rep:tt [$($st:tt)*] Self $($tail:tt)*) => {
31        trait_group!{@replace_self with $rep [$($st)* $rep] $($tail)*}
32    };
33    (@replace_self with $rep:tt [$($st:tt)*] $t:tt $($tail:tt)*) => {
34        trait_group!{@replace_self with $rep [$($st)* $t] $($tail)*}
35    };
36    (@replace_self with $rep:tt [$($st:tt)*]) => {
37        trait_group!{@as_items $($st)*}
38    };
39    // User-facing rule: pub trait
40    ($(#[$attr:meta])* pub trait $name:ident : $($t:tt)+) => {
41        trait_group!{@as_items $(#[$attr])* pub trait $name : $($t)+ { }}
42        trait_group!{@replace_self with T [] impl<T> $name for T where T: $($t)+ { }}
43    };
44    // User-facing rule: (not pub) trait 
45    ($(#[$attr:meta])* trait $name:ident : $($t:tt)+) => {
46        trait_group!{@as_items $(#[$attr])* trait $name : $($t)+ { }}
47        trait_group!{@replace_self with T [] impl<T> $name for T where T: $($t)+ { }}
48    };
49}
50
51
52#[cfg(test)]
53mod tests {
54    #[test]
55    #[allow(deprecated)]
56    fn it_works() {
57        trait_group! {
58            /// This is the documentation
59            #[deprecated(note = "just a test")]
60            trait Test : Extend<u8> + Default
61        }
62
63        fn foo<V: Test>() -> V { let mut v = V::default(); v.extend(Some(0)); v }
64
65        assert_eq!(foo::<Vec<_>>(), vec![0]);
66    }
67}