Add Option::as_ptr and Option::as_mut_ptr

When interfacing with C code, I find myself writing repetitive code like this a lot:

p_vertex_input_state: vertex_input_state
    .as_ref()
    .map(|p| p as *const _)
    .unwrap_or(ptr::null()),
p_input_assembly_state: input_assembly_state
    .as_ref()
    .map(|p| p as *const _)
    .unwrap_or(ptr::null()),
p_tessellation_state: tessellation_state
    .as_ref()
    .map(|p| p as *const _)
    .unwrap_or(ptr::null()),
p_viewport_state: viewport_state
    .as_ref()
    .map(|p| p as *const _)
    .unwrap_or(ptr::null()),
p_rasterization_state: rasterization_state
    .as_ref()
    .map(|p| p as *const _)
    .unwrap_or(ptr::null()),
...etc

The p_ members here are all pointers which can be null, while the other variables are Option. Some should be converted to a regular valid pointer, while None should become null. At least in my case this seems like a common enough operation that it might be useful to have two additional methods on Option:

pub fn as_ptr(&self) -> *const T {
    self
        .as_ref()
        .map(|p| p as *const _)
        .unwrap_or(ptr::null())
}

pub fn as_mut_ptr(&mut self) -> *mut T {
    self
        .as_mut()
        .map(|p| p as *mut _)
        .unwrap_or(ptr::null_mut())
}
2 Likes

Can you just define your FFI to take Option<&T>? This is well-defined as nullable:

https://doc.rust-lang.org/std/option/index.html#options-and-pointers-nullable-pointers

The major thing I'd be worried about is confusion between this (&Option<T> -> *const T) and the reffed version (Option<&T> -> *const T).

Given that Option<&_> is the "nullable reference" type (and ABI guaranteed to be a *const T), though, I think it does make sense to provide a way to go Option<&T> -> *const T.

So your original example would be opt.as_ref().as_ptr() instead.

(But also yes, if the FFI expects a pointer that respects Rust's reference rules or NULL, then defining the FFI as taking Option<&T> is best. But sometimes APIs require non-reference-compatible use of pointers, so those need to be defined as *const T.)

2 Likes

In this case the FFI is the Vulkan API, and the Rust bindings I'm using expose these values as pointers.