#derive-builder #builder #macro-derive #derive #setter #macro #struct-fields

macon

另一个基于构建宏的生成器,拥有自己的语法

4 个版本 (1 个稳定版本)

1.0.1-beta.12024年7月14日
1.0.1-beta.02024年4月7日
1.0.0 2024年2月2日
0.3.0 2024年1月30日
0.2.0 2023年12月11日

#343 in Rust 模式


translators 中使用

MIT/Apache

340KB
262

另一个基于构建宏的生成器,拥有自己的语法。

"Maçon" 是 "builder" 的法语翻译

用法

#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyType {
  integer: i32,
  string: String,
  optional: Option<String>,
}

let _mytype: MyType = MyType::builder()
    .integer(42)
    .string("foobar")
    .build();
  • 添加一个构建结构体 (<TargetStruct>Builder)
  • 构建结构体实现了 Default
  • 向目标结构体添加一个 builder() 函数以初始化新的构建器
  • 每个目标结构体字段都可以使用同名的函数和相同类型的参数进行设置
  • 使用 build() 函数创建新的目标结构体实例
  • 任何未设置的字段将导致 build() 调用无法编译(默认值)
  • setter 参数泛型于 Into
  • Option 字段不是必需的。并且设置器使用包装类型。

设置

使用 #[builder()] 属性来设置设置。

结构体

字段

配置

可以通过在 crate 根目录添加 macon-config.yaml 来传递一些额外的配置(也支持 .yml.json 扩展名)。

内容示例

version: "1" # Ignored

default_types:
  defaults: true
  includes:
  - my_crate::a_module::Foobar
  excludes:
  - usize

option_types:
  defaults: true
  includes:
  - my_crate::a_module::MyOption    # Must have a generic parameter
  - path: Flag                      # An alias for Option<bool>
    wrapped: bool
  excludes:
  - core::option::Option

语法描述(所有键都是可选的)

  • 版本
    定义配置语法版本。目前被忽略。

  • 默认类型
    配置自动 Default 类型。

  • 默认类型.默认值
    包括(或不包括)default_types 的默认值。支持的值:true(默认)或 false

  • 默认类型.排除
    要排除的路径列表(例如 std::string::String)。默认为空。

  • 默认类型.包含
    要包含的路径列表(例如 my_crate::a_module::Foobar)。默认为空。

  • 选项类型
    配置自动 Default 类型。

  • 选项类型.默认值
    包括(或不包括)default_types 的默认值。支持的值:true(默认)或 false

  • 选项类型.排除
    要排除的路径列表(例如 std::string::String)。默认为空。

  • 选项类型.包含
    路径列表(例如 my_crate::a_module::MyOption)作为 String 或结构化类型。默认为空。

  • 选项类型.包含.路径
    应被视为 Option 的路径。必需。

  • 选项类型.包含.包装
    包装类型的路径。可选,如果缺失,则使用第一个类型参数。

特性

对于任何特性,您可以在 [./tests 目录)测试 中找到蓝图,展示宏生成的代码。

类型状态模式(默认)

蓝图

默认情况下,构建器依赖于类型状态模式。这意味着状态被编码在类型(使用泛型)中。只有当状态(类型)匹配时,适用的函数才会实现(可调用)

  • 当所有属性都已设置时,执行 build() 函数
  • 每个属性设置函数只要属性尚未设置

可选地,您可以明确设置它

#[macro_use] extern crate macon;

#[derive(Builder)]
#[builder(mode=Typestate)]
struct MyType {
  integer: i32,
  string: String,
}

build() 上引发恐慌

蓝图

默认情况下,构建器通过添加编译约束来避免通过类型状态模式添加错误配置。您可以切换到在错误配置时引发恐慌的构建器

#[macro_use] extern crate macon;

use std::path::PathBuf;

#[derive(Builder)]
#[builder(mode=Panic)]
struct MyType {
  integer: i32,
  path: PathBuf,
}

let _mytype: MyType = MyType::builder()
    .integer(42)
    .build();

build() 上返回结果

蓝图

