Sorry for the vague/misleading topic title but I have a question about this. I'd like to use the zerocopy crate to convert an array of bytes into a structure. The structure I'd like to convert to and from bytes looks like this in C:
typedef volatile struct tagHBA_MEM
{
// 0x00 - 0x2B, Generic Host Control
uint32_t cap; // 0x00, Host capability
uint32_t ghc; // 0x04, Global host control
uint32_t is; // 0x08, Interrupt status
uint32_t pi; // 0x0C, Port implemented
uint32_t vs; // 0x10, Version
uint32_t ccc_ctl; // 0x14, Command completion coalescing control
uint32_t ccc_pts; // 0x18, Command completion coalescing ports
uint32_t em_loc; // 0x1C, Enclosure management location
uint32_t em_ctl; // 0x20, Enclosure management control
uint32_t cap2; // 0x24, Host capabilities extended
uint32_t bohc; // 0x28, BIOS/OS handoff control and status
// 0x2C - 0x9F, Reserved
uint8_t rsv[0xA0-0x2C];
// 0xA0 - 0xFF, Vendor specific registers
uint8_t vendor[0x100-0xA0];
// 0x100 - 0x10FF, Port control registers
HBA_PORT ports[1]; // 1 ~ 32
} HBA_MEM;
HBA_PORT
looks like this in C:
typedef volatile struct tagHBA_PORT
{
uint32_t clb; // 0x00, command list base address, 1K-byte aligned
uint32_t clbu; // 0x04, command list base address upper 32 bits
uint32_t fb; // 0x08, FIS base address, 256-byte aligned
uint32_t fbu; // 0x0C, FIS base address upper 32 bits
uint32_t is; // 0x10, interrupt status
uint32_t ie; // 0x14, interrupt enable
uint32_t cmd; // 0x18, command and status
uint32_t rsv0; // 0x1C, Reserved
uint32_t tfd; // 0x20, task file data
uint32_t sig; // 0x24, signature
uint32_t ssts; // 0x28, SATA status (SCR0:SStatus)
uint32_t sctl; // 0x2C, SATA control (SCR2:SControl)
uint32_t serr; // 0x30, SATA error (SCR1:SError)
uint32_t sact; // 0x34, SATA active (SCR3:SActive)
uint32_t ci; // 0x38, command issue
uint32_t sntf; // 0x3C, SATA notification (SCR4:SNotification)
uint32_t fbs; // 0x40, FIS-based switch control
uint32_t rsv1[11]; // 0x44 ~ 0x6F, Reserved
uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
} HBA_PORT;
(Taken from https://wiki.osdev.org/AHCI.) As you can see, the author defines the array to only hold a single item, however this array can hold up to 32 items. Defined in Rust, this neatly translates into:
#[repr(C)]
#[derive(FromBytes)]
pub struct HbaMem {
pub cap: u32,
pub ghc: u32,
pub is: u32,
pub pi: u32,
pub vs: u32,
pub ccc_ctl: u32,
pub ccc_pts: u32,
pub em_loc: u32,
pub em_ctl: u32,
pub cap2: u32,
pub bohc: u32,
rsv: [u8; 116],
pub vendor: [u8; 96],
// Problem: dynamically sized type, may not decode into a structure properly
pub ports: &[HbaPort]
}
#[repr(C)]
#[derive(FromBytes)]
pub struct HbaPort {
pub clb: u32,
pub clbu: u32,
pub fb: u32,
pub fbu: u32,
pub is: u32,
pub ie: u32,
pub cmd: u32,
rsv0: u32,
pub tfd: u32,
pub sig: u32,
pub ssts: u32,
pub sctl: u32,
pub serr: u32,
pub sact: u32,
pub ci: u32,
pub sntf: u32,
pub fbs: u32,
rsv1: [u32; 11],
pub vendor: [u32; 4],
}
The problem is that zerocopy derivation requires structs (and their fields) to implement the Sized trait. Implementation of the FromBytes trait looks like this:
pub unsafe trait FromBytes {
// NOTE: The Self: Sized bound makes it so that FromBytes is still object
// safe.
#[doc(hidden)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;
}
So, my question is, do structs implement Sized even with dynamically-sized fields? Or what would be the best, most idiomatic way of dealing with this problem while making zerocopy work (hopefully)?