Generic summary: I want to do somewhat, found a technique which is inconvenient, and want to make sure no one knows a more convenient technique before i file an RFC. Know a better way to do the following?
EDIT: Now as i think of it, i could potentially try a compiler plugin rather than an RFC, which raises the question too whether we think this is worthy to include in the stock compiler. Nonetheless, my earlier question remains.
I have a parametric struct, all whose members are essentially pointers of some kinds (e.g. Arc
, Vec
), for example:
struct T<A: ?Sized, B> {
x: Arc<A>,
y: Vec<B>,
}
and want an array of these heterogeneous in the type parametres only, with the struct itself and the vtable pointer (or better yet, the vtable itself) all stored together contiguously. This is possible in unsafe Rust:
struct T {
x: *mut (),
y: Vec<()>,
method1: fn(&T, x: A1, ...) -> Z1,
method2: fn(T, x: A2, ...) -> Z2,
drop: fn(&mut T),
}
impl T {
fn method1(&self, x: A1, ...) -> Z1 { (self.method1)(self, x, ...) }
fn method2(&self, x: A2, ...) -> Z2 { (self.method2)(self, x, ...) }
}
impl Drop for T {
fn drop(&mut self) { (self.drop)(self) }
}
struct ActualT<A: ?Sized, B> {
x: Arc<A>,
y: Vec<B>,
method1: fn(&ActualT<A, B>, x: A1, ...) -> Z1,
method2: fn(ActualT<A, B>, x: A2, ...) -> Z2,
drop: fn(&mut ActualT<A, B>),
}
impl<A: ?Sized, B> ActualT<A, B> {
fn method1(&self, x: A1, ...) -> Z1 { _ }
fn method2(self, x: A2, ...) -> Z2 { _ }
fn do_drop(&mut self) { core::mem::drop(self) }
}
fn mkT() -> T {
type AT = ActualT<SomeA, SomeB>;
core::mem::transmute::<AT, T>(ActualT {
x: _,
y: _,
method1: AT::method1,
method2: AT::method2,
drop: AT::do_drop,
})
}
which essentially unpacks the struct we actually want and the vtable into a new struct, which has no parametres and can be held in a Vec
or whatever. But this is quite verbose and cumbersome, and i feel rustc
ought to be able to generate this code for me, lest Rust fall short of its pledge of zero-cost abstractions, and so i needn't write unsafe code every time.