160636f74Sopenharmony_ci// Copyright (c) 2017 Gilad Naaman 260636f74Sopenharmony_ci// 360636f74Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a copy 460636f74Sopenharmony_ci// of this software and associated documentation files (the "Software"), to deal 560636f74Sopenharmony_ci// in the Software without restriction, including without limitation the rights 660636f74Sopenharmony_ci// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 760636f74Sopenharmony_ci// copies of the Software, and to permit persons to whom the Software is 860636f74Sopenharmony_ci// furnished to do so, subject to the following conditions: 960636f74Sopenharmony_ci// 1060636f74Sopenharmony_ci// The above copyright notice and this permission notice shall be included in all 1160636f74Sopenharmony_ci// copies or substantial portions of the Software. 1260636f74Sopenharmony_ci// 1360636f74Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1460636f74Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1560636f74Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1660636f74Sopenharmony_ci// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1760636f74Sopenharmony_ci// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1860636f74Sopenharmony_ci// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1960636f74Sopenharmony_ci// SOFTWARE. 2060636f74Sopenharmony_ci 2160636f74Sopenharmony_ci/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as 2260636f74Sopenharmony_ci/// much as is possible currently. 2360636f74Sopenharmony_ci#[cfg(maybe_uninit)] 2460636f74Sopenharmony_ci#[macro_export] 2560636f74Sopenharmony_ci#[doc(hidden)] 2660636f74Sopenharmony_cimacro_rules! _memoffset__let_base_ptr { 2760636f74Sopenharmony_ci ($name:ident, $type:ty) => { 2860636f74Sopenharmony_ci // No UB here, and the pointer does not dangle, either. 2960636f74Sopenharmony_ci // But we have to make sure that `uninit` lives long enough, 3060636f74Sopenharmony_ci // so it has to be in the same scope as `$name`. That's why 3160636f74Sopenharmony_ci // `let_base_ptr` declares a variable (several, actually) 3260636f74Sopenharmony_ci // instead of returning one. 3360636f74Sopenharmony_ci let uninit = $crate::__priv::mem::MaybeUninit::<$type>::uninit(); 3460636f74Sopenharmony_ci let $name: *const $type = uninit.as_ptr(); 3560636f74Sopenharmony_ci }; 3660636f74Sopenharmony_ci} 3760636f74Sopenharmony_ci#[cfg(not(maybe_uninit))] 3860636f74Sopenharmony_ci#[macro_export] 3960636f74Sopenharmony_ci#[doc(hidden)] 4060636f74Sopenharmony_cimacro_rules! _memoffset__let_base_ptr { 4160636f74Sopenharmony_ci ($name:ident, $type:ty) => { 4260636f74Sopenharmony_ci // No UB right here, but we will later dereference this pointer to 4360636f74Sopenharmony_ci // offset into a field, and that is UB because the pointer is dangling. 4460636f74Sopenharmony_ci let $name = $crate::__priv::mem::align_of::<$type>() as *const $type; 4560636f74Sopenharmony_ci }; 4660636f74Sopenharmony_ci} 4760636f74Sopenharmony_ci 4860636f74Sopenharmony_ci/// Macro to compute the distance between two pointers. 4960636f74Sopenharmony_ci#[cfg(any(feature = "unstable_const", stable_const))] 5060636f74Sopenharmony_ci#[macro_export] 5160636f74Sopenharmony_ci#[doc(hidden)] 5260636f74Sopenharmony_cimacro_rules! _memoffset_offset_from_unsafe { 5360636f74Sopenharmony_ci ($field:expr, $base:expr) => {{ 5460636f74Sopenharmony_ci let field = $field; // evaluate $field outside the `unsafe` block 5560636f74Sopenharmony_ci let base = $base; // evaluate $base outside the `unsafe` block 5660636f74Sopenharmony_ci // Compute offset, with unstable `offset_from` for const-compatibility. 5760636f74Sopenharmony_ci // (Requires the pointers to not dangle, but we already need that for `raw_field!` anyway.) 5860636f74Sopenharmony_ci unsafe { (field as *const u8).offset_from(base as *const u8) as usize } 5960636f74Sopenharmony_ci }}; 6060636f74Sopenharmony_ci} 6160636f74Sopenharmony_ci#[cfg(not(any(feature = "unstable_const", stable_const)))] 6260636f74Sopenharmony_ci#[macro_export] 6360636f74Sopenharmony_ci#[doc(hidden)] 6460636f74Sopenharmony_cimacro_rules! _memoffset_offset_from_unsafe { 6560636f74Sopenharmony_ci ($field:expr, $base:expr) => { 6660636f74Sopenharmony_ci // Compute offset. 6760636f74Sopenharmony_ci ($field as usize) - ($base as usize) 6860636f74Sopenharmony_ci }; 6960636f74Sopenharmony_ci} 7060636f74Sopenharmony_ci 7160636f74Sopenharmony_ci/// Calculates the offset of the specified field from the start of the named struct. 7260636f74Sopenharmony_ci/// 7360636f74Sopenharmony_ci/// ## Examples 7460636f74Sopenharmony_ci/// ``` 7560636f74Sopenharmony_ci/// use memoffset::offset_of; 7660636f74Sopenharmony_ci/// 7760636f74Sopenharmony_ci/// #[repr(C, packed)] 7860636f74Sopenharmony_ci/// struct Foo { 7960636f74Sopenharmony_ci/// a: u32, 8060636f74Sopenharmony_ci/// b: u64, 8160636f74Sopenharmony_ci/// c: [u8; 5] 8260636f74Sopenharmony_ci/// } 8360636f74Sopenharmony_ci/// 8460636f74Sopenharmony_ci/// fn main() { 8560636f74Sopenharmony_ci/// assert_eq!(offset_of!(Foo, a), 0); 8660636f74Sopenharmony_ci/// assert_eq!(offset_of!(Foo, b), 4); 8760636f74Sopenharmony_ci/// } 8860636f74Sopenharmony_ci/// ``` 8960636f74Sopenharmony_ci/// 9060636f74Sopenharmony_ci/// ## Notes 9160636f74Sopenharmony_ci/// Rust's ABI is unstable, and [type layout can be changed with each 9260636f74Sopenharmony_ci/// compilation](https://doc.rust-lang.org/reference/type-layout.html). 9360636f74Sopenharmony_ci/// 9460636f74Sopenharmony_ci/// Using `offset_of!` with a `repr(Rust)` struct will return the correct offset of the 9560636f74Sopenharmony_ci/// specified `field` for a particular compilation, but the exact value may change 9660636f74Sopenharmony_ci/// based on the compiler version, concrete struct type, time of day, or rustc's mood. 9760636f74Sopenharmony_ci/// 9860636f74Sopenharmony_ci/// As a result, the value should not be retained and used between different compilations. 9960636f74Sopenharmony_ci#[macro_export(local_inner_macros)] 10060636f74Sopenharmony_cimacro_rules! offset_of { 10160636f74Sopenharmony_ci ($parent:path, $field:tt) => {{ 10260636f74Sopenharmony_ci // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). 10360636f74Sopenharmony_ci _memoffset__let_base_ptr!(base_ptr, $parent); 10460636f74Sopenharmony_ci // Get field pointer. 10560636f74Sopenharmony_ci let field_ptr = raw_field!(base_ptr, $parent, $field); 10660636f74Sopenharmony_ci // Compute offset. 10760636f74Sopenharmony_ci _memoffset_offset_from_unsafe!(field_ptr, base_ptr) 10860636f74Sopenharmony_ci }}; 10960636f74Sopenharmony_ci} 11060636f74Sopenharmony_ci 11160636f74Sopenharmony_ci/// Calculates the offset of the specified field from the start of the tuple. 11260636f74Sopenharmony_ci/// 11360636f74Sopenharmony_ci/// ## Examples 11460636f74Sopenharmony_ci/// ``` 11560636f74Sopenharmony_ci/// use memoffset::offset_of_tuple; 11660636f74Sopenharmony_ci/// 11760636f74Sopenharmony_ci/// fn main() { 11860636f74Sopenharmony_ci/// assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout"); 11960636f74Sopenharmony_ci/// } 12060636f74Sopenharmony_ci/// ``` 12160636f74Sopenharmony_ci#[cfg(tuple_ty)] 12260636f74Sopenharmony_ci#[macro_export(local_inner_macros)] 12360636f74Sopenharmony_cimacro_rules! offset_of_tuple { 12460636f74Sopenharmony_ci ($parent:ty, $field:tt) => {{ 12560636f74Sopenharmony_ci // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). 12660636f74Sopenharmony_ci _memoffset__let_base_ptr!(base_ptr, $parent); 12760636f74Sopenharmony_ci // Get field pointer. 12860636f74Sopenharmony_ci let field_ptr = raw_field_tuple!(base_ptr, $parent, $field); 12960636f74Sopenharmony_ci // Compute offset. 13060636f74Sopenharmony_ci _memoffset_offset_from_unsafe!(field_ptr, base_ptr) 13160636f74Sopenharmony_ci }}; 13260636f74Sopenharmony_ci} 13360636f74Sopenharmony_ci 13460636f74Sopenharmony_ci/// Calculates the offset of the specified union member from the start of the union. 13560636f74Sopenharmony_ci/// 13660636f74Sopenharmony_ci/// ## Examples 13760636f74Sopenharmony_ci/// ``` 13860636f74Sopenharmony_ci/// use memoffset::offset_of_union; 13960636f74Sopenharmony_ci/// 14060636f74Sopenharmony_ci/// #[repr(C, packed)] 14160636f74Sopenharmony_ci/// union Foo { 14260636f74Sopenharmony_ci/// foo32: i32, 14360636f74Sopenharmony_ci/// foo64: i64, 14460636f74Sopenharmony_ci/// } 14560636f74Sopenharmony_ci/// 14660636f74Sopenharmony_ci/// fn main() { 14760636f74Sopenharmony_ci/// assert!(offset_of_union!(Foo, foo64) == 0); 14860636f74Sopenharmony_ci/// } 14960636f74Sopenharmony_ci/// ``` 15060636f74Sopenharmony_ci/// 15160636f74Sopenharmony_ci/// ## Note 15260636f74Sopenharmony_ci/// Due to macro_rules limitations, this macro will accept structs with a single field as well as unions. 15360636f74Sopenharmony_ci/// This is not a stable guarantee, and future versions of this crate might fail 15460636f74Sopenharmony_ci/// on any use of this macro with a struct, without a semver bump. 15560636f74Sopenharmony_ci#[macro_export(local_inner_macros)] 15660636f74Sopenharmony_cimacro_rules! offset_of_union { 15760636f74Sopenharmony_ci ($parent:path, $field:tt) => {{ 15860636f74Sopenharmony_ci // Get a base pointer (non-dangling if rustc supports `MaybeUninit`). 15960636f74Sopenharmony_ci _memoffset__let_base_ptr!(base_ptr, $parent); 16060636f74Sopenharmony_ci // Get field pointer. 16160636f74Sopenharmony_ci let field_ptr = raw_field_union!(base_ptr, $parent, $field); 16260636f74Sopenharmony_ci // Compute offset. 16360636f74Sopenharmony_ci _memoffset_offset_from_unsafe!(field_ptr, base_ptr) 16460636f74Sopenharmony_ci }}; 16560636f74Sopenharmony_ci} 16660636f74Sopenharmony_ci 16760636f74Sopenharmony_ci#[cfg(test)] 16860636f74Sopenharmony_cimod tests { 16960636f74Sopenharmony_ci #[test] 17060636f74Sopenharmony_ci fn offset_simple() { 17160636f74Sopenharmony_ci #[repr(C)] 17260636f74Sopenharmony_ci struct Foo { 17360636f74Sopenharmony_ci a: u32, 17460636f74Sopenharmony_ci b: [u8; 2], 17560636f74Sopenharmony_ci c: i64, 17660636f74Sopenharmony_ci } 17760636f74Sopenharmony_ci 17860636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, a), 0); 17960636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, b), 4); 18060636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, c), 8); 18160636f74Sopenharmony_ci } 18260636f74Sopenharmony_ci 18360636f74Sopenharmony_ci #[test] 18460636f74Sopenharmony_ci #[cfg_attr(miri, ignore)] // this creates unaligned references 18560636f74Sopenharmony_ci fn offset_simple_packed() { 18660636f74Sopenharmony_ci #[repr(C, packed)] 18760636f74Sopenharmony_ci struct Foo { 18860636f74Sopenharmony_ci a: u32, 18960636f74Sopenharmony_ci b: [u8; 2], 19060636f74Sopenharmony_ci c: i64, 19160636f74Sopenharmony_ci } 19260636f74Sopenharmony_ci 19360636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, a), 0); 19460636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, b), 4); 19560636f74Sopenharmony_ci assert_eq!(offset_of!(Foo, c), 6); 19660636f74Sopenharmony_ci } 19760636f74Sopenharmony_ci 19860636f74Sopenharmony_ci #[test] 19960636f74Sopenharmony_ci fn tuple_struct() { 20060636f74Sopenharmony_ci #[repr(C)] 20160636f74Sopenharmony_ci struct Tup(i32, i32); 20260636f74Sopenharmony_ci 20360636f74Sopenharmony_ci assert_eq!(offset_of!(Tup, 0), 0); 20460636f74Sopenharmony_ci assert_eq!(offset_of!(Tup, 1), 4); 20560636f74Sopenharmony_ci } 20660636f74Sopenharmony_ci 20760636f74Sopenharmony_ci #[test] 20860636f74Sopenharmony_ci fn offset_union() { 20960636f74Sopenharmony_ci // Since we're specifying repr(C), all fields are supposed to be at offset 0 21060636f74Sopenharmony_ci #[repr(C)] 21160636f74Sopenharmony_ci union Foo { 21260636f74Sopenharmony_ci a: u32, 21360636f74Sopenharmony_ci b: [u8; 2], 21460636f74Sopenharmony_ci c: i64, 21560636f74Sopenharmony_ci } 21660636f74Sopenharmony_ci 21760636f74Sopenharmony_ci assert_eq!(offset_of_union!(Foo, a), 0); 21860636f74Sopenharmony_ci assert_eq!(offset_of_union!(Foo, b), 0); 21960636f74Sopenharmony_ci assert_eq!(offset_of_union!(Foo, c), 0); 22060636f74Sopenharmony_ci } 22160636f74Sopenharmony_ci 22260636f74Sopenharmony_ci #[test] 22360636f74Sopenharmony_ci fn path() { 22460636f74Sopenharmony_ci mod sub { 22560636f74Sopenharmony_ci #[repr(C)] 22660636f74Sopenharmony_ci pub struct Foo { 22760636f74Sopenharmony_ci pub x: u32, 22860636f74Sopenharmony_ci } 22960636f74Sopenharmony_ci } 23060636f74Sopenharmony_ci 23160636f74Sopenharmony_ci assert_eq!(offset_of!(sub::Foo, x), 0); 23260636f74Sopenharmony_ci } 23360636f74Sopenharmony_ci 23460636f74Sopenharmony_ci #[test] 23560636f74Sopenharmony_ci fn inside_generic_method() { 23660636f74Sopenharmony_ci struct Pair<T, U>(T, U); 23760636f74Sopenharmony_ci 23860636f74Sopenharmony_ci fn foo<T, U>(_: Pair<T, U>) -> usize { 23960636f74Sopenharmony_ci offset_of!(Pair<T, U>, 1) 24060636f74Sopenharmony_ci } 24160636f74Sopenharmony_ci 24260636f74Sopenharmony_ci assert_eq!(foo(Pair(0, 0)), 4); 24360636f74Sopenharmony_ci } 24460636f74Sopenharmony_ci 24560636f74Sopenharmony_ci #[cfg(tuple_ty)] 24660636f74Sopenharmony_ci #[test] 24760636f74Sopenharmony_ci fn test_tuple_offset() { 24860636f74Sopenharmony_ci let f = (0i32, 0.0f32, 0u8); 24960636f74Sopenharmony_ci let f_ptr = &f as *const _; 25060636f74Sopenharmony_ci let f1_ptr = &f.1 as *const _; 25160636f74Sopenharmony_ci 25260636f74Sopenharmony_ci assert_eq!( 25360636f74Sopenharmony_ci f1_ptr as usize - f_ptr as usize, 25460636f74Sopenharmony_ci offset_of_tuple!((i32, f32, u8), 1) 25560636f74Sopenharmony_ci ); 25660636f74Sopenharmony_ci } 25760636f74Sopenharmony_ci 25860636f74Sopenharmony_ci #[test] 25960636f74Sopenharmony_ci fn test_raw_field() { 26060636f74Sopenharmony_ci #[repr(C)] 26160636f74Sopenharmony_ci struct Foo { 26260636f74Sopenharmony_ci a: u32, 26360636f74Sopenharmony_ci b: [u8; 2], 26460636f74Sopenharmony_ci c: i64, 26560636f74Sopenharmony_ci } 26660636f74Sopenharmony_ci 26760636f74Sopenharmony_ci let f: Foo = Foo { 26860636f74Sopenharmony_ci a: 0, 26960636f74Sopenharmony_ci b: [0, 0], 27060636f74Sopenharmony_ci c: 0, 27160636f74Sopenharmony_ci }; 27260636f74Sopenharmony_ci let f_ptr = &f as *const _; 27360636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 0, raw_field!(f_ptr, Foo, a) as usize); 27460636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 4, raw_field!(f_ptr, Foo, b) as usize); 27560636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 8, raw_field!(f_ptr, Foo, c) as usize); 27660636f74Sopenharmony_ci } 27760636f74Sopenharmony_ci 27860636f74Sopenharmony_ci #[cfg(tuple_ty)] 27960636f74Sopenharmony_ci #[test] 28060636f74Sopenharmony_ci fn test_raw_field_tuple() { 28160636f74Sopenharmony_ci let t = (0u32, 0u8, false); 28260636f74Sopenharmony_ci let t_ptr = &t as *const _; 28360636f74Sopenharmony_ci let t_addr = t_ptr as usize; 28460636f74Sopenharmony_ci 28560636f74Sopenharmony_ci assert_eq!( 28660636f74Sopenharmony_ci &t.0 as *const _ as usize - t_addr, 28760636f74Sopenharmony_ci raw_field_tuple!(t_ptr, (u32, u8, bool), 0) as usize - t_addr 28860636f74Sopenharmony_ci ); 28960636f74Sopenharmony_ci assert_eq!( 29060636f74Sopenharmony_ci &t.1 as *const _ as usize - t_addr, 29160636f74Sopenharmony_ci raw_field_tuple!(t_ptr, (u32, u8, bool), 1) as usize - t_addr 29260636f74Sopenharmony_ci ); 29360636f74Sopenharmony_ci assert_eq!( 29460636f74Sopenharmony_ci &t.2 as *const _ as usize - t_addr, 29560636f74Sopenharmony_ci raw_field_tuple!(t_ptr, (u32, u8, bool), 2) as usize - t_addr 29660636f74Sopenharmony_ci ); 29760636f74Sopenharmony_ci } 29860636f74Sopenharmony_ci 29960636f74Sopenharmony_ci #[test] 30060636f74Sopenharmony_ci fn test_raw_field_union() { 30160636f74Sopenharmony_ci #[repr(C)] 30260636f74Sopenharmony_ci union Foo { 30360636f74Sopenharmony_ci a: u32, 30460636f74Sopenharmony_ci b: [u8; 2], 30560636f74Sopenharmony_ci c: i64, 30660636f74Sopenharmony_ci } 30760636f74Sopenharmony_ci 30860636f74Sopenharmony_ci let f = Foo { a: 0 }; 30960636f74Sopenharmony_ci let f_ptr = &f as *const _; 31060636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, a) as usize); 31160636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, b) as usize); 31260636f74Sopenharmony_ci assert_eq!(f_ptr as usize + 0, raw_field_union!(f_ptr, Foo, c) as usize); 31360636f74Sopenharmony_ci } 31460636f74Sopenharmony_ci 31560636f74Sopenharmony_ci #[cfg(any(feature = "unstable_const", stable_const))] 31660636f74Sopenharmony_ci #[test] 31760636f74Sopenharmony_ci fn const_offset() { 31860636f74Sopenharmony_ci #[repr(C)] 31960636f74Sopenharmony_ci struct Foo { 32060636f74Sopenharmony_ci a: u32, 32160636f74Sopenharmony_ci b: [u8; 2], 32260636f74Sopenharmony_ci c: i64, 32360636f74Sopenharmony_ci } 32460636f74Sopenharmony_ci 32560636f74Sopenharmony_ci assert_eq!([0; offset_of!(Foo, b)].len(), 4); 32660636f74Sopenharmony_ci } 32760636f74Sopenharmony_ci 32860636f74Sopenharmony_ci #[cfg(feature = "unstable_const")] 32960636f74Sopenharmony_ci #[test] 33060636f74Sopenharmony_ci fn const_offset_interior_mutable() { 33160636f74Sopenharmony_ci #[repr(C)] 33260636f74Sopenharmony_ci struct Foo { 33360636f74Sopenharmony_ci a: u32, 33460636f74Sopenharmony_ci b: core::cell::Cell<u32>, 33560636f74Sopenharmony_ci } 33660636f74Sopenharmony_ci 33760636f74Sopenharmony_ci assert_eq!([0; offset_of!(Foo, b)].len(), 4); 33860636f74Sopenharmony_ci } 33960636f74Sopenharmony_ci 34060636f74Sopenharmony_ci #[cfg(any(feature = "unstable_const", stable_const))] 34160636f74Sopenharmony_ci #[test] 34260636f74Sopenharmony_ci fn const_fn_offset() { 34360636f74Sopenharmony_ci const fn test_fn() -> usize { 34460636f74Sopenharmony_ci #[repr(C)] 34560636f74Sopenharmony_ci struct Foo { 34660636f74Sopenharmony_ci a: u32, 34760636f74Sopenharmony_ci b: [u8; 2], 34860636f74Sopenharmony_ci c: i64, 34960636f74Sopenharmony_ci } 35060636f74Sopenharmony_ci 35160636f74Sopenharmony_ci offset_of!(Foo, b) 35260636f74Sopenharmony_ci } 35360636f74Sopenharmony_ci 35460636f74Sopenharmony_ci assert_eq!([0; test_fn()].len(), 4); 35560636f74Sopenharmony_ci } 35660636f74Sopenharmony_ci} 357