1 // Copyright (c) 2017 Gilad Naaman 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in all 11 // copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 // SOFTWARE. 20 21 /// Reexport for `local_inner_macros`; see 22 /// <https://doc.rust-lang.org/edition-guide/rust-2018/macros/macro-changes.html#macros-using-local_inner_macros>. 23 #[doc(hidden)] 24 #[macro_export] 25 macro_rules! _memoffset__compile_error { 26 ($($inner:tt)*) => { 27 compile_error! { $($inner)* } 28 } 29 } 30 31 /// Produces a range instance representing the sub-slice containing the specified member. 32 /// 33 /// This macro provides 2 forms of differing functionalities. 34 /// 35 /// The first form is identical to the appearance of the `offset_of!` macro. 36 /// 37 /// ```ignore 38 /// span_of!(Struct, member) 39 /// ``` 40 /// 41 /// The second form of `span_of!` returns a sub-slice which starts at one field, and ends at another. 42 /// The general pattern of this form is: 43 /// 44 /// ```ignore 45 /// // Exclusive 46 /// span_of!(Struct, member_a .. member_b) 47 /// // Inclusive 48 /// span_of!(Struct, member_a ..= member_b) 49 /// 50 /// // Open-ended ranges 51 /// span_of!(Struct, .. end) 52 /// span_of!(Struct, start ..) 53 /// ``` 54 /// 55 /// ### Note 56 /// This macro uses recursion in order to resolve the range expressions, so there is a limit to 57 /// the complexity of the expression. 58 /// In order to raise the limit, the compiler's recursion limit should be lifted. 59 /// 60 /// ### Safety 61 /// The inter-field form mentioned above assumes that the first field is positioned before the 62 /// second. 63 /// This is only guaranteed for `repr(C)` structs. 64 /// Usage with `repr(Rust)` structs may yield unexpected results, like downward-going ranges, 65 /// spans that include unexpected fields, empty spans, or spans that include *unexpected* padding bytes. 66 /// 67 /// ## Examples 68 /// ``` 69 /// use memoffset::span_of; 70 /// 71 /// #[repr(C)] 72 /// struct Florp { 73 /// a: u32 74 /// } 75 /// 76 /// #[repr(C)] 77 /// struct Blarg { 78 /// x: [u32; 2], 79 /// y: [u8; 56], 80 /// z: Florp, 81 /// egg: [[u8; 4]; 4] 82 /// } 83 /// 84 /// assert_eq!(0..84, span_of!(Blarg, ..)); 85 /// assert_eq!(0..8, span_of!(Blarg, .. y)); 86 /// assert_eq!(0..64, span_of!(Blarg, ..= y)); 87 /// assert_eq!(0..8, span_of!(Blarg, x)); 88 /// assert_eq!(8..84, span_of!(Blarg, y ..)); 89 /// assert_eq!(0..8, span_of!(Blarg, x .. y)); 90 /// assert_eq!(0..64, span_of!(Blarg, x ..= y)); 91 /// ``` 92 #[macro_export(local_inner_macros)] 93 macro_rules! span_of { 94 (@helper $root:ident, [] ..=) => { 95 _memoffset__compile_error!("Expected a range, found '..='") 96 }; 97 (@helper $root:ident, [] ..) => { 98 _memoffset__compile_error!("Expected a range, found '..'") 99 }; 100 // No explicit begin for range. 101 (@helper $root:ident, $parent:path, [] ..) => {{ 102 ($root as usize, 103 $root as usize + $crate::__priv::size_of_pointee($root)) 104 }}; 105 (@helper $root:ident, $parent:path, [] ..= $end:tt) => {{ 106 let end = raw_field!($root, $parent, $end); 107 ($root as usize, end as usize + $crate::__priv::size_of_pointee(end)) 108 }}; 109 (@helper $root:ident, $parent:path, [] .. $end:tt) => {{ 110 ($root as usize, raw_field!($root, $parent, $end) as usize) 111 }}; 112 // Explicit begin and end for range. 113 (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{ 114 let begin = raw_field!($root, $parent, $begin); 115 let end = raw_field!($root, $parent, $end); 116 (begin as usize, end as usize + $crate::__priv::size_of_pointee(end)) 117 }}; 118 (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{ 119 (raw_field!($root, $parent, $begin) as usize, 120 raw_field!($root, $parent, $end) as usize) 121 }}; 122 // No explicit end for range. 123 (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{ 124 (raw_field!($root, $parent, $begin) as usize, 125 $root as usize + $crate::__priv::size_of_pointee($root)) 126 }}; 127 (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{ 128 _memoffset__compile_error!( 129 "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?") 130 }}; 131 // Just one field. 132 (@helper $root:ident, $parent:path, # $field:tt []) => {{ 133 let field = raw_field!($root, $parent, $field); 134 (field as usize, field as usize + $crate::__priv::size_of_pointee(field)) 135 }}; 136 // Parsing. 137 (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{ 138 span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*) 139 }}; 140 (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{ 141 span_of!(@helper $root, $parent, #$tt [] $($rest)*) 142 }}; 143 144 // Entry point. 145 ($sty:path, $($exp:tt)+) => ({ 146 // Get a base pointer. 147 _memoffset__let_base_ptr!(root, $sty); 148 let base = root as usize; 149 let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*); 150 begin-base..end-base 151 }); 152 } 153 154 #[cfg(test)] 155 mod tests { 156 use core::mem; 157 158 #[test] span_simple()159 fn span_simple() { 160 #[repr(C)] 161 struct Foo { 162 a: u32, 163 b: [u8; 2], 164 c: i64, 165 } 166 167 assert_eq!(span_of!(Foo, a), 0..4); 168 assert_eq!(span_of!(Foo, b), 4..6); 169 assert_eq!(span_of!(Foo, c), 8..8 + 8); 170 } 171 172 #[test] 173 #[cfg_attr(miri, ignore)] // this creates unaligned references span_simple_packed()174 fn span_simple_packed() { 175 #[repr(C, packed)] 176 struct Foo { 177 a: u32, 178 b: [u8; 2], 179 c: i64, 180 } 181 182 assert_eq!(span_of!(Foo, a), 0..4); 183 assert_eq!(span_of!(Foo, b), 4..6); 184 assert_eq!(span_of!(Foo, c), 6..6 + 8); 185 } 186 187 #[test] span_forms()188 fn span_forms() { 189 #[repr(C)] 190 struct Florp { 191 a: u32, 192 } 193 194 #[repr(C)] 195 struct Blarg { 196 x: u64, 197 y: [u8; 56], 198 z: Florp, 199 egg: [[u8; 4]; 5], 200 } 201 202 // Love me some brute force 203 assert_eq!(0..8, span_of!(Blarg, x)); 204 assert_eq!(64..68, span_of!(Blarg, z)); 205 assert_eq!(68..mem::size_of::<Blarg>(), span_of!(Blarg, egg)); 206 207 assert_eq!(8..64, span_of!(Blarg, y..z)); 208 assert_eq!(0..64, span_of!(Blarg, x..=y)); 209 } 210 211 #[test] ig_test()212 fn ig_test() { 213 #[repr(C)] 214 struct Member { 215 foo: u32, 216 } 217 218 #[repr(C)] 219 struct Test { 220 x: u64, 221 y: [u8; 56], 222 z: Member, 223 egg: [[u8; 4]; 4], 224 } 225 226 assert_eq!(span_of!(Test, ..x), 0..0); 227 assert_eq!(span_of!(Test, ..=x), 0..8); 228 assert_eq!(span_of!(Test, ..y), 0..8); 229 assert_eq!(span_of!(Test, ..=y), 0..64); 230 assert_eq!(span_of!(Test, ..z), 0..64); 231 assert_eq!(span_of!(Test, ..=z), 0..68); 232 assert_eq!(span_of!(Test, ..egg), 0..68); 233 assert_eq!(span_of!(Test, ..=egg), 0..84); 234 assert_eq!(span_of!(Test, ..), 0..mem::size_of::<Test>()); 235 assert_eq!( 236 span_of!(Test, x..), 237 offset_of!(Test, x)..mem::size_of::<Test>() 238 ); 239 assert_eq!( 240 span_of!(Test, y..), 241 offset_of!(Test, y)..mem::size_of::<Test>() 242 ); 243 244 assert_eq!( 245 span_of!(Test, z..), 246 offset_of!(Test, z)..mem::size_of::<Test>() 247 ); 248 assert_eq!( 249 span_of!(Test, egg..), 250 offset_of!(Test, egg)..mem::size_of::<Test>() 251 ); 252 assert_eq!( 253 span_of!(Test, x..y), 254 offset_of!(Test, x)..offset_of!(Test, y) 255 ); 256 assert_eq!( 257 span_of!(Test, x..=y), 258 offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>() 259 ); 260 } 261 } 262