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/

Reply via email to