autogen ====== [github](https://github.com/pstroka/autogen) [crates.io](https://crates.io/crates/autogen) [docs.rs](https://docs.rs/autogen) Tired of repeating all the generics in every `impl` block or function? Autogen is a set of macros that allows you to automatically apply generics to `impl` blocks and functions. - the `#[register]` macro registers the generics of a `struct` or `enum`, including lifetimes and the where clause. - the `#[apply]` macro applies the generics to an `impl` block or function. ```rust #[autogen::register] struct Struct<'a, T, R: ?Sized> where T: PartialEq, { x: T, y: &'a R, } // This will expand to impl<'a, T, R: ?Sized> Struct<'a, T, R> where T: PartialEq {} #[autogen::apply] impl Struct {} // This will expand to impl<'a, T, T> Struct<'a, T, T> where T: PartialEq {} #[autogen::apply(R = T)] impl Struct {} // This will expand to impl<'a, String, str> Struct<'a, String, str> #[autogen::apply(T = String, R = str)] impl Struct {} ``` ## Examples ```rust #[autogen::register] struct Struct<'a, T, R: ?Sized> where T: PartialEq, { x: T, y: &'a R, } #[autogen::apply] impl Struct { fn x_equals(&self, other: &T) -> bool { &self.x == other } fn y(&self) -> &'a R { self.y } } let s = Struct { x: 1, y: "abc" }; assert!(s.x_equals(&1)); assert_eq!(s.y(), "abc"); #[autogen::apply] impl TryFrom> for Struct { type Error = String; fn try_from(vec: Vec) -> Result { let first: Option = vec.into_iter().next(); first.ok_or("empty".to_string()) } } let vec = vec![s]; let s: Struct<'_, _, _> = vec.try_into().unwrap(); assert!(s.x_equals(&1)); assert_eq!(s.y(), "abc"); #[autogen::apply] fn same_x(l: &Struct, r: &Struct) -> bool { l.x == r.x } let l = Struct { x: 2.1, y: &3 }; let r = Struct { x: 2.1, y: &7 }; assert!(same_x(&l, &r)); ``` By default, the generics are registered with the struct/enum name, but you can provide a custom identifier. This can be useful if a type with the same name is already registered in another module. ```rust #[autogen::register] struct Name { t: T, } #[autogen::apply] impl Name { fn t(&self) -> &T { &self.t } } mod sub { use std::str::FromStr; #[autogen::register(CustomName)] pub struct Name { pub s: S, pub x: X, } #[autogen::apply(CustomName)] impl Name { pub fn new(string: &str, x: X) -> Result { Ok(Name { s: string.parse()?, x }) } } #[autogen::apply(id = CustomName, X = S)] impl Name { pub fn parse(string: &str) -> Result { Ok(Name { s: string.parse()?, x: string.parse()? }) } } } let s1 = Name { t: 64 }; assert_eq!(s1.t(), &64); let s2 = sub::Name::::new("123", -5).unwrap(); assert_eq!(s2.s, 123); assert_eq!(s2.x, -5); let s3 = sub::Name::::parse("5.6").unwrap(); assert_eq!(s3.s, 5.6); assert_eq!(s3.x, 5.6); ``` For more examples and details, please see the [documentation](https://docs.rs/autogen)