#builder #options #codegen #crates #rust

engineer derive

Engineer 是一位大师级构建者!这就是它的 derive

7 个版本

0.1.6 2023 年 1 月 30 日
0.1.5 2023 年 1 月 29 日
0.1.2 2022 年 12 月 26 日

#62#crates

38 每月下载量
engineer 中使用

MIT/Apache

24KB
428

Engineer

Build and Test Rust

Engineer 是基于 Optional 的大师级构建者。

它仅生成一个用于数据模型的 Engineer (Builder) 类。

安装

将以下内容添加为依赖项

[dependencies]
engineer = "0.1.3"

入门

use engineer::Engineer;

#[derive(Engineer)]
struct Identity {
    id: usize,
    username: String,
    first_name: Option<String>,
    last_name: Option<String>,
    lang_code: Option<String>,
}

可选字段在初始化期间不是必需的。

// Option fields are set to None.
let identity = Identity::engineer(0, "immmdreza".to_string()).done();

但是,您也可以为 Option 字段设置一个值。

let identity = Identity::engineer(0, "immmdreza".to_string()) // IdentityEngineer
    .first_name("Arash".to_string()) // IdentityEngineer
    .last_name("Tofani".to_string()) // IdentityEngineer
    .done(); // Identity

这就是基础知识,但是您可以进行一些自定义。

自定义

Engineer 结构名称

默认情况下,Engineer 结构名为 {struct}Engineer(《IdentityEngineer》对于《Identity》),但您可以更改它。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(engineer_name = "IdentityBuilder")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::engineer(0, "immmdreza".to_string()) // IdentityBuilder
        .first_name("Arash".to_string()) // IdentityBuilder
        .last_name("Tofani".to_string()) // IdentityBuilder
        .done(); // Identity

Builder 函数名称

默认情况下,builder 函数的名称为 engineer,但您知道吗?

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(builder_func = "builder")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::builder(0, "immmdreza".to_string())
    // ~~~ sniff ~~~

您想将其用作 new 函数

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(builder_func = "new")]
struct Identity {
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza".to_string())
    // ~~~ sniff ~~~

这可以简化为特殊的 new 名称作为 builder 函数

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
}

Options 的默认值

您可以设置选项字段的默认值。

如果没有设置其他值,将使用此值。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
    #[engineer(default_value = r#"String::from("fa")"#)]
    lang_code: Option<String>,
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza".to_string());

    identity.lang_code // Some("fa")

或者,您可以使用 default 来设置 Some(Default::default) 替代 None,如果未提供其他值。

    // ~~~ sniff ~~~
    #[engineer(default)]
    luck_number: Option<i32>, // Some(0)
    // ~~~ sniff ~~~

重打字

您可以更改构建过程中请求的类型。

// ~~~ sniff ~~~

#[derive(Engineer)]
#[engineer(new)]
struct Identity {
    // ~~~ sniff ~~~
    #[engineer(retype(to = "impl Into<String>", re = ".into()"))]
    //                      ^                         ^
    //                      | Requested type in public.
    //                                                |
    //                                                | How we recover to original type.
    username: String,
    // ~~~ sniff ~~~
}

// ~~~ sniff ~~~

    let identity = Identity::new(0, "immmdreza"); // .to_string() is not needed.
    // ~~~ sniff ~~~

或者,对于 str 重打字(如上面的示例),您可以使用缩写 str_retype

    // ~~~ sniff ~~~
    #[engineer(str_retype)]
    username: String,
    // ~~~ sniff ~~~

您还可以在全局范围内使用重打字。

#[derive(Engineer)]
#[engineer(new, retype(from = "String", to = "impl Into<String>", re = ".into()"))]
struct Identity {
    // ~~~ sniff ~~~
}

或者,对于 String 重打字

#[derive(Engineer)]
#[engineer(new, str_retype)]
struct Identity {
    // ~~~ sniff ~~~
}

上述两种代码都将 全部 String 字段重打字为公开 API 中的 impl Into<String>

最终结果

#[derive(Engineer)]
#[engineer(new, str_retype)]
struct Identity {
    id: usize,
    username: String,
    first_name: String,
    last_name: Option<String>,
    #[engineer(str_retype, default_value = "\"fa\".to_string()")]
    lang_code: Option<String>,
}

fn print_identity(ident: impl Into<Identity>) {
    let ident: Identity = ident.into();
    println!("{ident:#?}");
}

fn main() {
    let ident = Identity::new(1, "immmdreza", "Arash").last_name("Tofani");

    print_identity(ident);
    // Identity {
    //     id: 1,
    //     username: "immmdreza",
    //     first_name: "Arash",
    //     last_name: Some(
    //         "Tofani",
    //     ),
    //     lang_code: Some(
    //         "fa",
    //     ),
    // }
}

更多关于特质的介绍

这个crate有两个主要特性: Builder<T> where T: EngineerEngineer

Engineer 特性有两个关联类型: ParamsBuilder

  • Params 是一个包含所需字段类型的元组(不是 Option<_> 的字段)
  • Builder 是Builder/Engineer类的类型。

使用 Engineer 宏,可以让您的数据类实现 Engineer 特性,并创建一个实现 Builder<T> 的Builder结构体(通常命名为 {struct_name}Engineer - 我正在考虑重命名),其中T是您的自己的结构体。

这使您可以在这些特性周围做一些泛型操作,例如

fn build_any<E>(required: E::Params) -> E
where
    E: Engineer,
{
    E::build(required)
}

// Or

fn get_builder<E>(required: E::Params) -> E::Builder
where
    E: Engineer,
{
    E::builder(required)
}

注意,E::Params 是一个元组。

如果所有所需字段(E::Param)都实现了Default,另一个函数 build_default 将在您的结构体上可用,该函数创建一个不需要输入的默认实例。

此外,Engineer 特性有两个常量字段

- const NORMAL_FIELDS: usize;
- const OPTIONAL_FIELDS: usize;

🧀

依赖

~2MB
~42K SLoC