#macro-derive #derive #enums #sorting #order #macro

sort_by_derive

提供派生宏 SortBy 和辅助宏 EnumAccessor 以及 EnumSequence,为不能自动派生这些特质的结构和枚举类型派生特质 OrdPartialOrdEqPartialEqHash

18个版本

0.1.17 2023年12月21日
0.1.16 2023年8月6日
0.1.15 2023年7月29日
0.1.13 2023年6月20日
0.1.10 2022年9月24日

#663过程宏


2 个crate中使用(通过 bones3_worldgen

无许可

65KB
1K SLoC

GitHub Crates.io docs.rs Continuous integration

sort_by_derive

此crate提供3个派生宏 SortByEnumAccessorEnumSequence

  • SortBy 为无法自动派生这些特质的结构派生特质 OrdPartialOrdEqPartialEqHash
  • 在枚举和结构体上,SortBy 还可以实现一个调用任意方法的 Ord 特质,这特别适用于与由 EnumAccessorEnumSequence 派生的枚举变体访问方法结合使用。
  • EnumAccessor 为变体中的常用字段派生访问器方法,因此您无需编写自己的 match 语句来访问具有相同名称和类型的字段。此功能类似于 enum_dispatch,但采用不同的方法,其中结构体不需要实现特质。
  • EnumSequence 提供了一个 enum_sequence 方法,其中第一个变体返回 0,第二个返回 1,依此类推。这在需要实现自定义排序时很有用,同时变体声明的顺序仍然是作为次要排序依据。

用法

SortBy

应用于排序的字段使用属性 #[sort_by] 标记。其他字段将被忽略。

use std::cmp::Ordering;
use sort_by_derive::SortBy;

#[derive(SortBy)]
struct Something {
    #[sort_by]
    a: u16,
    b: u16
}

assert_eq!(Something{a: 2, b: 0}.cmp(&Something{a: 1, b: 1}), Ordering::Greater); // a is compared
assert_eq!(Something{a: 1, b: 0}.cmp(&Something{a: 1, b: 1}), Ordering::Equal); // b is ignored

枚举访问器

此 derive 宏与 enum_dispatch 类似。 enum_dispatch 要求结构体实现一个公共特质,如果一组公共函数适用于所有变体,这可能会很有用。 EnumAccessor 采取了相反的方法:公共字段和方法在枚举级别声明,并且可以存在没有给定字段或方法的变体。如果变体数量很多,而你只关心访问字段,这可能更实用,因为单个结构体仅包含数据。这通常适用于事件——它们代表状态变化,通常作为一个整体被消费,单个结构体没有自己的代码。

字段访问器

在枚举上添加 derive(EnumAccessor) 之后,字段将声明为 accessor(field: type) 属性。

这将推导出访问器方法 fn name(&self) -> &type;fn name_mut(&mut self) -> &mut type;,并返回任何变体上同名字段的引用。

use sort_by_derive::EnumAccessor;

#[derive(EnumAccessor)]
#[accessor(a: u16)]
#[accessor(b: u16)]
enum E {
    Variant1{a: u16, b: u16},
    Variant2{a: u16, b: u16, c: u32},
}

let v1 = E::Variant1{a: 1, b: 1};
let mut v2 = E::Variant2{a: 1, b: 1, c: 2};

// Accessor methods are generated for the specified members
assert_eq!(*v1.a(), 1);
assert_eq!(*v2.b(), 1);

// Mutable accessors are also generated
*v2.a_mut() = 2;
assert_eq!(*v2.a(), 2);

因此,您可以取任何 E,所有变体都将有 aa_mutbb_mut

枚举序列

只需简单地 derive EnumSequence,您就可以得到 enum_sequence(&self),它返回一个从 0 开始并针对每个变体递增的 usize

当使用枚举的枚举时,创建对内部枚举序列的访问器可能会创建方法名歧义。为了减轻这种情况,可以使用 as 选择自定义访问器名称,例如 #[accessor(enum_sequence() as inner_sequence: usize)]

注意:这将创建一个扩展特质 {TypeName}EnumSequence(即类型 T 将获得一个新的特质 TEnumSequence)。此特质将具有与类型相同的可见性。当从另一个模块使用此类型时,请确保使用 use {TypeName}EnumSequence 带入特质的作用域。

示例

use sort_by_derive::EnumSequence;

#[derive(EnumSequence)]
enum ABC {
    A(u8),
    B(String),
    C { f: String, g: usize }
}

assert_eq!(ABC::B("hi!".into()).enum_sequence(), 1);

依赖项

~0.5–1MB
~21K SLoC