1 个不稳定版本
| 0.1.0 | 2022 年 8 月 2 日 | 
|---|
#34 in #correct
27KB
248 行
由 Builder 衍生宏创建的构建器是编译时正确的。这意味着它只允许你构建给定结构体,只要你为它的所有必需字段提供了值。
如果字段没有被 Option 包装,则解释为必需字段。为了构建给定结构体,任何在 Option 内的字段都不被认为是必需的。例如在
pub struct MyStruct {
    foo: String,
    bar: Option<usize>,
}
foo 字段是必需的,而 bar 是可选的。**注意**:虽然 std::option::Option 也指向相同的类型,但目前这个宏不识别除 Option 之外的内容。使用 Builder 宏生成的构建器通过使用 const generics 来编码已初始化的集合来保证正确性。以下是一个例子。假设我们有一个具有两个必需字段和一个可选字段的 struct
pub struct MyStruct {
    req1: String,
    req2: String,
    opt1: Option<String>
}
生成的构建器将是
pub struct MyStructBuilder<const P0: bool, const P1: bool> {
    req1: Option<String>,
    req2: Option<String>,
    opt1: Option<String>,
}
P0 表示第一个必需参数是否已初始化。同样,P1 对第二个必需参数执行相同的操作。构建器的初始状态将是 MyStructBuilder<false, false>,并在首次初始化必需字段时,其相应的 const generic 参数将被设置为 true,这表示不同的状态。设置可选值不会改变状态,因此保持相同的 const generic 参数。当构建器达到 MyStructBuilder<true, true> 时,你才能在构建器上调用 build 函数。
因此,给定示例结构体的完整生成代码是
pub struct MyStruct {
    req1: String,
    req2: String,
    opt1: Option<String>
}
pub struct MyStructBuilder<const P0: bool, const P1: bool> {
    req1: Option<String>,
    req2: Option<String>,
    opt1: Option<String>,
}
impl MyStruct {
    pub fn builder() -> MyStructBuilder<false, false> {
        MyStructBuilder {
            req1: None,
            req2: None,
            opt1: None,
        }
    }
}
impl<const P0: bool, const P1: bool> MyStructBuilder<P0, P1> {
    pub fn req1(self, req1: String) -> MyStructBuilder<true, P1> {
        MyStructBuilder {
            req1: Some(req1),
            req2: self.req2,
            opt1: self.opt1,
        }
    }
    pub fn req2(self, req2: String) -> MyStructBuilder<P0, true> {
        MyStructBuilder {
            req1: self.req1,
            req2: Some(req2),
            opt1: self.opt1,
        }
    }
    pub fn opt1(self, opt1: String) -> MyStructBuilder<P0, P1> {
        MyStructBuilder {
            req1: self.req1,
            req2: self.req2,
            opt1: Some(opt1),
        }
    }
}
impl MyStructBuilder<true, true> {
    pub fn build(self) -> MyStruct {
        unsafe {
            MyStruct {
                req1: self.req1.unwrap_unchecked(),
                req2: self.req2.unwrap_unchecked(),
                opt1: self.opt1,
            }
        }
    }
}
依赖关系
~1.5MB
~36K SLoC