How can I transmute a `MaybeUninit<T>` to a `T`? - rust

I'd like to transmute a MaybeUninit<T> to a T.
use std::mem::transmute;
use std::mem::MaybeUninit;
fn make_init<T: Sized>(mt: MaybeUninit<T>) -> T {
unsafe { transmute(mt) }
}
fn main() {
make_init(MaybeUninit::new(1));
}
However this program gives me:
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
What's the right way to do this?

Generally, the workaround when the compiler doesn't know that types have the same size is to use transmute_copy(), but in your case there is MaybeUninit::assume_init() that does exactly what you want.

Related

How to write a wrapper enum for C error codes?

I am writing a Rust wrapper for a C API. It contains a function that may fail, in which case it returns an error code encoded as an int. Let's call these SOME_ERROR and OTHER_ERROR, and they will have the values 1 and 2, respectively. I want to write an enum wrapping these error codes, as follows:
// Declared in a seperate C header
const SOME_ERROR: c_int = 1;
const OTHER_ERROR: c_int = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
enum ErrorCodeWrapper {
SomeError = SOME_ERROR,
OtherError = OTHER_ERROR,
}
Here comes my first question. It does not seem to be possible to specify std::os::raw::c_int as the underlying type of an enum. But I do feel like it should be, as int isn't required to be 32 bits wide. Is there any way to achieve this?
I'd then like some methods to convert to and from a raw error code:
use std::os::raw::c_int;
impl ErrorCodeWrapper {
fn from_raw(raw: c_int) -> Option<Self> {
match raw {
SOME_ERROR => Some(Self::SomeError),
OTHER_ERROR => Some(Self::OtherError),
_ => None
}
}
unsafe fn from_raw_unchecked(raw: c_int) -> Self {
*(&raw as *const _ as *const Self)
}
fn as_raw(self) -> c_int {
unsafe { *(&self as *const _ as *const c_int) }
}
}
The only way I could find to "bit-cast" c_int to and from ErrorCodeWrapper is to do it C-style, by casting a pointer and then dereferencing it. This should work as ErrorCodeWrapper and int have the same size and alignment, and the value of every ErrorCodeWrapper variant maps to its corresponding error code. However, this solution is a bit to hackery for my taste; is there a more idiomatic one, like C++'s std::bit_cast?
Furthermore, is it possible to replace the match statement in ErrorCodeWrapper::from_raw with a simple validity check, for simpler code in the case of more variants?
The last bit of code, the necessary error implementations:
use std::{fmt::Display, error::Error};
impl Display for ErrorCodeWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
Self::SomeError => "some error",
Self::OtherError => "some other error",
})
}
}
impl Error for ErrorCodeWrapper {}
Now let's imagine a second wrapper, SuperErrorCodeWrapper, that includes some or all of the variants of ErrorCodeWrapper, with the same description and everything. That would mean that either:
One could "factor out" the common variants of ErrorCodeWrapper and SuperErrorCodeWrapper into a separate enum. ErrorCodeWrapper and SuperErrorCodeWrapper would then have a variant containing this enum. However I am not really fond of this kind of nesting, which would seem arbitrary when focusing on one particular error.
Duplicating the common variants across both enums.
The latter would add a lot to the existing boilerplate. Could a macro be a viable option to handle this?
Is there a library that could handle all this for me?
Here comes my first question. It does not seem to be possible to specify std::os::raw::c_int as the underlying type of an enum. But I do feel like it should be, as int isn't required to be 32 bits wide. Is there any way to achieve this?
No. There was an RFC in 2016 (I can't even access the RFC text. it seems it was removed), but it was closed:
We discussed in the #rust-lang/lang meeting and decided that while the RFC is well-motivated, it doesn't sufficiently address the various implementation complexities that must be overcome nor the interaction with hygiene. It would make sense to extend the attribute system to support more general paths before considering this RFC (but that is a non-trivial undertaking).
The best you can do is to use #[cfg_attr] with all configurations. c_int is defined here as, and all current options are
#[cfg_attr(any(target_arch = "avr", target_arch = "msp430"), repr(i16))]
#[cfg_attr(not(any(target_arch = "avr", target_arch = "msp430")), repr(i32))]
enum ErrorCodeWrapper { ... }
is there a more idiomatic one, like C++'s std::bit_cast?
Yes; std::mem::transmute().
One could "factor out" the common variants of ErrorCodeWrapper and SuperErrorCodeWrapper into a separate enum. ErrorCodeWrapper and SuperErrorCodeWrapper would then have a variant containing this enum.
If you do that, you lose the ability to transmute() (or pointer cast, it doesn't matter), as they'll be no longer layout compatible with int.
Could a macro be a viable option to handle this?
Probably yes.
Is there a library that could handle all this for me?
I don't know all library that handles all of this (although it is possible that one exists), but there is thiserror (and friends) for the Error and Display implementations, and strum::FromRepr that can help you with from_raw().

Why do most ffi functions use raw pointers instead of references?

Both in ffi tutorials and in automatically generated interfaces, *const T pointers are used most of the time. As far as I know the difference between &T and *const T is only that *const T doesn't have to fulfill certain conditions like not being null and is unsafe to dereference.
fn main() {
unsafe {
do_something(&TestStruct {data: 3})
}
}
#[repr(C)]
pub struct TestStruct {
data: u32
}
extern "C" {
fn do_something(arg: &TestStruct);
}
This code can be compiled and runs. Because external functions are similar in usage to internal ones, i don't understand why raw pointers are used there as the default.
An element of answer can probably be found in the fact that references must be aligned. As using un-aligned references is undefined behaviour, and the alignment of the pointers cannot be guaranteed in FFIs, defaulting to pointers seems to be a sane choice

FFI: Convert nullable pointer to option

I'm using rust-bindgen to access a C library from Rust. Some functions return nullable pointers to structs, which bindgen represents as
extern "C" {
pub fn get_some_data() -> *const SomeStruct;
}
Now, for a higher level wrapper, I would like to convert this to a Option<&'a SomeStruct> with an appropriate lifetime. Due to the nullable pointer optimization, this is actually represented identically to *const SomeStruct. However, I couln't find any concise syntax to cast between the two. Transmuting
let data: Option<&'a SomeStruct> = unsafe { mem::transmute( get_some_data() ) };
and reborrowing
let data_ptr = get_some_data();
let data = if data_ptr.is_null() { None } else { unsafe { &*data_ptr } };
could be used. The docs for mem::transmute state that
transmute is incredibly unsafe. There are a vast number of ways to cause undefined behavior with this function. transmute should be the absolute last resort.
and recommends re-borrowing instead for
Turning a *mut T into an &mut T
However, for the nullable pointer, this is quite clumsy as shown in the second example.
Q: Is there a more concise Syntax for this cast? Alternatively, is there a way to tell bindgen to generate
extern "C" {
pub fn get_some_data() -> Option<&SomeStruct>;
}
directly?
Use <*const T>::as_ref¹:
let data = unsafe { get_some_data().as_ref() };
Since a raw pointer may not point to a valid object of sufficient lifetime for any 'a, as_ref is unsafe to call.
There is a corresponding as_mut for *mut T → Option<&mut T>.
¹ This is a different as_ref from, for example, AsRef::as_ref and Option::as_ref, both of which are common in safe code.

How to idiomatically convert from Option<T> to Result<T, ()>?

I'm a Rust newbie! What's the best way to convert from an Option<T> to a Result<T, ()>?
The TryFrom trait seems prevalent and returns a Result. The popular num_traits' NumCast has many conversions but they all return an Option<T>. Similarly, as do the NonZero* constructors such as NonZeroI32 in the Rust Standard Library. I then noticed that NumCast implements a from() that returns an Option<T> so I was thinking that maybe it had a non-standard way of doing things in general but then I saw the NonZero* implementations and questioned that idea.
Regardless, converting from Options to Results seem frequent and I haven't found a neat way to do yet. E.g.:
/// Add common conversion from an i32 to a non-zero i32.
impl TryFrom<Container<i32>> for Container<NonZeroI32> {
type Error = ();
fn try_from(container: Container<i32>) -> Result<Self, ()> {
// NonZeroI32::new() returns an Option not a Result. Try a helper.
Ok(Self(option_to_result(NonZeroI32::new(container.0))?))
}
}
/// Helper function to convert from an Option to a Result (both types are
/// foreign and so is From).
fn option_to_result<T>(option: Option<T>) -> Result<T, ()> {
if let Some(some) = option {
Ok(some)
} else {
Err(())
}
}
/// Add another common conversion from an i32 to an i16.
impl TryFrom<Container<i32>> for Container<i16> {
type Error = ();
fn try_from(container: Container<i32>) -> Result<Self, ()> {
// NumCast::from() also returns an Option not a Result. Try map_or() instead
// of the helper.
Ok(Self(NumCast::from(container.0).map_or(Err(()), |x| Ok(x))?))
}
}
(Above examples in the Rust Playground.)
These NumCast, NonZero*, and TryFrom conversions seem common enough but my approach feels clumsy as though I'm pitting the Option and Result types against each other. I struggle with these conversions and also miss the fundamental point of the Option type given Result<T,()> feels similar.
So, what's the idiomatic way to convert an Option<T> to Result<T,()> in Rust 2018?
Option has the ok_or method, usable for exactly this (well, for more wide case, in fact, but your request fits here too):
fn option_to_result<T>(option: Option<T>) -> Result<T, ()> {
option.ok_or(())
}
Modified playground

How do I specify a generic type where one of the types is not needed?

I'm trying to use a generic datatype where one of the types is not needed (edge weights in a graph). I've been thinking to use the never type for this, which would look something like this:
#![feature(never_type)]
struct Foo<T> {
bar: T
}
impl<T> Foo<T> {
fn foo(&mut self, bar: T) {
self.bar = bar;
}
}
fn main() {
let mut foo: Foo<!> = Foo { bar: "nada" };
foo.foo("nada");
}
This obviously results in a type-mismatch for the "nada" placeholders, but just typing nothing will cause other errors. Is ! the right type to use here, and if so, what's the correct syntax?
I've gotten it to work using () instead of !, but I'm a bit unsure as to whether that's the proper choice of type. I believe in terms of efficiency it should make no difference, as () has no memory footprint?
() is the right choice. It is a type with a single value (also named ()), so it has a value, but contains no information.
! doesn't have any value, so if you put it in a struct the struct type doesn't have a value either and is basically unusable.

Resources