1 #![forbid(unsafe_code)] 2 3 /// Find the offset in bytes of the given `$field` of `$Type`. Requires an 4 /// already initialized `$instance` value to work with. 5 /// 6 /// This is similar to the macro from [`memoffset`](https://docs.rs/memoffset), 7 /// however it uses no `unsafe` code. 8 /// 9 /// This macro has a 3-argument and 2-argument version. 10 /// * In the 3-arg version you specify an instance of the type, the type itself, 11 /// and the field name. 12 /// * In the 2-arg version the macro will call the [`default`](Default::default) 13 /// method to make a temporary instance of the type for you. 14 /// 15 /// The output of this macro is the byte offset of the field (as a `usize`). The 16 /// calculations of the macro are fixed across the entire program, but if the 17 /// type used is `repr(Rust)` then they're *not* fixed across compilations or 18 /// compilers. 19 /// 20 /// ## Examples 21 /// 22 /// ### 3-arg Usage 23 /// 24 /// ```rust 25 /// # use bytemuck::offset_of; 26 /// // enums can't derive default, and for this example we don't pick one 27 /// enum MyExampleEnum { 28 /// A, 29 /// B, 30 /// C, 31 /// } 32 /// 33 /// // so now our struct here doesn't have Default 34 /// #[repr(C)] 35 /// struct MyNotDefaultType { 36 /// pub counter: i32, 37 /// pub some_field: MyExampleEnum, 38 /// } 39 /// 40 /// // but we provide an instance of the type and it's all good. 41 /// let val = MyNotDefaultType { counter: 5, some_field: MyExampleEnum::A }; 42 /// assert_eq!(offset_of!(val, MyNotDefaultType, some_field), 4); 43 /// ``` 44 /// 45 /// ### 2-arg Usage 46 /// 47 /// ```rust 48 /// # use bytemuck::offset_of; 49 /// #[derive(Default)] 50 /// #[repr(C)] 51 /// struct Vertex { 52 /// pub loc: [f32; 3], 53 /// pub color: [f32; 3], 54 /// } 55 /// // if the type impls Default the macro can make its own default instance. 56 /// assert_eq!(offset_of!(Vertex, loc), 0); 57 /// assert_eq!(offset_of!(Vertex, color), 12); 58 /// ``` 59 /// 60 /// # Usage with `#[repr(packed)]` structs 61 /// 62 /// Attempting to compute the offset of a `#[repr(packed)]` struct with 63 /// `bytemuck::offset_of!` requires an `unsafe` block. We hope to relax this in 64 /// the future, but currently it is required to work around a soundness hole in 65 /// Rust (See [rust-lang/rust#27060]). 66 /// 67 /// [rust-lang/rust#27060]: https://github.com/rust-lang/rust/issues/27060 68 /// 69 /// <p style="background:rgba(255,181,77,0.16);padding:0.75em;"> 70 /// <strong>Warning:</strong> This is only true for versions of bytemuck > 71 /// 1.4.0. Previous versions of 72 /// <code style="background:rgba(41,24,0,0.1);">bytemuck::offset_of!</code> 73 /// will only emit a warning when used on the field of a packed struct in safe 74 /// code, which can lead to unsoundness. 75 /// </p> 76 /// 77 /// For example, the following will fail to compile: 78 /// 79 /// ```compile_fail 80 /// #[repr(C, packed)] 81 /// #[derive(Default)] 82 /// struct Example { 83 /// field: u32, 84 /// } 85 /// // Doesn't compile: 86 /// let _offset = bytemuck::offset_of!(Example, field); 87 /// ``` 88 /// 89 /// While the error message this generates will mention the 90 /// `safe_packed_borrows` lint, the macro will still fail to compile even if 91 /// that lint is `#[allow]`ed: 92 /// 93 /// ```compile_fail 94 /// # #[repr(C, packed)] #[derive(Default)] struct Example { field: u32 } 95 /// // Still doesn't compile: 96 /// #[allow(safe_packed_borrows)] 97 /// { 98 /// let _offset = bytemuck::offset_of!(Example, field); 99 /// } 100 /// ``` 101 /// 102 /// This *can* be worked around by using `unsafe`, but it is only sound to do so 103 /// if you can guarantee that taking a reference to the field is sound. 104 /// 105 /// In practice, this means it only works for fields of align(1) types, or if 106 /// you know the field's offset in advance (defeating the point of `offset_of`) 107 /// and can prove that the struct's alignment and the field's offset are enough 108 /// to prove the field's alignment. 109 /// 110 /// Once the `raw_ref` macros are available, a future version of this crate will 111 /// use them to lift the limitations of packed structs. For the duration of the 112 /// `1.x` version of this crate that will be behind an on-by-default cargo 113 /// feature (to maintain minimum rust version support). 114 #[macro_export] 115 macro_rules! offset_of { 116 ($instance:expr, $Type:path, $field:tt) => {{ 117 #[forbid(safe_packed_borrows)] 118 { 119 // This helps us guard against field access going through a Deref impl. 120 #[allow(clippy::unneeded_field_pattern)] 121 let $Type { $field: _, .. }; 122 let reference: &$Type = &$instance; 123 let address = reference as *const _ as usize; 124 let field_pointer = &reference.$field as *const _ as usize; 125 // These asserts/unwraps are compiled away at release, and defend against 126 // the case where somehow a deref impl is still invoked. 127 let result = field_pointer.checked_sub(address).unwrap(); 128 assert!(result <= $crate::__core::mem::size_of::<$Type>()); 129 result 130 } 131 }}; 132 ($Type:path, $field:tt) => {{ 133 $crate::offset_of!(<$Type as Default>::default(), $Type, $field) 134 }}; 135 } 136