144. Vec::into_raw_parts — Hand a Vec to C Without the ManuallyDrop Dance
You want to give a Rust-allocated buffer to C and re-take it later. That means handing over (ptr, len, capacity) — and historically, prying those three out of a Vec without freeing the allocation meant wrapping the vector in ManuallyDrop first. Rust 1.93 stabilises Vec::into_raw_parts, a single safe call that returns the triple and consumes the Vec for you.
The pain: extracting parts while suppressing drop
The classic recipe leaks the Vec’s destructor on purpose so the C side owns the memory. You need three reads and a guard to keep Drop from racing the allocator:
| |
It works, but the ManuallyDrop wrapper exists only to keep the destructor from running. Forget it, write mem::forget(v) in the wrong order, or read capacity() after the move and you’ve got a use-after-free or a leak.
The fix: one safe call, three return values
Vec::into_raw_parts(self) -> (*mut T, usize, usize) consumes the Vec, hands you the pointer-length-capacity triple, and leaves the allocation alive for you to manage:
| |
No wrapper, no separate field reads, no chance of accidentally calling a &self method after the move. The method is const, too.
String::into_raw_parts follows the same shape
String gets the same treatment in 1.93. The triple is (*mut u8, usize, usize), which is what String::from_raw_parts wants back:
| |
The pairing is the point: into_raw_parts is safe (the Vec/String is gone, no aliasing exists yet), and from_raw_parts is unsafe (you’re asserting the triple came from a matching allocator with the right layout). The split keeps the unsafety where it actually lives.
When to reach for it
Any FFI boundary where the C side will hold the buffer for a while: graphics buffers, codec frames, command queues, anything with an extern "C" fn free_my_thing(ptr, len, cap) callback. Also handy when you’re building your own typed handles around a raw allocation — Box::into_raw covers the single-value case; into_raw_parts covers the variable-length one.
If you only need the pointer and nothing will ever reclaim the allocation, Vec::leak is still the shorter call. Reach for into_raw_parts the moment the capacity matters — i.e. anyone, anywhere, might want to give the memory back.