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!.

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/

--
Best Regards
Junjie Mao

Reply via email to