>
wrapping/boxing/unboxing, as they have exactly the same native data representationRust's Box and Option> have the same representation as a C pointer to the same type, so this is true of Rust too.
You do have to wrap the type in source code to indicate what the ownership guarantees/contracts are. (Is this not also true of ATS? That is, if ATS code calls a C function that returns a pointer, how do you know how long that pointer is valid for and whether you're expected to free it?) But there is no runtime overhead/conversion.
> which undermines the initial safety argument
No, adding unsafe Rust does not undermine the safety argument (at least, no more than having any C somewhere in your address space does). See my reply in the comment section of TFA: https://lwn.net/Articles/830158/
(It's unfortunate that the Rust language used the "unsafe" keyword to mark blocks where you can access raw pointers, because it causes people to think that using such code is unsafe. Something like "manually_verified_safe" would have been better - the whole point of putting an "unsafe" block on a safe function is to write code that is safe to use that cannot benefit from the Rust compiler's checks. But at the boundary with C, it is impossible to have automated checks, because the relevant typing/safety information doesn't exist in C in the first place. It's no different from ATS code using $UN where you've manually verified that you're using a C function or C-created data in the way it's intended to be used.)