So my embedded environment does not support allocation - everything must be statically allocated. I have a LARGE (complex) data structure that I can easily initialize with code, but it is really hard to initialize statically at compile time.
HOWEVER - RUST demands that I always declare and initialize what a pain.
a) The structure is defined in C - not rust (Think device driver structure)
b) I pass a pointer to that struct to a C initialization function (along with a device name)
c) RUST says no - I have to initialize the damn thing.
What's a workaround? The code is sort of like this:
// My example is a network interface structure */
#[repr(C)]
struct network_interface { /* lots of stuff here */ };
struct uart_interface { /* lots of stuff here */ };
/* i have others, I2C, SPI, etc */
/* I'd like to do something like this, note: Not initialized! */
pub static eth_FRONT_PANNEL : network_driver_interface;
pub static eth_BACK_PANNEL : network_driver_interface;;
pub static uartFRONT_PANNEL : uart_driver_interface;
pub static uartBACK_PANNEL : uart_driver_interface;
pub fn bsp_init_drivers()
{
ether_driver_initializer( ð_FRONT_PANNEL, "eth0" );
ether_driver_initializer( ð_BACK_PANNEL, "eth1" );
// other drivers here too
}
I effectively need to tell rust:
The variable FOO is initialized by means you cannot determine.
Well that's, of course, fundamentally unsafe. And Rust has things like NonZeroU8 that it can't just zero-initialize, so you have to give it a valid value of the type, no matter what. (Though of course you can wrap it in something that has a simple valid value, like None.)
Use MaybeUninit, take a pointer via as_mut_ptr() pass it to C, use assume_init_mut to get initialized mutable reference. I prefer using StaticCell::unint there, and static_cell in general, even on std, because it gives extremely convenient access to &'static mut T that is basically a miracle, not a type. It is small, safe to pin, reborrow asuch as you like, represents a full ownership but without a right to drop.
Additionally, if it is just a C struct... Just memzero it and pass to initializer? IIRC bindgen can generate some safe zeroing functions, or at least slap some zerocopy derives. Or manually construct with some garbage/zeros? Even if no, unsafe: const { MaybeUninit::zeroed().assume_init() } and pass a pointer to the zeroed struct. C doesn't have types like NonZeroU8.
It just doesn't work that way, unfortunately. Author is on no_std, so Rust doesn't know about any OS and locks, there's no OnceLock. And then, probably that C function is from some C library. Reimplementing a function from the C dependency is the last thing you want, especially if it is using some global linked lists or hardware MMIO (both are the baseline in embedded development). Except when it just zeroes the struct