• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 guarenteed 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 /// fn main() {
85 ///     assert_eq!(0..84,  span_of!(Blarg, ..));
86 ///     assert_eq!(0..8,   span_of!(Blarg, .. y));
87 ///     assert_eq!(0..64,  span_of!(Blarg, ..= y));
88 ///     assert_eq!(0..8,   span_of!(Blarg, x));
89 ///     assert_eq!(8..84,  span_of!(Blarg, y ..));
90 ///     assert_eq!(0..8,   span_of!(Blarg, x .. y));
91 ///     assert_eq!(0..64,  span_of!(Blarg, x ..= y));
92 /// }
93 /// ```
94 #[macro_export(local_inner_macros)]
95 macro_rules! span_of {
96     (@helper  $root:ident, [] ..=) => {
97         _memoffset__compile_error!("Expected a range, found '..='")
98     };
99     (@helper $root:ident, [] ..) => {
100         _memoffset__compile_error!("Expected a range, found '..'")
101     };
102     // No explicit begin for range.
103     (@helper $root:ident, $parent:path, [] ..) => {{
104         ($root as usize,
105          $root as usize + $crate::__priv::size_of_pointee($root))
106     }};
107     (@helper $root:ident, $parent:path, [] ..= $end:tt) => {{
108         let end = raw_field!($root, $parent, $end);
109         ($root as usize, end as usize + $crate::__priv::size_of_pointee(end))
110     }};
111     (@helper $root:ident, $parent:path, [] .. $end:tt) => {{
112         ($root as usize, raw_field!($root, $parent, $end) as usize)
113     }};
114     // Explicit begin and end for range.
115     (@helper $root:ident, $parent:path, # $begin:tt [] ..= $end:tt) => {{
116         let begin = raw_field!($root, $parent, $begin);
117         let end = raw_field!($root, $parent, $end);
118         (begin as usize, end as usize + $crate::__priv::size_of_pointee(end))
119     }};
120     (@helper $root:ident, $parent:path, # $begin:tt [] .. $end:tt) => {{
121         (raw_field!($root, $parent, $begin) as usize,
122          raw_field!($root, $parent, $end) as usize)
123     }};
124     // No explicit end for range.
125     (@helper $root:ident, $parent:path, # $begin:tt [] ..) => {{
126         (raw_field!($root, $parent, $begin) as usize,
127          $root as usize + $crate::__priv::size_of_pointee($root))
128     }};
129     (@helper $root:ident, $parent:path, # $begin:tt [] ..=) => {{
130         _memoffset__compile_error!(
131             "Found inclusive range to the end of a struct. Did you mean '..' instead of '..='?")
132     }};
133     // Just one field.
134     (@helper $root:ident, $parent:path, # $field:tt []) => {{
135         let field = raw_field!($root, $parent, $field);
136         (field as usize, field as usize + $crate::__priv::size_of_pointee(field))
137     }};
138     // Parsing.
139     (@helper $root:ident, $parent:path, $(# $begin:tt)+ [] $tt:tt $($rest:tt)*) => {{
140         span_of!(@helper $root, $parent, $(#$begin)* #$tt [] $($rest)*)
141     }};
142     (@helper $root:ident, $parent:path, [] $tt:tt $($rest:tt)*) => {{
143         span_of!(@helper $root, $parent, #$tt [] $($rest)*)
144     }};
145 
146     // Entry point.
147     ($sty:path, $($exp:tt)+) => ({
148         // Get a base pointer.
149         _memoffset__let_base_ptr!(root, $sty);
150         let base = root as usize;
151         let (begin, end) = span_of!(@helper root, $sty, [] $($exp)*);
152         begin-base..end-base
153     });
154 }
155 
156 #[cfg(test)]
157 mod tests {
158     // ANDROID: use std instead of core, since we're not building wiht no-std.
159     use std::mem;
160 
161     #[test]
span_simple()162     fn span_simple() {
163         #[repr(C)]
164         struct Foo {
165             a: u32,
166             b: [u8; 2],
167             c: i64,
168         }
169 
170         assert_eq!(span_of!(Foo, a), 0..4);
171         assert_eq!(span_of!(Foo, b), 4..6);
172         assert_eq!(span_of!(Foo, c), 8..8 + 8);
173     }
174 
175     #[test]
176     #[cfg_attr(miri, ignore)] // this creates unaligned references
span_simple_packed()177     fn span_simple_packed() {
178         #[repr(C, packed)]
179         struct Foo {
180             a: u32,
181             b: [u8; 2],
182             c: i64,
183         }
184 
185         assert_eq!(span_of!(Foo, a), 0..4);
186         assert_eq!(span_of!(Foo, b), 4..6);
187         assert_eq!(span_of!(Foo, c), 6..6 + 8);
188     }
189 
190     #[test]
span_forms()191     fn span_forms() {
192         #[repr(C)]
193         struct Florp {
194             a: u32,
195         }
196 
197         #[repr(C)]
198         struct Blarg {
199             x: u64,
200             y: [u8; 56],
201             z: Florp,
202             egg: [[u8; 4]; 5],
203         }
204 
205         // Love me some brute force
206         assert_eq!(0..8, span_of!(Blarg, x));
207         assert_eq!(64..68, span_of!(Blarg, z));
208         assert_eq!(68..mem::size_of::<Blarg>(), span_of!(Blarg, egg));
209 
210         assert_eq!(8..64, span_of!(Blarg, y..z));
211         assert_eq!(0..64, span_of!(Blarg, x..=y));
212     }
213 
214     #[test]
ig_test()215     fn ig_test() {
216         #[repr(C)]
217         struct Member {
218             foo: u32,
219         }
220 
221         #[repr(C)]
222         struct Test {
223             x: u64,
224             y: [u8; 56],
225             z: Member,
226             egg: [[u8; 4]; 4],
227         }
228 
229         assert_eq!(span_of!(Test, ..x), 0..0);
230         assert_eq!(span_of!(Test, ..=x), 0..8);
231         assert_eq!(span_of!(Test, ..y), 0..8);
232         assert_eq!(span_of!(Test, ..=y), 0..64);
233         assert_eq!(span_of!(Test, ..z), 0..64);
234         assert_eq!(span_of!(Test, ..=z), 0..68);
235         assert_eq!(span_of!(Test, ..egg), 0..68);
236         assert_eq!(span_of!(Test, ..=egg), 0..84);
237         assert_eq!(span_of!(Test, ..), 0..mem::size_of::<Test>());
238         assert_eq!(
239             span_of!(Test, x..),
240             offset_of!(Test, x)..mem::size_of::<Test>()
241         );
242         assert_eq!(
243             span_of!(Test, y..),
244             offset_of!(Test, y)..mem::size_of::<Test>()
245         );
246 
247         assert_eq!(
248             span_of!(Test, z..),
249             offset_of!(Test, z)..mem::size_of::<Test>()
250         );
251         assert_eq!(
252             span_of!(Test, egg..),
253             offset_of!(Test, egg)..mem::size_of::<Test>()
254         );
255         assert_eq!(
256             span_of!(Test, x..y),
257             offset_of!(Test, x)..offset_of!(Test, y)
258         );
259         assert_eq!(
260             span_of!(Test, x..=y),
261             offset_of!(Test, x)..offset_of!(Test, y) + mem::size_of::<[u8; 56]>()
262         );
263     }
264 }
265