| 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 | |