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