3个不稳定版本

0.2.0 2024年7月18日
0.1.1 2024年3月14日
0.1.0 2024年3月13日

#189 in 过程宏

Download history 107/week @ 2024-07-14 4/week @ 2024-07-21 15/week @ 2024-07-28

每月 126 次下载

MIT/Apache

50KB
926

spread_macros crate spread_macros documentation

扩展散列语法的宏。

spread!

扩展散列/结构体更新语法,允许从不同类型的结构体中获取字段,只要列出的字段在两个结构体中都具有相同的类型。它支持修饰符前缀,允许执行常见的转换,如克隆、转换、取引用;甚至可以通过提供函数路径来执行自定义转换。

use spread_macros::spread;

struct Foo {
    one: String,
    two: u32,
    three: u32,
    four: &'static str,
}

struct Bar<'a> {
    one: String,
    two: u64,
    three: &'a u32,
    four: String,
}

let foo = Foo {
    one: "Hello".to_string(),
    two: 2,
    three: 3,
    four: "HELLO",
};

let two = 2u32;
let bar = spread!(Bar {
    >two, // calls .into()
    {
        +one, // calls .clone()
        &three, // takes a reference
        [str::to_lowercase] four,
    } in &foo,
});

anon!

使用提供的字段生成匿名结构体的值,其类型是推断的。可以用于将多个变量捆绑在一个结构体中,然后用于 spread!。它支持与 spread! 相同的功能(列表和修饰符),但除外最后的结构体更新语法。

use spread_macros::anon;

struct Foo {
    one: String,
    two: u32,
    three: u32,
}

let foo = Foo {
    one: "Hello".to_string(),
    two: 2,
    three: 3,
};
let four = 4u32;

// Creates an anonymous struct with the given fields.
let exemple = anon! {
    { +one, >two, &three } in &foo,
    four,
};

// When using `>` (into) the field must be used for its type to be inferred.
let inferred: u64 = exemple.two;
println!("{exemple:?})");

slet!

通过列出所有标识符和转换,与 anon! 使用相同的语法来避免编写大量的转换,如 let variable_with_long_name = variable_with_long_name.clone()(这在闭包和异步块中很常见)通过列出所有标识符和转换。此外,每个字段名都可以由 mut(在潜在的修饰符之前)前缀,以创建一个 let mut 绑定。

use spread_macros::slet;

let foo = "Hello".to_string();
let bar = 42u32;

slet! {mut +foo, >bar};
let inferred: u64 = bar;

fn_struct!

生成表示给定函数或方法参数的结构体,允许使用Rust的结构体更新语法、spread!Default 与函数参数。列出的字段可以使用 spread! 的修饰符,如 &,例如,可以使用没有引用的结构体来调用具有引用参数的函数,从而实现 Default。该结构体可以泛型化函数参数的类型,而 call 函数也可以泛型化不在参数中出现的类型。

该宏旨在在编写测试时使用,其中频繁调用具有许多参数的函数,并且可以使用 spread! 重复应用参数。

断言提供的某些字段与期望匹配。

use spread_macros::fn_struct;

fn foo(foo: u32, bar: u32, baz: &u32) -> u32 {
    foo + bar + baz
}

fn_struct!(
    struct Foo
    for fn foo(
        one: u32 = 1,
        >two: u16 = 2, // converts from struct's u16 to functions u32
        &three: u32 = 3 // struct stores value, function takes reference
    ) -> u32
);

let res = Foo {
    three: 33,
    ..Default::default()
}
.call();

assert_eq!(res, 1 + 2 + 33);

assert_fields_eq!

这种期望可以用两种方式表达

  • 可以提供另一个值,然后是一个列表,其中包含两个值共有的字段,并且这些字段应该相等。
  • 一个匿名结构体,其语法与 anon! 相同。

之后,宏接受一个自定义的 panic 消息,其格式化方式与 assert_eq! 相似。

它使用作用域内的 assert_eq! 宏,允许在需要时使用替代宏,如 similar_asserts::assert_eq!

use spread_macros::{anon, assert_fields_eq};

#[derive(Clone, Debug)]
struct Exemple {
    _foo: u32,
    bar: String,
    baz: bool,
}

let exemple = Exemple {
    _foo: 42,
    bar: String::from("exemple"),
    baz: true,
};

let expected = anon! {
    bar: String::from("exemple"),
    baz: true,
    other: "other",
};

assert_fields_eq!(exemple, {
    bar: String::from("exemple"),
    { +baz } in &expected,
});

assert_fields_eq!(
    exemple,
    expected,
    [bar, baz],
    "unexpected fields in {exemple:?}"
);

依赖项

~275–730KB
~17K SLoC