Crates.io | autogen |
lib.rs | autogen |
version | 1.0.0 |
source | src |
created_at | 2024-07-21 20:18:23.793698 |
updated_at | 2024-11-10 17:18:32.403727 |
description | Autogen is a set of macros that allows you to automatically apply generics to impl blocks. |
homepage | |
repository | https://github.com/pstroka/autogen |
max_upload_size | |
id | 1310557 |
size | 57,035 |
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.
#[register]
macro registers the generics of a struct
or enum
, including lifetimes and
the where clause.#[apply]
macro applies the generics to an impl
block or function.#[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 {}
#[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<Vec<Struct>> for Struct {
type Error = String;
fn try_from(vec: Vec<Struct>) -> Result<Struct, String> {
let first: Option<Struct> = 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.
#[autogen::register]
struct Name<T: PartialEq> {
t: T,
}
#[autogen::apply]
impl Name {
fn t(&self) -> &T {
&self.t
}
}
mod sub {
use std::str::FromStr;
#[autogen::register(CustomName)]
pub struct Name<S: FromStr, X> {
pub s: S,
pub x: X,
}
#[autogen::apply(CustomName)]
impl Name {
pub fn new(string: &str, x: X) -> Result<Self, S::Err> {
Ok(Name { s: string.parse()?, x })
}
}
#[autogen::apply(id = CustomName, X = S)]
impl Name {
pub fn parse(string: &str) -> Result<Self, S::Err> {
Ok(Name { s: string.parse()?, x: string.parse()? })
}
}
}
let s1 = Name { t: 64 };
assert_eq!(s1.t(), &64);
let s2 = sub::Name::<u32, i32>::new("123", -5).unwrap();
assert_eq!(s2.s, 123);
assert_eq!(s2.x, -5);
let s3 = sub::Name::<f64, f64>::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