Il ven 18 ott 2024, 05:16 Junjie Mao <junjie....@hotmail.com> ha scritto:
> > 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. > Ok, using quote! to generate the with_offsets! {} call should be easy. Paolo > 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/ > >