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