@@ -1254,42 +1254,56 @@ impl<T> SizedTypeProperties for T {}
1254
1254
1255
1255
/// Expands to the offset in bytes of a field from the beginning of the given type.
1256
1256
///
1257
- /// Structs, enums, unions and tuples are supported .
1257
+ /// The type may be a `struct`, `enum`, `union`, or tuple .
1258
1258
///
1259
- /// Nested field accesses may be used, but not array indexes.
1259
+ /// The field may be a nested field (`field1.field2`), but not an array index.
1260
+ /// The field must be visible to the call site.
1260
1261
///
1261
- /// If the nightly-only feature `offset_of_enum` is enabled,
1262
- /// variants may be traversed as if they were fields.
1263
- /// Variants themselves do not have an offset.
1262
+ /// The offset is returned as a [`usize`].
1264
1263
///
1265
- /// Visibility is respected - all types and fields must be visible to the call site:
1264
+ /// # Offsets of, and in, dynamically sized types
1266
1265
///
1267
- /// ```
1268
- /// mod nested {
1269
- /// #[repr(C)]
1270
- /// pub struct Struct {
1271
- /// private: u8,
1272
- /// }
1273
- /// }
1266
+ /// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container.
1267
+ /// If the field type is dynamically sized, then you cannot use `offset_of!` (since the field's
1268
+ /// alignment, and therefore its offset, may also be dynamic) and must take the offset from an
1269
+ /// actual pointer to the container instead.
1274
1270
///
1275
- /// // assert_eq!(mem::offset_of!(nested::Struct, private), 0);
1276
- /// // ^^^ error[E0616]: field `private` of struct `Struct` is private
1277
- /// ```
1278
- ///
1279
- /// Only [`Sized`] fields are supported, but the container may be unsized:
1280
1271
/// ```
1281
1272
/// # use core::mem;
1273
+ /// # use core::fmt::Debug;
1282
1274
/// #[repr(C)]
1283
- /// pub struct Struct {
1275
+ /// pub struct Struct<T: ?Sized> {
1284
1276
/// a: u8,
1285
- /// b: [u8] ,
1277
+ /// b: T ,
1286
1278
/// }
1287
1279
///
1288
- /// assert_eq!(mem::offset_of!(Struct, a), 0); // OK
1289
- /// // assert_eq!(mem::offset_of!(Struct, b), 1);
1290
- /// // ^^^ error[E0277]: doesn't have a size known at compile-time
1280
+ /// #[derive(Debug)]
1281
+ /// #[repr(C, align(4))]
1282
+ /// struct Align4(u32);
1283
+ ///
1284
+ /// assert_eq!(mem::offset_of!(Struct<dyn Debug>, a), 0); // OK — Sized field
1285
+ /// assert_eq!(mem::offset_of!(Struct<Align4>, b), 4); // OK — not DST
1286
+ ///
1287
+ /// // assert_eq!(mem::offset_of!(Struct<dyn Debug>, b), 1);
1288
+ /// // ^^^ error[E0277]: ... cannot be known at compilation time
1289
+ ///
1290
+ /// // To obtain the offset of a !Sized field, examine a concrete value
1291
+ /// // instead of using offset_of!.
1292
+ /// let value: Struct<Align4> = Struct { a: 1, b: Align4(2) };
1293
+ /// let ref_unsized: &Struct<dyn Debug> = &value;
1294
+ /// let offset_of_b = unsafe {
1295
+ /// (&raw const ref_unsized.b).byte_offset_from_unsigned(ref_unsized)
1296
+ /// };
1297
+ /// assert_eq!(offset_of_b, 4);
1291
1298
/// ```
1292
1299
///
1300
+ /// If you need to obtain the offset of a field of a `!Sized` type, then, since the offset may
1301
+ /// depend on the particular value being stored (in particular, `dyn Trait` values have a
1302
+ /// dynamically-determined alignment), you must retrieve the offset from a specific reference
1303
+ /// or pointer, and so you cannot use `offset_of!` to work without one.
1304
+ ///
1305
+ /// # Layout is subject to change
1306
+ ///
1293
1307
/// Note that type layout is, in general, [subject to change and
1294
1308
/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If
1295
1309
/// layout stability is required, consider using an [explicit `repr` attribute].
@@ -1325,11 +1339,16 @@ impl<T> SizedTypeProperties for T {}
1325
1339
///
1326
1340
/// [explicit `repr` attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations
1327
1341
///
1342
+ /// # Unstable features
1343
+ ///
1344
+ /// The following unstable features expand the functionality of `offset_of!`:
1345
+ ///
1346
+ /// * [`offset_of_enum`] — allows `enum` variants to be traversed as if they were fields.
1347
+ /// * [`offset_of_slice`] — allows getting the offset of a field of type `[T]`.
1348
+ ///
1328
1349
/// # Examples
1329
1350
///
1330
1351
/// ```
1331
- /// #![feature(offset_of_enum)]
1332
- ///
1333
1352
/// use std::mem;
1334
1353
/// #[repr(C)]
1335
1354
/// struct FieldStruct {
@@ -1351,18 +1370,11 @@ impl<T> SizedTypeProperties for T {}
1351
1370
/// struct NestedB(u8);
1352
1371
///
1353
1372
/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
1354
- ///
1355
- /// #[repr(u8)]
1356
- /// enum Enum {
1357
- /// A(u8, u16),
1358
- /// B { one: u8, two: u16 },
1359
- /// }
1360
- ///
1361
- /// assert_eq!(mem::offset_of!(Enum, A.0), 1);
1362
- /// assert_eq!(mem::offset_of!(Enum, B.two), 2);
1363
- ///
1364
- /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0);
1365
1373
/// ```
1374
+ ///
1375
+ /// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
1376
+ /// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html
1377
+ /// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html
1366
1378
#[ stable( feature = "offset_of" , since = "1.77.0" ) ]
1367
1379
#[ allow_internal_unstable( builtin_syntax) ]
1368
1380
pub macro offset_of ( $Container: ty, $( $fields: expr) + $( , ) ?) {
0 commit comments