默认情况下,构建器通过添加编译约束来避免通过类型状态模式添加错误配置。您可以切换到返回一个 Result 的构建器

#[macro_use] extern crate macon;

use std::path::PathBuf;

#[derive(Builder)]
#[builder(mode=Result)]
struct MyType {
  integer: i32,
  string: String,
}

let myTypeResult: Result<MyType,String> = MyType::builder()
    .integer(42)
    .build();

assert_eq!(
  Err(String::from("Field path is missing")),
  myTypeResult.map(|_| ())
);

元组

蓝图

元组是未命名字段的 struct。然后使用 set<ordinal>() 作为设置器

#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  i32,
  Option<String>,
  String,
);

let _mytuple: MyTuple = MyTuple::builder()
    .set0(42)
    .set2(String::from("foobar"))
    .build();

仅适用于 Typestate 模式,您可以使用 set()none()keep()default() 调用来按顺序分配值

#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  i32,
  Option<String>,
  String,
);
let _mytuple: MyTuple = MyTuple::builder()
    .set(42)
    .none()
    .set(String::from("foobar"))
    .build();

Into 参数

蓝图

设置函数参数泛型于 Into 以简化转换(尤其是对于 &str

#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyTuple(
  String,
);
let _mytuple: MyTuple = MyTuple::builder()
    .set("foobar")
    .build();

实现 Into

蓝图

构建器为目标类型实现 Into(以及反向的 From)。除了使用 TryInto / TryFromResult 模式之外。

#[macro_use] extern crate macon;

#[derive(Builder)]
struct MyStruct {
  value: String,
};
let _mytuple: MyStruct = MyStruct::builder()
    .value("foobar")
    .into();

Option 字段

蓝图

正如其名所示,Option 字段是可选的:您可以不显式设置它们来构建实例。

设置参数仍然泛型于 Into 但对于包装类型。无需将其包装在一个 Option 中。

#[macro_use] extern crate macon;

#[derive(Builder)]
struct WithOptional {
  mandatory: String,
  optional: Option<String>,
}

let built = WithOptional::builder()
  .optional("optional value")
  .mandatory("some value")
  .build();

assert_eq!(Some(String::from("optional value")), built.optional);

您可以使用 <field>_none()none() 对有序设置器显式地将它们设置为 None

#[macro_use] extern crate macon;

#[derive(Builder)]
pub struct WithOptional {
  mandatory: String,
  optional: Option<String>,
}

let built = WithOptional::builder()
  .optional_none()
  .mandatory("some value")
  .build();

assert_eq!(None, built.optional);

注意:为了检测可选字段,字段类型 名称 必须匹配

  • core::option::选项
  • ::core::option::选项
  • std::option::选项
  • ::std::option::选项
  • 选项

您可以使用在结构体或字段级别使用 #[builder(Option=!)] 来禁用 Option 支持

#[macro_use] extern crate macon;

#[derive(Builder)]
#[builder(Option=!)]
struct DisableOptionStruct {
  optional: Option<String>,
}

let built = DisableOptionStruct::builder()
  .optional(Some(String::from("mandatory value")))
  .build();

assert_eq!(Some(String::from("mandatory value")), built.optional);

如果您使用别名,请在字段级别使用 #[builder(Option=<WrappedType>)] 来启用 Option 支持

#[macro_use] extern crate macon;

type OptString = Option<String>;
#[derive(Builder)]
struct AliasedOptionStruct {
  #[builder(Option=String)]
  optional: OptString,
}

let built = AliasedOptionStruct::builder()
  .optional("aliased value")
  .build();

assert_eq!(Some(String::from("aliased value")), built.optional);

Default 结构体

蓝图

如果结构体实现了 Default,则所有字段都变为可选的,并且值从默认实例中保留

注意:为了检测 Default 实现,必须在其他 derive 属性之前放置 Builder derive 属性。

#[macro_use] extern crate macon;

#[derive(Builder,)]
#[derive(PartialEq,Debug,)]
#[builder(Default,)]
struct DeriveDefaultStruct {
  integer: usize,
  string: String,
  optional: Option<String>,
}

