How do I extract an initialized field from an uninitialized struct

I'm wrapping some C code, and the way the API works, sometimes only part of the struct is initialized (we are given a pointer to the data which we do not own). IIUC, this means I cannot create a reference to the struct in Rust: I need to somehow create a reference directly to the fields in question. How do I do this?

My current approach is something like the following (playground)

use std::ffi::c_void;


// imagine this struct
pub struct Foo;

#[repr(C)]
struct CData {
    foo: Foo, // uninit
    bar: u8,
}

// to get the data in cdata.bar without creating in uninit ref to foo, imagine the following fn:
extern "C" fn get_data() -> *mut c_void {
    // implementation for example's sake
    let x = Box::<CData>::new_uninit();
    let raw = Box::into_raw(x) as *mut CData;
    unsafe { (&raw mut (*raw).bar).write(42) };
    raw as *mut c_void
}

// in my code I do
pub fn get_data_wrapped() -> u8 {
    unsafe { 
        let data = get_data() as *mut CData;
        let field = &raw const (*data).bar;
        *field
    }
}

but I'm worried I'm dereferencing the pointer of not fully init data - meaning I'm breaking Rust rules.

Maybe union is something you want?

what you have rn is completely ok.
raw pointers have no validity requirements.
as long as the bar field was initialized, you are allowed to read it.
and your way to initialize it was correct too.

Just to be sure: do you know MaybeUninit?

the dereference operator * itself does nothing, deferencing a raw pointer simply evaluates to a "place" expression.

this is case, the place expression (*raw) is mapped to its field (*raw).bar, which in turn is used for the &raw operator, which does NOT read the value from the (uninitialized) location, so you don't have UB here.

#[repr(C)]
struct CData {
    foo: MaybeUninit<Foo>,
    bar: u8
}

whilst this certainly has good uses, i would not recommend it in general as it makes using initialized CDatas harder.
really what would be best completely depends on what the real use case is.

for example, with the given sample code, get_data_wrapped will leak memory each time it is called, which i hope is not what happens in real code.

Yes in reality the pointer comes from C code, that is also responsible for freeing the memory.

Do I need to use &raw const at all or can I use (*data).bar to get the data?

For future reference, you can use cargo miri to test a lot of these things against an automated UB checker. It can't handle FFI, but you could make a test project with your example code and play with that.

That's a good idea - I tried miri and it didn't work because of FFI and I gave up. I didn't think of creating a toy crate to play with miri.

I prefer having one unsafe operation per block. I know that not everyone has that preference, but if you go with (*data).bar, I think it'd be best to comment that there's two unsafe operations.

In &raw const (*data).bar where data is a raw pointer (no Deref::deref), there is one unsafe operation; namely, it performs an inbounds offset on the data pointer (by the offset of the bar field of the pointee type). See the add_of macro, which is the older form of &raw const (before the better syntax was stabilized). The requirement of being inbounds is why it's unsafe (and this requirement obviously holds in your case).

In (*data).bar, it both performs that offset and reads from the produced pointer.