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/// Reexport for `local_inner_macros`; see
2260636f74Sopenharmony_ci/// <https://doc.rust-lang.org/edition-guide/rust-2018/macros/macro-changes.html#macros-using-local_inner_macros>.
2360636f74Sopenharmony_ci#[doc(hidden)]
2460636f74Sopenharmony_ci#[macro_export]
2560636f74Sopenharmony_cimacro_rules! _memoffset__compile_error {
2660636f74Sopenharmony_ci    ($($inner:tt)*) => {
2760636f74Sopenharmony_ci        compile_error! { $($inner)* }
2860636f74Sopenharmony_ci    }
2960636f74Sopenharmony_ci}
3060636f74Sopenharmony_ci
3160636f74Sopenharmony_ci/// Produces a range instance representing the sub-slice containing the specified member.
3260636f74Sopenharmony_ci///
3360636f74Sopenharmony_ci/// This macro provides 2 forms of differing functionalities.
3460636f74Sopenharmony_ci///
3560636f74Sopenharmony_ci/// The first form is identical to the appearance of the `offset_of!` macro.
3660636f74Sopenharmony_ci///
3760636f74Sopenharmony_ci/// ```ignore
3860636f74Sopenharmony_ci/// span_of!(Struct, member)
3960636f74Sopenharmony_ci/// ```
4060636f74Sopenharmony_ci///
4160636f74Sopenharmony_ci/// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another.
4260636f74Sopenharmony_ci/// The general pattern of this form is:
4360636f74Sopenharmony_ci///
4460636f74Sopenharmony_ci/// ```ignore
4560636f74Sopenharmony_ci/// // Exclusive
4660636f74Sopenharmony_ci/// span_of!(Struct, member_a .. member_b)
4760636f74Sopenharmony_ci/// // Inclusive
4860636f74Sopenharmony_ci/// span_of!(Struct, member_a ..= member_b)
4960636f74Sopenharmony_ci///
5060636f74Sopenharmony_ci/// // Open-ended ranges
5160636f74Sopenharmony_ci/// span_of!(Struct, .. end)
5260636f74Sopenharmony_ci/// span_of!(Struct, start ..)
5360636f74Sopenharmony_ci/// ```
5460636f74Sopenharmony_ci///
5560636f74Sopenharmony_ci/// ### Note
5660636f74Sopenharmony_ci/// This macro uses recursion in order to resolve the range expressions, so there is a limit to
5760636f74Sopenharmony_ci/// the complexity of the expression.
5860636f74Sopenharmony_ci/// In order to raise the limit, the compiler's recursion limit should be lifted.
5960636f74Sopenharmony_ci///
6060636f74Sopenharmony_ci/// ### Safety
6160636f74Sopenharmony_ci/// The inter-field form mentioned above assumes that the first field is positioned before the
6260636f74Sopenharmony_ci/// second.
6360636f74Sopenharmony_ci/// This is only guarenteed for `repr(C)` structs.
6460636f74Sopenharmony_ci/// Usage with `repr(Rust)` structs may yield unexpected results, like downward-going ranges,
6560636f74Sopenharmony_ci/// spans that include unexpected fields, empty spans, or spans that include *unexpected* padding bytes.
6660636f74Sopenharmony_ci///
6760636f74Sopenharmony_ci/// ## Examples
6860636f74Sopenharmony_ci/// ```
6960636f74Sopenharmony_ci/// use memoffset::span_of;
7060636f74Sopenharmony_ci///
7160636f74Sopenharmony_ci/// #[repr(C)]
7260636f74Sopenharmony_ci/// struct Florp {
7360636f74Sopenharmony_ci///     a: u32
7460636f74Sopenharmony_ci/// }
7560636f74Sopenharmony_ci///
7660636f74Sopenharmony_ci/// #[repr(C)]
7760636f74Sopenharmony_ci/// struct Blarg {
7860636f74Sopenharmony_ci///     x: [u32; 2],
7960636f74Sopenharmony_ci///     y: [u8; 56],
8060636f74Sopenharmony_ci///     z: Florp,
8160636f74Sopenharmony_ci///     egg: [[u8; 4]; 4]
8260636f74Sopenharmony_ci/// }
8360636f74Sopenharmony_ci///
8460636f74Sopenharmony_ci/// fn main() {
8560636f74Sopenharmony_ci///     assert_eq!(0..84,  span_of!(Blarg, ..));
8660636f74Sopenharmony_ci///     assert_eq!(0..8,   span_of!(Blarg, .. y));
8760636f74Sopenharmony_ci///     assert_eq!(0..64,  span_of!(Blarg, ..= y));
8860636f74Sopenharmony_ci///     assert_eq!(0..8,   span_of!(Blarg, x));
8960636f74Sopenharmony_ci///     assert_eq!(8..84,  span_of!(Blarg, y ..));
9060636f74Sopenharmony_ci///     assert_eq!(0..8,   span_of!(Blarg, x .. y));
9160636f74Sopenharmony_ci///     assert_eq!(0..64,  span_of!(Blarg, x ..= y));
9260636f74Sopenharmony_ci/// }
9360636f74Sopenharmony_ci/// ```
9460636f74Sopenharmony_ci#[macro_export(local_inner_macros)]
9560636f74Sopenharmony_cimacro_rules! span_of {
9660636f74Sopenharmony_ci    (@helper  $root:ident, [] ..=) => {
9760636f74Sopenharmony_ci        _memoffset__compile_error!("Expected a range, found '..='")
9860636f74Sopenharmony_ci    };
9960636f74Sopenharmony_ci    (@helper $root:ident, [] ..) => {
10060636f74Sopenharmony_ci        _memoffset__compile_error!("Expected a range, found '..'")
10160636f74Sopenharmony_ci    };
10260636f74Sopenharmony_ci    // No explicit begin for range.
10360636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, [] ..) => {{
10460636f74Sopenharmony_ci        ($root as usize,
10560636f74Sopenharmony_ci         $root as usize + $crate::__priv::size_of_pointee($root))
10660636f74Sopenharmony_ci    }};
10760636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, [] ..= $end:tt) => {{
10860636f74Sopenharmony_ci        let end = raw_field!($root, $parent, $end);
10960636f74Sopenharmony_ci        ($root as usize, end as usize + $crate::__priv::size_of_pointee(end))
11060636f74Sopenharmony_ci    }};
11160636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, [] .. $end:tt) => {{
11260636f74Sopenharmony_ci        ($root as usize, raw_field!($root, $parent, $end) as usize)
11360636f74Sopenharmony_ci    }};
11460636f74Sopenharmony_ci    // Explicit begin and end for range.
11560636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{
11660636f74Sopenharmony_ci        let begin = raw_field!($root, $parent, $begin);
11760636f74Sopenharmony_ci        let end = raw_field!($root, $parent, $end);
11860636f74Sopenharmony_ci        (begin as usize, end as usize + $crate::__priv::size_of_pointee(end))
11960636f74Sopenharmony_ci    }};
12060636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{
12160636f74Sopenharmony_ci        (raw_field!($root, $parent, $begin) as usize,
12260636f74Sopenharmony_ci         raw_field!($root, $parent, $end) as usize)
12360636f74Sopenharmony_ci    }};
12460636f74Sopenharmony_ci    // No explicit end for range.
12560636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{
12660636f74Sopenharmony_ci        (raw_field!($root, $parent, $begin) as usize,
12760636f74Sopenharmony_ci         $root as usize + $crate::__priv::size_of_pointee($root))
12860636f74Sopenharmony_ci    }};
12960636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{
13060636f74Sopenharmony_ci        _memoffset__compile_error!(
13160636f74Sopenharmony_ci            "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
13260636f74Sopenharmony_ci    }};
13360636f74Sopenharmony_ci    // Just one field.
13460636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, # $field:tt []) => {{
13560636f74Sopenharmony_ci        let field = raw_field!($root, $parent, $field);
13660636f74Sopenharmony_ci        (field as usize, field as usize + $crate::__priv::size_of_pointee(field))
13760636f74Sopenharmony_ci    }};
13860636f74Sopenharmony_ci    // Parsing.
13960636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
14060636f74Sopenharmony_ci        span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
14160636f74Sopenharmony_ci    }};
14260636f74Sopenharmony_ci    (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{
14360636f74Sopenharmony_ci        span_of!(@helper $root, $parent, #$tt [] $($rest)*)
14460636f74Sopenharmony_ci    }};
14560636f74Sopenharmony_ci
14660636f74Sopenharmony_ci    // Entry point.
14760636f74Sopenharmony_ci    ($sty:path, $($exp:tt)+) => ({
14860636f74Sopenharmony_ci        // Get a base pointer.
14960636f74Sopenharmony_ci        _memoffset__let_base_ptr!(root, $sty);
15060636f74Sopenharmony_ci        let base = root as usize;
15160636f74Sopenharmony_ci        let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*);
15260636f74Sopenharmony_ci        begin-base..end-base
15360636f74Sopenharmony_ci    });
15460636f74Sopenharmony_ci}
15560636f74Sopenharmony_ci
15660636f74Sopenharmony_ci#[cfg(test)]
15760636f74Sopenharmony_cimod tests {
15860636f74Sopenharmony_ci    use core::mem;
15960636f74Sopenharmony_ci
16060636f74Sopenharmony_ci    #[test]
16160636f74Sopenharmony_ci    fn span_simple() {
16260636f74Sopenharmony_ci        #[repr(C)]
16360636f74Sopenharmony_ci        struct Foo {
16460636f74Sopenharmony_ci            a: u32,
16560636f74Sopenharmony_ci            b: [u8; 2],
16660636f74Sopenharmony_ci            c: i64,
16760636f74Sopenharmony_ci        }
16860636f74Sopenharmony_ci
16960636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, a), 0..4);
17060636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, b), 4..6);
17160636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, c), 8..8 + 8);
17260636f74Sopenharmony_ci    }
17360636f74Sopenharmony_ci
17460636f74Sopenharmony_ci    #[test]
17560636f74Sopenharmony_ci    #[cfg_attr(miri, ignore)] // this creates unaligned references
17660636f74Sopenharmony_ci    fn span_simple_packed() {
17760636f74Sopenharmony_ci        #[repr(C, packed)]
17860636f74Sopenharmony_ci        struct Foo {
17960636f74Sopenharmony_ci            a: u32,
18060636f74Sopenharmony_ci            b: [u8; 2],
18160636f74Sopenharmony_ci            c: i64,
18260636f74Sopenharmony_ci        }
18360636f74Sopenharmony_ci
18460636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, a), 0..4);
18560636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, b), 4..6);
18660636f74Sopenharmony_ci        assert_eq!(span_of!(Foo, c), 6..6 + 8);
18760636f74Sopenharmony_ci    }
18860636f74Sopenharmony_ci
18960636f74Sopenharmony_ci    #[test]
19060636f74Sopenharmony_ci    fn span_forms() {
19160636f74Sopenharmony_ci        #[repr(C)]
19260636f74Sopenharmony_ci        struct Florp {
19360636f74Sopenharmony_ci            a: u32,
19460636f74Sopenharmony_ci        }
19560636f74Sopenharmony_ci
19660636f74Sopenharmony_ci        #[repr(C)]
19760636f74Sopenharmony_ci        struct Blarg {
19860636f74Sopenharmony_ci            x: u64,
19960636f74Sopenharmony_ci            y: [u8; 56],
20060636f74Sopenharmony_ci            z: Florp,
20160636f74Sopenharmony_ci            egg: [[u8; 4]; 5],
20260636f74Sopenharmony_ci        }
20360636f74Sopenharmony_ci
20460636f74Sopenharmony_ci        // Love me some brute force
20560636f74Sopenharmony_ci        assert_eq!(0..8, span_of!(Blarg, x));
20660636f74Sopenharmony_ci        assert_eq!(64..68, span_of!(Blarg, z));
20760636f74Sopenharmony_ci        assert_eq!(68..mem::size_of::<Blarg>(), span_of!(Blarg, egg));
20860636f74Sopenharmony_ci
20960636f74Sopenharmony_ci        assert_eq!(8..64, span_of!(Blarg, y..z));
21060636f74Sopenharmony_ci        assert_eq!(0..64, span_of!(Blarg, x..=y));
21160636f74Sopenharmony_ci    }
21260636f74Sopenharmony_ci
21360636f74Sopenharmony_ci    #[test]
21460636f74Sopenharmony_ci    fn ig_test() {
21560636f74Sopenharmony_ci        #[repr(C)]
21660636f74Sopenharmony_ci        struct Member {
21760636f74Sopenharmony_ci            foo: u32,
21860636f74Sopenharmony_ci        }
21960636f74Sopenharmony_ci
22060636f74Sopenharmony_ci        #[repr(C)]
22160636f74Sopenharmony_ci        struct Test {
22260636f74Sopenharmony_ci            x: u64,
22360636f74Sopenharmony_ci            y: [u8; 56],
22460636f74Sopenharmony_ci            z: Member,
22560636f74Sopenharmony_ci            egg: [[u8; 4]; 4],
22660636f74Sopenharmony_ci        }
22760636f74Sopenharmony_ci
22860636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..x), 0..0);
22960636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..=x), 0..8);
23060636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..y), 0..8);
23160636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..=y), 0..64);
23260636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..z), 0..64);
23360636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..=z), 0..68);
23460636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..egg), 0..68);
23560636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..=egg), 0..84);
23660636f74Sopenharmony_ci        assert_eq!(span_of!(Test, ..), 0..mem::size_of::<Test>());
23760636f74Sopenharmony_ci        assert_eq!(
23860636f74Sopenharmony_ci            span_of!(Test, x..),
23960636f74Sopenharmony_ci            offset_of!(Test, x)..mem::size_of::<Test>()
24060636f74Sopenharmony_ci        );
24160636f74Sopenharmony_ci        assert_eq!(
24260636f74Sopenharmony_ci            span_of!(Test, y..),
24360636f74Sopenharmony_ci            offset_of!(Test, y)..mem::size_of::<Test>()
24460636f74Sopenharmony_ci        );
24560636f74Sopenharmony_ci
24660636f74Sopenharmony_ci        assert_eq!(
24760636f74Sopenharmony_ci            span_of!(Test, z..),
24860636f74Sopenharmony_ci            offset_of!(Test, z)..mem::size_of::<Test>()
24960636f74Sopenharmony_ci        );
25060636f74Sopenharmony_ci        assert_eq!(
25160636f74Sopenharmony_ci            span_of!(Test, egg..),
25260636f74Sopenharmony_ci            offset_of!(Test, egg)..mem::size_of::<Test>()
25360636f74Sopenharmony_ci        );
25460636f74Sopenharmony_ci        assert_eq!(
25560636f74Sopenharmony_ci            span_of!(Test, x..y),
25660636f74Sopenharmony_ci            offset_of!(Test, x)..offset_of!(Test, y)
25760636f74Sopenharmony_ci        );
25860636f74Sopenharmony_ci        assert_eq!(
25960636f74Sopenharmony_ci            span_of!(Test, x..=y),
26060636f74Sopenharmony_ci            offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>()
26160636f74Sopenharmony_ci        );
26260636f74Sopenharmony_ci    }
26360636f74Sopenharmony_ci}
264