24
24
#[ macro_export]
25
25
#[ doc( hidden) ]
26
26
macro_rules! _memoffset__let_base_ptr {
27
- ( $name: ident, $type: path ) => {
27
+ ( $name: ident, $type: ty ) => {
28
28
// No UB here, and the pointer does not dangle, either.
29
29
// But we have to make sure that `uninit` lives long enough,
30
30
// so it has to be in the same scope as `$name`. That's why
@@ -38,7 +38,7 @@ macro_rules! _memoffset__let_base_ptr {
38
38
#[ macro_export]
39
39
#[ doc( hidden) ]
40
40
macro_rules! _memoffset__let_base_ptr {
41
- ( $name: ident, $type: path ) => {
41
+ ( $name: ident, $type: ty ) => {
42
42
// No UB right here, but we will later dereference this pointer to
43
43
// offset into a field, and that is UB because the pointer is dangling.
44
44
let $name = $crate:: mem:: align_of:: <$type>( ) as * const $type;
@@ -66,7 +66,7 @@ macro_rules! _memoffset_offset_from {
66
66
} ;
67
67
}
68
68
69
- /// Calculates the offset of the specified field from the start of the struct.
69
+ /// Calculates the offset of the specified field from the start of the named struct.
70
70
///
71
71
/// ## Examples
72
72
/// ```
@@ -97,6 +97,30 @@ macro_rules! offset_of {
97
97
} } ;
98
98
}
99
99
100
+ /// Calculates the offset of the specified field from the start of the tuple.
101
+ ///
102
+ /// ## Examples
103
+ /// ```
104
+ /// #[macro_use]
105
+ /// extern crate memoffset;
106
+ ///
107
+ /// fn main() {
108
+ /// assert!(offset_of_tuple!((u8, u32), 1) >= 0, "Tuples do not have a defined layout");
109
+ /// }
110
+ /// ```
111
+ #[ cfg( tuple_ty) ]
112
+ #[ macro_export( local_inner_macros) ]
113
+ macro_rules! offset_of_tuple {
114
+ ( $parent: ty, $field: tt) => { {
115
+ // Get a base pointer (non-dangling if rustc supports `MaybeUninit`).
116
+ _memoffset__let_base_ptr!( base_ptr, $parent) ;
117
+ // Get field pointer.
118
+ let field_ptr = raw_field_tuple!( base_ptr, $parent, $field) ;
119
+ // Compute offset.
120
+ _memoffset_offset_from!( field_ptr, base_ptr)
121
+ } } ;
122
+ }
123
+
100
124
#[ cfg( test) ]
101
125
mod tests {
102
126
#[ test]
@@ -160,6 +184,19 @@ mod tests {
160
184
assert_eq ! ( foo( Pair ( 0 , 0 ) ) , 4 ) ;
161
185
}
162
186
187
+ #[ cfg( tuple_ty) ]
188
+ #[ test]
189
+ fn test_tuple_offset ( ) {
190
+ let f = ( 0i32 , 0.0f32 , 0u8 ) ;
191
+ let f_ptr = & f as * const _ ;
192
+ let f1_ptr = & f. 1 as * const _ ;
193
+
194
+ assert_eq ! (
195
+ f1_ptr as usize - f_ptr as usize ,
196
+ offset_of_tuple!( ( i32 , f32 , u8 ) , 1 )
197
+ ) ;
198
+ }
199
+
163
200
#[ test]
164
201
fn test_raw_field ( ) {
165
202
#[ repr( C ) ]
@@ -180,6 +217,27 @@ mod tests {
180
217
assert_eq ! ( f_ptr as usize + 8 , raw_field!( f_ptr, Foo , c) as usize ) ;
181
218
}
182
219
220
+ #[ cfg( tuple_ty) ]
221
+ #[ test]
222
+ fn test_raw_field_tuple ( ) {
223
+ let t = ( 0u32 , 0u8 , false ) ;
224
+ let t_ptr = & t as * const _ ;
225
+ let t_addr = t_ptr as usize ;
226
+
227
+ assert_eq ! (
228
+ & t. 0 as * const _ as usize - t_addr,
229
+ raw_field_tuple!( t_ptr, ( u32 , u8 , bool ) , 0 ) as usize - t_addr
230
+ ) ;
231
+ assert_eq ! (
232
+ & t. 1 as * const _ as usize - t_addr,
233
+ raw_field_tuple!( t_ptr, ( u32 , u8 , bool ) , 1 ) as usize - t_addr
234
+ ) ;
235
+ assert_eq ! (
236
+ & t. 2 as * const _ as usize - t_addr,
237
+ raw_field_tuple!( t_ptr, ( u32 , u8 , bool ) , 2 ) as usize - t_addr
238
+ ) ;
239
+ }
240
+
183
241
#[ cfg( feature = "unstable_const" ) ]
184
242
#[ test]
185
243
fn const_offset ( ) {
0 commit comments