1 个稳定版本
1.0.0 | 2021年11月10日 |
---|
#1337 在 Rust 模式
20KB
451 行
标记指针枚举类型
一组结构体、特性和宏,用于实现标记指针。
基本用法
// import macro
use tagged_pointer_as_enum::tagged_enum;
// declare it like a normal enum but inside tagged_enum! macro
tagged_enum! {
enum E {
// specify how many bits you want to be used by tag.
// should be at least log2(count(variants) + 1), but you can set more
// if you need to keep ABI stable after adding new variants
bits = 2;
A(u8),
B(Box<String>),
C(i16),
}
}
// macro generates constructors:
let a = E::A(42_u8);
let b = E::B(Box::new(String::from("foo")));
let c = E::C(300_i16);
// and a helper module with tags
assert_eq!(tags::A, 1);
assert_eq!(tags::B, 2);
assert_eq!(tags::C, 3);
// these tags can be used to check variant of enum
assert_eq!(a.tag(), tags::A);
assert_eq!(b.tag(), tags::B);
assert_eq!(c.tag(), tags::C);
// only variants that behave like containers can be borrowed
assert_eq!(b.borrow_value::<Box<String>, String>(), &String::from("foo"));
// borrowing values variants is impossible
// because there's no memory location containing value WITHOUT tag
// of course, you can get values back
assert_eq!(a.unwrap::<u8>(), 42);
assert_eq!(b.unwrap::<Box<String>>(), Box::new(String::from("foo")));
assert_eq!(c.unwrap::<u16>(), 300);
自定义变体类型
默认情况下,以下类型可以用作变体
u8
u16
u32
i8
i16
i32
Box<T>
Option<Box<T>>
可以通过为它们实现 TaggedPointerValue
来使用其他类型
use tagged_pointer_as_enum::{tagged_enum, TaggedPointerValue};
struct Custom {
low: u8,
high: u8
}
// even if it looks like a marker trait in fact it's not
impl TaggedPointerValue for Custom {}
tagged_enum! {
enum E {
bits = 1;
Custom(Custom),
}
}
let custom = E::Custom(Custom { low: 1, high: 2 });
let unwrapped = custom.unwrap::<Custom>();
assert_eq!(unwrapped.low, 1);
assert_eq!(unwrapped.high, 2);
实现默认特质
默认情况下,tagged_enum!
宏生成的结构体不实现任何内置特质。
可以像通常附加到原生 Rust 枚举一样附加类似的 #[derive(...)]
元数据,但是所有变体类型也必须实现这些特质。
仅支持以下特质
Debug
Clone
PartialEq
Eq
此外,所有标记枚举都会自动实现 Drop
。
use tagged_pointer_as_enum::{tagged_enum, TaggedPointerValue};
#[derive(Debug)]
struct NumAbsCompare {
n: i32
}
impl TaggedPointerValue for NumAbsCompare {}
// implement comparison by absolute value
impl PartialEq for NumAbsCompare {
fn eq(&self, other: &Self) -> bool {
self.n.abs() == other.n.abs()
}
}
tagged_enum! {
#[derive(Debug, PartialEq)]
enum E {
bits = 2;
I32(i32),
NumAbsCompare(NumAbsCompare),
}
}
// variants ARE equal if they have the same tag and value
assert_eq!(
E::NumAbsCompare(NumAbsCompare { n: 100 }),
E::NumAbsCompare(NumAbsCompare { n: -100 }),
);
// variants ARE NOT equal if tags are different
assert_ne!(
E::NumAbsCompare(NumAbsCompare { n: 100 }),
E::I32(100),
);
// variants ARE NOT equal if values are different
assert_ne!(
E::NumAbsCompare(NumAbsCompare { n: 100 }),
E::NumAbsCompare(NumAbsCompare { n: 101 }),
);
依赖
~0–11MB
~94K SLoC