简体   繁体   中英

Pointer-stashing generics via `mem::transmute()`

I'm attempting to write Rust bindings for a C collection library (Judy Arrays [1]) which only provides itself room to store a pointer-width value. My company has a fair amount of existing code which uses this space to directly store non-pointer values such as pointer-width integers and small structs. I'd like my Rust bindings to allow type-safe access to such collections using generics, but am having trouble getting the pointer-stashing semantics working correctly.

The mem::transmute() function seems like one potential tool for implementing the desired behavior, but attempting to use it on an instance of a parameterized type yield a confusing-to-me compilation error.

Example code:

pub struct Example<T> {
    v: usize,
    t: PhantomData<T>,
}

impl<T> Example<T> {
    pub fn new() -> Example<T> {
        Example { v: 0, t: PhantomData }
    }

    pub fn insert(&mut self, val: T) {
        unsafe {
            self.v = mem::transmute(val);
        }
    }
}

Resulting error:

src/lib.rs:95:22: 95:36 error: cannot transmute to or from a type that contains type parameters in its interior [E0139]
src/lib.rs:95             self.v = mem::transmute(val);
                                   ^~~~~~~~~~~~~~

Does this mean a type consisting only of a parameter "contains type parameters in its interior" and thus transmute() just won't work here? Any suggestions of the right way to do this?

( Related question , attempting to achieve the same result, but not necessarily via mem::transmute() .)

[1] I'm aware of the existing rust-judy project, but it doesn't support the pointer-stashing I want, and I'm writing these new bindings largely as a learning exercise anyway.

Instead of transmuting T to usize directly, you can transmute a &T to &usize :

pub fn insert(&mut self, val: T) {
    unsafe {
        let usize_ref: &usize = mem::transmute(&val);
        self.v = *usize_ref;
    }
}

Beware that this may read from an invalid memory location if the size of T is smaller than the size of usize or if the alignment requirements differ. This could cause a segfault. You can add an assertion to prevent this:

assert_eq!(mem::size_of::<T>(), mem::size_of::<usize>());
assert!(mem::align_of::<usize>() <= mem::align_of::<T>());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM