@@ -140,5 +140,70 @@ fn panic(_info: &PanicInfo) -> ! {
140
140
}
141
141
}
142
142
143
+ /// Calculates the offset of a field from the beginning of the struct it belongs to.
144
+ ///
145
+ /// # Example
146
+ ///
147
+ ///```
148
+ /// struct Test {
149
+ /// a: u64,
150
+ /// b: u32,
151
+ /// }
152
+ ///
153
+ /// fn test() {
154
+ /// // This prints `8`.
155
+ /// println!("{}", offset_of!(Test, b));
156
+ /// }
157
+ ///```
158
+ #[ macro_export]
159
+ macro_rules! offset_of {
160
+ ( $type: ty, $( $f: tt) * ) => { {
161
+ let tmp = core:: mem:: MaybeUninit :: <$type>:: uninit( ) ;
162
+ let outer = tmp. as_ptr( ) ;
163
+ // To avoid warnings when nesting `unsafe` blocks.
164
+ #[ allow( unused_unsafe) ]
165
+ // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
166
+ // we don't actually read from `outer` (which would be UB) nor create an intermediate
167
+ // reference.
168
+ let inner = unsafe { core:: ptr:: addr_of!( ( * outer) . $( $f) * ) } as * const u8 ;
169
+ // To avoid warnings when nesting `unsafe` blocks.
170
+ #[ allow( unused_unsafe) ]
171
+ // SAFETY: The two pointers are within the same allocation block.
172
+ unsafe { inner. offset_from( outer as * const u8 ) }
173
+ } }
174
+ }
175
+
176
+ /// Produces a pointer to an object from a pointer to one of its fields.
177
+ ///
178
+ /// # Safety
179
+ ///
180
+ /// Callers must ensure that the pointer to the field is in fact a pointer to the specified field,
181
+ /// as opposed to a pointer to another object of the same type.
182
+ ///
183
+ /// # Example
184
+ ///
185
+ ///```
186
+ /// struct Test {
187
+ /// a: u64,
188
+ /// b: u32,
189
+ /// }
190
+ ///
191
+ /// fn test() {
192
+ /// let test = Test{a: 10, b: 20};
193
+ /// let b_ptr = &test.b;
194
+ /// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
195
+ /// // This prints `true`.
196
+ /// println!("{}", core::ptr::eq(&test, test_alias));
197
+ /// }
198
+ ///```
199
+ ///
200
+ #[ macro_export]
201
+ macro_rules! container_of {
202
+ ( $ptr: expr, $type: ty, $( $f: tt) * ) => { {
203
+ let offset = $crate:: offset_of!( $type, $( $f) * ) ;
204
+ ( $ptr as * const _ as * const u8 ) . offset( -offset) as * const $type
205
+ } }
206
+ }
207
+
143
208
#[ global_allocator]
144
209
static ALLOCATOR : allocator:: KernelAllocator = allocator:: KernelAllocator ;
0 commit comments