Enum dispatch, casting between mutable and const variants of the ref struct

⚓ rust    📅 2025-07-03    👤 surdeus    👁️ 3      

surdeus

I have a project where I use enum dispatch (as opposed to dyn) in order to get better control over inlining and branch prediction.

The issue I'm having is that I have mutable and const methods, and therefore I need two variants of the ref struct. The code is structured like this:

trait MyTrait {
    fn const_f(&self);
    fn mut_f(&mut self);
}

struct TypeA {}
impl MyTrait for TypeA {
    fn const_f(&self) {}
    fn mut_f(&mut self) {}
}

struct TypeB {}
impl MyTrait for TypeB {
    fn const_f(&self) {}
    fn mut_f(&mut self) {}
}

enum MyRef<'a> {
    TypeA(&'a TypeA),
    TypeB(&'a TypeB),
}

impl MyRef<'_> {
    fn const_f(&self) {
        match self {
            Self::TypeA(t) => t.const_f(),
            Self::TypeB(t) => t.const_f(),
        }
    }
    fn mut_f(&mut self) { unreachable!() }
}

enum MyRefMut<'a> {
    TypeA(&'a mut TypeA),
    TypeB(&'a mut TypeB),
}

impl MyRefMut<'_> {
    fn const_f(&self) {
        match self {
            Self::TypeA(t) => t.const_f(),
            Self::TypeB(t) => t.const_f(),
        }
    }
    fn mut_f(&mut self) {
        match self {
            Self::TypeA(t) => t.mut_f(),
            Self::TypeB(t) => t.mut_f(),
        }
    }
}

This is generally a yucky amount of boilerplate, but I shrug that off because having the dispatch tables like this gives me a place to do things like insert a #[cold] wrapper around certain paths, etc.

However, having two identical sets of dispatch tables, for for the mutable and const variants of the ref structs, feels like a bridge too far. Or at least the straw that's breaking this particular camel's back. Also, it can't be good for the instruction cache to have twice as many dispatch tables as is needed - I don't think the compiler is able to figure that out and deduplicate them.

So I could ensure the two enums get the same discriminant tag values, and then transmute the mutable variant into the const variant. But that feels a little dangerous.

What would you guys do in this situation?

Thanks for any thoughts.

3 posts - 2 participants

Read full topic

🏷️ rust_feed