Decode {
#[allow(dead_code)] // block is only meant to drop offsets and entries
block: Vec<u8>,
offsets: ManuallyDrop<Box<[u8]>>, // unsafe ownership into `block`
entries: ManuallyDrop<Box<[u8]>>, // unsafe ownership into `block`
},
which is constructed using a block of bytes, that is made up of offsets
followed by entries.
On way to do is:
let offsets = block[..n].to_vec();
let entries = block[n..].to_vec();
which involves copying. To avoid this, I am doing
let (offsets, entries) = unsafe {
let ptr = block.as_mut_ptr();
let len = block.len();
let cap = block.capacity();
let offsets = Vec::from_raw_parts(ptr, n, n).into_boxed_slice();
let p = ptr.add(adjust);
let entries = Vec::from_raw_parts(p, l-n, c-n).into_boxed_slice();
(ManuallyDrop::new(offsets), ManuallyDrop::new(entries))
};
I want to know whether it is okay to it this way. Note that along with offsets and entries, the original block is owned by the
type. It is my understanding that when the type's value go out of
scope, drop will be called only for block.
Yes, realloc is the problem. Even the first one would be a problem if RawVec didn't bother checking that the capacity already matches the length. I wouldn't recommend relying on such implementation details.
Instead of ManuallyDrop<Box<_>>, to afterwards never drop, you should use &'static _ or NonNull<_> to express the borrowing idea (forbidden without unsafe because Rust sees it as self-referential).
Here is an implementation using Pin to enforce the implicit invariant: the bytes on the heap will not move / be mutated as long as block is not dropped.