| Crates.io | tagged-pointer-as-enum |
| lib.rs | tagged-pointer-as-enum |
| version | 1.0.0 |
| created_at | 2021-11-10 14:33:03.615408+00 |
| updated_at | 2021-11-10 14:33:03.615408+00 |
| description | A set of structs, traits and macros to implement tagged pointers. |
| homepage | |
| repository | https://github.com/iliabylich/tagged-pointer-as-enum |
| max_upload_size | |
| id | 479743 |
| size | 22,996 |
A set of structs, traits and macros to implement tagged pointers.
// 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);
By default the following types can be used as variants:
u8u16u32i8i16i32Box<T>Option<Box<T>>It is possible to use other types by implementing TaggedPointerValue for them:
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);
Out of the box tagged_enum! macro generates a struct that doesn't implement any builtin traits.
It is possible to attach #[derive(...)] metadata similar to how it's usually attached to native Rust enums, however all variant types must also implement these traits.
Only the following traits are supported
DebugClonePartialEqEqAlso, Drop is auto-implemented for all tagged enums.
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 }),
);