Paolo Bonzini <pbonz...@redhat.com> writes:
> On Thu, Oct 17, 2024 at 7:35 AM Junjie Mao <junjie....@hotmail.com> wrote: >> Paolo Bonzini <pbonz...@redhat.com> writes: >> > offset_of! was stabilized in Rust 1.77.0. Use an alternative implemenation >> > that was found on the Rust forums, and whose author agreed to license as >> > MIT for use in QEMU. >> > >> > The alternative allows only one level of field access, but apart >> > from this can be used just by replacing core::mem::offset_of! with >> > qemu_api::offset_of!. >> >> How about a macro like this (which essentially comes from memoffset >> crate [1])? It has the same use as core::mem::offset_of! (except the >> same single-level limitation) and does not need wrapping structures with >> with_offsets!. > > Unfortunately offset_from is not available in const context, and > offset_of! is needed to fill in the Property and VMStateDescription > arrays. > > That said, I noticed now that declare_properties! does not declare the > resulting array as const, so that would be possible. But if > declare_properties could use a non-mut static, that would be better. Agree. Then how about converting with_offsets! to a derive attribute (e.g. #[derive(offsets)])? The current approach introduces one more level of indentation. When we later upgrade the minimal supported version of Rust and switch to std::mem::offset_of!, we'll need a large diff to adjust the indentation which may be annoying to rebase upon. An attribute seems easier to manage. I can help draft the macro early next week if you think that is valuable. Junjie Mao > > Paolo > >> macro_rules! offset_of { >> ($parent:ty, $field:tt) => {{ >> let uninit = std::mem::MaybeUninit::<$parent>::uninit(); >> let base = uninit.as_ptr(); >> // SAFETY: >> // >> // MaybeUninit<$parent> has the same size and alignment as $parent, >> so >> // projection to $field is in bound. >> // >> // addr_of! does not create intermediate references to the >> uninitialized >> // memory, thus no UB is involved. >> let field = unsafe { std::ptr::addr_of!((*base).$field) }; >> // SAFETY: >> // >> // Both base and field point to the MaybeUninit<$parent> and are >> casted >> // to u8 for calculating their distance. >> unsafe { field.cast::<u8>().offset_from(base.cast::<u8>()) as usize } >> }}; >> } >> >> [1] https://docs.rs/memoffset/latest/memoffset/