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