Browse Source
Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>pull/291/head
15 changed files with 16 additions and 239 deletions
@ -1,168 +0,0 @@ |
|||
// SPDX-License-Identifier: MIT
|
|||
|
|||
#![doc(hidden)] |
|||
//! This module provides macros that emulate the functionality of
|
|||
//! `core::mem::offset_of` on older versions of Rust.
|
|||
//!
|
|||
//! Documentation is hidden because it only exposes macros, which
|
|||
//! are exported directly from `qemu_api`.
|
|||
|
|||
/// This macro provides the same functionality as `core::mem::offset_of`,
|
|||
/// except that only one level of field access is supported. The declaration
|
|||
/// of the struct must be wrapped with `with_offsets! { }`.
|
|||
///
|
|||
/// It is needed because `offset_of!` was only stabilized in Rust 1.77.
|
|||
#[cfg(not(has_offset_of))] |
|||
#[macro_export] |
|||
macro_rules! offset_of { |
|||
($Container:ty, $field:ident) => { |
|||
<$Container>::OFFSET_TO__.$field |
|||
}; |
|||
} |
|||
|
|||
/// A wrapper for struct declarations, that allows using `offset_of!` in
|
|||
/// versions of Rust prior to 1.77
|
|||
#[macro_export] |
|||
macro_rules! with_offsets { |
|||
// This method to generate field offset constants comes from:
|
|||
//
|
|||
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10a22a9b8393abd7b541d8fc844bc0df
|
|||
//
|
|||
// used under MIT license with permission of Yandros aka Daniel Henry-Mantilla
|
|||
( |
|||
$(#[$struct_meta:meta])* |
|||
$struct_vis:vis |
|||
struct $StructName:ident { |
|||
$( |
|||
$(#[$field_meta:meta])* |
|||
$field_vis:vis |
|||
$field_name:ident : $field_ty:ty |
|||
),* |
|||
$(,)? |
|||
} |
|||
) => ( |
|||
#[cfg(not(has_offset_of))] |
|||
const _: () = { |
|||
struct StructOffsetsHelper<T>(std::marker::PhantomData<T>); |
|||
const END_OF_PREV_FIELD: usize = 0; |
|||
|
|||
// populate StructOffsetsHelper<T> with associated consts,
|
|||
// one for each field
|
|||
$crate::with_offsets! { |
|||
@struct $StructName |
|||
@names [ $($field_name)* ] |
|||
@tys [ $($field_ty ,)*] |
|||
} |
|||
|
|||
// now turn StructOffsetsHelper<T>'s consts into a single struct,
|
|||
// applying field visibility. This provides better error messages
|
|||
// than if offset_of! used StructOffsetsHelper::<T> directly.
|
|||
pub |
|||
struct StructOffsets { |
|||
$( |
|||
$field_vis |
|||
$field_name: usize, |
|||
)* |
|||
} |
|||
impl $StructName { |
|||
pub |
|||
const OFFSET_TO__: StructOffsets = StructOffsets { |
|||
$( |
|||
$field_name: StructOffsetsHelper::<$StructName>::$field_name, |
|||
)* |
|||
}; |
|||
} |
|||
}; |
|||
); |
|||
|
|||
( |
|||
@struct $StructName:ident |
|||
@names [] |
|||
@tys [] |
|||
) => (); |
|||
|
|||
( |
|||
@struct $StructName:ident |
|||
@names [$field_name:ident $($other_names:tt)*] |
|||
@tys [$field_ty:ty , $($other_tys:tt)*] |
|||
) => ( |
|||
#[allow(non_local_definitions)] |
|||
#[allow(clippy::modulo_one)] |
|||
impl StructOffsetsHelper<$StructName> { |
|||
#[allow(nonstandard_style)] |
|||
const $field_name: usize = { |
|||
const ALIGN: usize = std::mem::align_of::<$field_ty>(); |
|||
const TRAIL: usize = END_OF_PREV_FIELD % ALIGN; |
|||
END_OF_PREV_FIELD + (if TRAIL == 0 { 0usize } else { ALIGN - TRAIL }) |
|||
}; |
|||
} |
|||
const _: () = { |
|||
const END_OF_PREV_FIELD: usize = |
|||
StructOffsetsHelper::<$StructName>::$field_name + |
|||
std::mem::size_of::<$field_ty>() |
|||
; |
|||
$crate::with_offsets! { |
|||
@struct $StructName |
|||
@names [$($other_names)*] |
|||
@tys [$($other_tys)*] |
|||
} |
|||
}; |
|||
); |
|||
} |
|||
|
|||
#[cfg(test)] |
|||
mod tests { |
|||
use crate::offset_of; |
|||
|
|||
#[repr(C)] |
|||
struct Foo { |
|||
a: u16, |
|||
b: u32, |
|||
c: u64, |
|||
d: u16, |
|||
} |
|||
|
|||
#[repr(C)] |
|||
struct Bar { |
|||
pub a: u16, |
|||
pub b: u64, |
|||
c: Foo, |
|||
d: u64, |
|||
} |
|||
|
|||
crate::with_offsets! { |
|||
#[repr(C)] |
|||
struct Bar { |
|||
pub a: u16, |
|||
pub b: u64, |
|||
c: Foo, |
|||
d: u64, |
|||
} |
|||
} |
|||
|
|||
#[repr(C)] |
|||
pub struct Baz { |
|||
b: u32, |
|||
a: u8, |
|||
} |
|||
crate::with_offsets! { |
|||
#[repr(C)] |
|||
pub struct Baz { |
|||
b: u32, |
|||
a: u8, |
|||
} |
|||
} |
|||
|
|||
#[test] |
|||
fn test_offset_of() { |
|||
const OFFSET_TO_C: usize = offset_of!(Bar, c); |
|||
|
|||
assert_eq!(offset_of!(Bar, a), 0); |
|||
assert_eq!(offset_of!(Bar, b), 8); |
|||
assert_eq!(OFFSET_TO_C, 16); |
|||
assert_eq!(offset_of!(Bar, d), 40); |
|||
|
|||
assert_eq!(offset_of!(Baz, b), 0); |
|||
assert_eq!(offset_of!(Baz, a), 4); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue