Search code examples
rustrust-obsolete

What is a modern analog to the deprecated std::raw::Repr?


I'm looking through some old (~2014) Rust code and I'm seeing this code block:

fn compile(self, func:&UncompiledFunction<'a>) -> &'a Val {
    unsafe {
        use std::raw::Repr;
        use std::mem::transmute as cast;
        let slice = self.repr();
        let ty = <&'a str as Compile<'a>>::get_type();
        let structure = Val::new(func, &ty);
        let offset_data = cast::<_, usize>(&slice.data) - cast::<_, usize>(&slice);
        let offset_len = cast::<_, usize>(&slice.len) - cast::<_, usize>(&slice);
        func.insn_store_relative(structure, offset_data, func.insn_of(mem::transmute::<_, isize>(slice.data)));
        func.insn_store_relative(structure, offset_len, func.insn_of(slice.len));
        structure
    }
}

According to the docs and this GitHub discussion std::raw::Repr and std::raw::Slice have been deprecated in favor of std::slice functions.

As someone with only a beginner's understanding of the std library I'm unsure how to translate these particular lines from the above block:

let slice = self.repr(); // `self` here is a `static str`
let offset_data = cast::<_, usize>(&slice.data) - cast::<_, usize>(&slice);
let offset_len = cast::<_, usize>(&slice.len) - cast::<_, usize>(&slice);

I was looking through the documentation for Repr with the hopes that I could produce an analogy with some function in the std::slice family, but nothing is immediately clear to me.

I'm hoping someone can explain to me what exactly Repr does (in different language) and what a more updated approach might be.


Solution

  • For x of type &[T] or &str:

    • The replacement for x.repr().data is x.as_ptr().
    • The replacement for x.repr().len is x.len().
    • The replacement for transmuting from std::raw::Slice back to &[T] or &str is std::slice::from_raw_parts (and optionally std::str::from_utf8_unchecked).

    However what this code does not just access the pointer and the length, it’s taking the address of those fields in order to compute their offset, presumably to later do some unsafe/unchecked memory reads or writes.

    The unhelpful answer is don’t do this. std::raw::Slice was removed precisely because we didn’t want to stabilize the exact memory layout of &[T] and &str. If this is possible at all, consider refactoring the code to not do these unchecked memory accesses but instead e.g. replace the whole string with std::str::from_utf8_unchecked(std::slice::from_raw_parts(new_pointer, new_len)).

    The practical answer is that the memory layout is very unlikely to change, and you’ll probably be ok if you hard-code:

    let offset_data = 0;
    let offset_len = std::mem::size_of::<usize>();