impl Default for DeriveDefaultStruct {
    fn default() -> Self {
        DeriveDefaultStruct {
            integer: 42,
            string: String::from("plop!"),
            optional: Some(String::from("some")),
        }
    }
}

let built = DeriveDefaultStruct::builder()
  .build();

assert_eq!(
  DeriveDefaultStruct {
    integer: 42,
    string: String::from("plop!"),
    optional: Some(String::from("some")),
  },
  built,
);

如果不需要检测 Default 实现,您可以使用 #[builder(Default=!)] 来禁用它。

另一方面,如果您有自己的 Default 实现,您可以添加 #[builder(Default)] 来启用支持。

#[macro_use] extern crate macon;

#[derive(Builder,)]
#[derive(PartialEq,Debug,)]
#[builder(Default,)]
struct CustomDefaultStruct {
  integer: usize,
  string: String,
  optional: Option<String>,
}

impl Default for CustomDefaultStruct {
    fn default() -> Self {
        CustomDefaultStruct {
            integer: 42,
            string: String::from("plop!"),
            optional: Some(String::from("some")),
        }
    }
}

let built = CustomDefaultStruct::builder()
  .build();

assert_eq!(
  CustomDefaultStruct {
    integer: 42,
    string: String::from("plop!"),
    optional: Some(String::from("some")),
  },
  built,
);

您可以使用 <field>_keep()keep() 对有序设置器显式地保留默认值(来自默认构建实例)

let built = CustomDefaultStruct::builder()
  .integer_keep()
  .string("overriden")
  .optional_none()
  .build();

assert_eq!(
  CustomDefaultStruct {
    integer: 42,
    string: String::from("overriden"),
    optional: None,
  },
  built,
);

Default 字段

蓝图

如果字段实现了 Default,则它是可选的,并且值

  1. 如果结构体实现了 Default,则从默认实例中保留,
  2. 或者,使用默认值初始化。
#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct WithDefaultFields {
  integer: usize,
  string: String,
  optional: Option<String>,
}

let built = WithDefaultFields::builder()
  .build();

assert_eq!(
  WithDefaultFields {
    integer: 0,
    string: String::from(""),
    optional: None,
  },
  built,
);

您可以使用 <field>_default()default() 显式地将它们设置为默认值,用于有序设置器(例如,重写默认实例值

#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct WithDefaultFields {
  integer: usize,
  string: String,
  optional: Option<String>,
}

let built = WithDefaultFields::builder()
  .integer_default()
  .string_default()
  .optional_default()
  .build();

assert_eq!(
  WithDefaultFields {
    integer: 0,
    string: String::from(""),
    optional: None,
  },
  built,
);

为了检测默认字段,字段类型 名称 必须匹配(前缀 :: 和模块路径是可选的)

  • bool
  • char
  • f32
  • f64
  • i8
  • i16
  • i32
  • i64
  • i128
  • isize
  • str
  • u8
  • u16
  • u32
  • u64
  • u128
  • usize
  • std::string::String
  • core::option::选项
  • std::option::选项
  • std::vec::Vec
  • alloc::vec::Vec
  • std::collections::HashMap
  • std::collections::hash_map::HashMap
  • std::collections::HashSet
  • std::collections::hash_set::HashSet

如果您使用别名或不受支持的类型,请在字段级别使用 #[builder(Default)] 启用 Default 支持

#[macro_use] extern crate macon;

#[derive(Builder)]
#[derive(Debug,PartialEq,)]
struct ExplicitDefaultOnField {
  #[builder(Default)]
  boxed: Box<usize>,
}

let built = ExplicitDefaultOnField::builder()
    .build();

assert_eq!(
  ExplicitDefaultOnField {
    boxed: Box::from(0),
  },
  built,
);

您可以通过在字段级别使用 #[builder(Default=!)] 禁用 Default 支持

// Don't compile
#[macro_use] extern crate macon;

#[derive(Builder)]
struct DisableDefaultOnField {
  #[builder(Default=!)]
  integer: usize,
}

DisableDefaultOnField::builder()
  .integer_default()
  .build();

依赖关系

~2–2.8MB
~60K SLoC