A set of structs, traits and macros to implement tagged pointers.
```rust // import macro use taggedpointerasenum::taggedenum;
// declare it like a normal enum but inside taggedenum! macro taggedenum! { 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(42u8); let b = E::B(Box::new(String::from("foo"))); let c = E::C(300i16);
// and a helper module with tags asserteq!(tags::A, 1); asserteq!(tags::B, 2); assert_eq!(tags::C, 3);
// these tags can be used to check variant of enum asserteq!(a.tag(), tags::A); asserteq!(b.tag(), tags::B); assert_eq!(c.tag(), tags::C);
// only variants that behave like containers can be borrowed
asserteq!(b.borrowvalue::
// of course, you can get values back
asserteq!(a.unwrap::
By default the following types can be used as variants:
u8
u16
u32
i8
i16
i32
Box<T>
Option<Box<T>>
It is possible to use other types by implementing TaggedPointerValue
for them:
```rust use taggedpointerasenum::{taggedenum, 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::
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
Debug
Clone
PartialEq
Eq
Also, Drop
is auto-implemented for all tagged enums.
```rust use taggedpointerasenum::{taggedenum, TaggedPointerValue};
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 asserteq!( E::NumAbsCompare(NumAbsCompare { n: 100 }), E::NumAbsCompare(NumAbsCompare { n: -100 }), ); // variants ARE NOT equal if tags are different assertne!( 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 }), ); ```