To get right to the point I have a struct that effectively acts as an enum that I want to essentially write a for match
in macro form. I'm writing a dynamic scripting language that I'm trying to be relatively performant so I'm trying a lot of tricks to get some extra speed.
The two primary structs of relevance are GcObj<T>
and GcObject
in both cases they effectively just wrappers around a NonNull<u8>
. I do some layout logic but otherwise they are really just pointers to the objects. They are laid out like
[ ObjHeader { marked: AtomicBool, kind: ValueKind } | T ]
So just to get ahead of the question why don't you just use an enum?
- The issue is I generally need the struct that points or owns the object to exactly a single pointer wide. I'm using technique called NAN boxing where I essentially hide pointers inside a floating point number
- I want to avoid the space overhead of all enum variants being the size of the largest variant. My smallest variant is only 16 bytes, while my largest in 136 bytes, with the header being 16bytes itself I may be using 5x the amount of memory I need for the smallest variant.
- In some cases I know exactly what variant I'm looking at and don't want to pay to keep wrapping and unwrapping the enum.
With how I have things setup now this will be how I have to do my "matching" now
let obj: GcObject = get_obj();
match obj.kind() [
ValueKind::Class => {
let class: GcObj<Class> = obj.to_class();
class.do_stuff();
}
ValueKind::Fun => {
let fun: GcObj<Fun> = obj.to_fun();
string.do_stuff();
}
// ...
}
Besides being a bit verbose nothing stops me from unwrapping to the wrong variant. This is were I think a macro could really help, but I'm so far only written relatively simple macros. Ideally I think it would be great if I could do something like this:
match!(match obj {
ValueKind::Class(class) => class.do_stuff(),
ValueKind::Fun(fun) => fun.do_stuff(),
// ..
});
// maybe expands
match obj.kind() {
ValueKind::Class => {
let class: GcObj<Class> = obj.to_class();
{
class.do_stuff();
}
}
ValueKind::Fun => {
let fun: GcObj<Fun> = obj.to_fun();
{
string.do_stuff();
}
}
// ..
}