6个版本 (3个重大变更)
0.6.0 | 2020年10月26日 |
---|---|
0.5.0 | 2020年10月23日 |
0.3.0 | 2020年10月20日 |
0.1.2 | 2020年10月16日 |
#900 in 进程宏
25KB
578 行
structout
用法
此库允许通过进程宏从单个定义生成多个结构体。
generate!(
attributes
visibility <...> where ... {
field: type,
...
} => {
OutputStruct => [action(arg), ...]
}
)
- (可选)
attributes
将应用于 所有 变体。 - (可选)
visibility
将应用于 所有 变体。 - (可选)
<...>
是类型参数(即泛型);如果未使用,则不应包含。 - (可选)
where ...
表示类型约束。 { field: type, ... }
是常用的 结构体体,将用于生成新的结构体。{ OutputStruct => [action(arg), ...] }
是输出配置,其中每个条目映射到一个新生成的结构体;进一步OutputStruct
是结构体的名称[action(arg), ...]
是构建此特定变体的操作列表。
其中“操作”可以是以下之一
omit(fields_names)
从此结构体定义中省略字段。include(fields_names)
优先于omit
。在结构体定义中包含字段。attr(args)
在结构体定义之前插入一个属性。as_tuple()
将结构体输出为一个元组结构体。upsert(fields)
将根据指定的类型进行更新或插入字段(即在存在具有相同标识符的字段定义的情况下替换字段定义,否则插入一个新的字段)。
实际应用
use structout::generate;
generate!(
{
foo: u32,
bar: u64,
baz: String
} => {
WithoutFoo => [omit(foo)],
WithoutBar => [omit(bar)],
}
);
上面的代码应该展开为两个结构体
struct WithoutFoo {
bar: u64,
baz: String
}
struct WithoutBar {
foo: u32,
baz: String
}
如果添加了两个泛型参数,它们应有效地在变体之间分割,而无需使用 PhantomData。
generate!(
<S, C> where S: Sized, C: Copy {
foo: S,
bar: G
} => {
OnlyBar => [omit(foo)],
OnlyFoo => [omit(bar)],
}
);
上面的代码应该展开为
struct OnlyBar<C>
where
C: Copy,
{
bar: G,
}
struct OnlyFoo<S>
where
S: Sized,
{
foo: S,
}
有关完整 API 的使用示例,请参阅 测试模块。
开发
测试
测试围绕快照测试(insta)进行。它通过运行 cargo expand
(cargo-expand),获取其输出,然后使用 cargo insta review
(cargo insta)进行审查来实现。
请参阅 测试模块,了解其实际实现方式。
动机
这个库解决了为单个定义生成多个结构体的需求。考虑以下代码
struct Human {
id: u32,
age: u32,
username: String,
name: String,
surname: String
}
// suppose this is what you would get from an API
struct HumanEditableParts {
name: String,
surname: String
}
HumanEditableParts
手动重复了一些字段,并且这些字段需要保持同步。
在 Rust 中,据说可以通过“结构体组合”来避免这种模式,即。
struct HumanEditableParts {
name: String,
surname: String1
}
struct Human {
id: u32,
age: u32,
username: String,
editable_parts: HumanEditableParts
}
但这并不总是可行的,也不总是令人愉快的事情。
依赖项
~1.5MB
~36K SLoC