1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
// Copyright (c) 2017 Gilad Naaman // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /// Calculates the offset of the specified field from the start of the struct. /// This macro supports arbitrary amount of subscripts and recursive member-accesses. /// /// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]` /// /// ## Examples - Simple /// ``` /// #[macro_use] /// extern crate memoffset; /// /// #[repr(C, packed)] /// struct Foo { /// a: u32, /// b: u64, /// c: [u8; 5] /// } /// /// fn main() { /// assert_eq!(offset_of!(Foo, a), 0); /// assert_eq!(offset_of!(Foo, b), 4); /// assert_eq!(offset_of!(Foo, c[2]), 14); /// } /// ``` /// /// ## Examples - Advanced /// ``` /// #[macro_use] /// extern crate memoffset; /// /// #[repr(C, packed)] /// struct UnnecessarilyComplicatedStruct { /// member: [UnnecessarilyComplexStruct; 12] /// } /// /// #[repr(C, packed)] /// struct UnnecessarilyComplexStruct { /// a: u32, /// b: u64, /// c: [u8; 5] /// } /// /// /// fn main() { /// assert_eq!(offset_of!(UnnecessarilyComplicatedStruct, member[3].c[3]), 66); /// } /// ``` #[macro_export] macro_rules! offset_of { ($father:ty, $($field:tt)+) => ({ #[allow(unused_unsafe)] let root: $father = unsafe { $crate::mem::uninitialized() }; let base = &root as *const _ as usize; // Future error: borrow of packed field requires unsafe function or block (error E0133) #[allow(unused_unsafe)] let member = unsafe { &root.$($field)* as *const _ as usize }; $crate::mem::forget(root); member - base }); } #[cfg(test)] mod tests { #[repr(C, packed)] struct Foo { a: u32, b: [u8; 4], c: i64, } #[test] fn offset_simple() { assert_eq!(offset_of!(Foo, a), 0); assert_eq!(offset_of!(Foo, b), 4); assert_eq!(offset_of!(Foo, c), 8); } #[test] fn offset_index() { assert_eq!(offset_of!(Foo, b[2]), 6); } #[test] #[should_panic] fn offset_index_out_of_bounds() { offset_of!(Foo, b[4]); } #[test] fn tuple_struct() { #[repr(C, packed)] struct Tup(i32, i32); assert_eq!(offset_of!(Tup, 0), 0); } }