5个版本
0.2.3 | 2024年8月1日 |
---|---|
0.2.2 | 2024年7月31日 |
0.2.1 | 2024年7月30日 |
0.2.0 | 2024年7月29日 |
0.1.0 | 2024年7月21日 |
#203 in 进程宏
591 每月下载量
24KB
289 行
autogen
厌倦了在每个impl
块中重复所有泛型吗?
Autogen是一组宏,允许您自动将泛型应用到impl
块中。
#[register]
宏注册了结构体或枚举的泛型,包括生命周期和where子句。#[apply]
宏将泛型应用到impl
块中。
#[autogen::register]
struct Struct<'a, T, R: ?Sized>
where
T: PartialEq,
{
x: T,
y: &'a R,
}
#[autogen::apply]
impl Struct {}
这将展开为
impl<'a, T, R: ?Sized> Struct<'a, T, R> where T: PartialEq {}
除了类型本身,泛型还可以应用到
- 给定类型的数组
- 给定类型的切片
- 给定类型的引用
- 给定类型的指针
- 包含给定类型的元组
- 包含给定类型作为泛型参数的其他类型
- 上述所有组合
唯一限制是impl块不能包含不同的已注册类型。
#[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
}
}
trait Trait {
fn type_of(&self) -> &'static str;
}
#[autogen::apply]
impl Trait for Struct {
fn type_of(&self) -> &'static str {
"regular"
}
}
#[autogen::apply]
impl Trait for [Struct; 2] {
fn type_of(&self) -> &'static str {
"array of size 2"
}
}
#[autogen::apply]
impl Trait for [Struct] {
fn type_of(&self) -> &'static str {
"slice"
}
}
#[autogen::apply]
impl Trait for &Struct {
fn type_of(&self) -> &'static str {
"reference"
}
}
#[autogen::apply]
impl Trait for *const Struct {
fn type_of(&self) -> &'static str {
"pointer"
}
}
#[autogen::apply]
impl Trait for (Struct, &'static str, Struct) {
fn type_of(&self) -> &'static str {
"tuple"
}
}
#[autogen::apply]
impl Trait for Result<Struct, String> {
fn type_of(&self) -> &'static str {
"generic argument"
}
}
#[autogen::apply]
impl Trait for [([Option<&Struct>; 1], Struct, String)] {
fn type_of(&self) -> &'static str {
"crazy ****"
}
}
let struct1 = Struct { x: 1, y: "abc" };
assert!(struct1.x_equals(&1));
assert_eq!(struct1.y(), "abc");
assert_eq!(struct1.type_of(), "regular");
assert_eq!((&&struct1).type_of(), "reference");
let pointer = &struct1 as *const Struct<'_, i32, str>;
assert_eq!(pointer.type_of(), "pointer");
let struct2 = Struct { x: 2, y: "xyz" };
assert!(struct2.x_equals(&2));
assert_eq!(struct2.y(), "xyz");
let tuple = (struct1, "string", struct2);
assert_eq!(tuple.type_of(), "tuple");
let array = [tuple.0, tuple.2];
assert_eq!(array.type_of(), "array of size 2");
assert_eq!(array[..].type_of(), "slice");
let struct3 = Struct { x: -1, y: "b" };
let result: Result<_, String> = Ok(struct3);
assert_eq!(result.type_of(), "generic argument");
let struct3 = result.unwrap();
let struct4 = Struct { x: -2, y: "s" };
let crazy = [([Some(&struct3)], struct4, "****".to_string())];
assert_eq!(crazy[..].type_of(), "crazy ****");
默认情况下,泛型会与结构体/枚举名称一起注册,但您也可以提供自定义标识符。如果您在其他模块中已注册具有相同名称的类型,这可能很有用。
这不会编译,因为Name
已经被注册。
#[autogen::register]
struct Name<T: PartialEq> {
t: T,
}
mod sub {
#[autogen::register]
pub struct Name<S: FromStr> {
s: S,
}
}
为了解决这个问题,您必须提供自定义标识符。
#[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> {
s: S,
}
#[autogen::apply(CustomName)]
impl Name {
pub fn parse(string: &str) -> Result<Self, S::Err> {
Ok(Name { s: string.parse()? })
}
pub fn s(&self) -> &S {
&self.s
}
}
}
let s1 = Name { t: 64 };
assert_eq!(s1.t(), &64);
let s2 = sub::Name::<u32>::parse("123").unwrap();
assert_eq!(s2.s(), &123);
依赖关系
~280–730KB
~17K SLoC