@@ -229,7 +229,16 @@ particular, the implementation should not allocate space for an instance of
229
229
time) would otherwise be hard-coded, so in some cases it may reduce the risk
230
230
of a compatibility hazard.
231
231
232
- 2 . This is a feature most code won't need to use, and it may be confusing to
232
+ 2 . Similarly, this reduces the amount of dynamism that a Rust implementation
233
+ could use for ` repr(Rust) ` types.
234
+
235
+ For example, it forbids a Rust implementation from varying field offsets of
236
+ ` repr(Rust) ` types between executions of the same compiled program (for
237
+ example, by way of interpretation or code modification), unless it also
238
+ performs modifications to adjust the result of ` offset_of! ` (and recompute
239
+ the values of derived constants, and regenerate relevant code, ...).
240
+
241
+ 3 . This is a feature most code won't need to use, and it may be confusing to
233
242
users unfamiliar with low level programming.
234
243
235
244
# Rationale and alternatives
@@ -255,6 +264,12 @@ considered:
255
264
implementation from ` memoffset ` , or the implementation they could implement
256
265
if they computed it manually.
257
266
267
+ Needing the offset of fields on ` #[repr(Rust)] ` is not as common, but still
268
+ useful in code which needs to describe precise details of type layout to
269
+ some other system, including GPU APIs which accept configurable vertex
270
+ formats or binary serialization formats that contain descriptions of the
271
+ field offsets for the record types they contain, etc.
272
+
258
273
3 . Require that all fields of ` $Container ` be visible at the invocation site,
259
274
rather than just requiring that ` $field ` is.
260
275
@@ -409,6 +424,28 @@ functionality.
409
424
This proposal is intentionally minimal, so there are a number of future
410
425
possibilities.
411
426
427
+ ## Nested Field Access
428
+
429
+ In C, expressions like ` offsetof(struct some_struct, foo.bar.baz[3].quux) ` are
430
+ allowed, where ` foo.bar.baz[3].quux ` denotes a path to a derived field. This can
431
+ be of somewhat arbitrary complexity, accessing fields of nested structs,
432
+ performing array indexing (often this is used to access past the end of the
433
+ array even), and so on. Similar functionality is offered by
434
+ ` MemoryLayout.offset ` in Swift, where more complex language features are used to
435
+ achieve it.
436
+
437
+ This was omitted from this proposal because it is not commonly used, and can
438
+ generally be replaced (at the cost of convenience) by multiple invocations of
439
+ the macro.
440
+
441
+ Additionally, in the future similar functionality could be added in a
442
+ backwards-compatible way, either by directly allowing usage like
443
+ ` offset_of!(SomeStruct, foo.bar.baz[3].quux) ` , or by requiring each field be
444
+ comma-separated, as in ` offset_of!(SomeStruct, foo, bar, baz, [3], quux) ` .
445
+
446
+ Note that while this example shows a combination that supports array indexing,
447
+ it's unclear if this is actually desirable for Rust.
448
+
412
449
## Enum support (` offset_of!(SomeEnum::StructVariant, field_on_variant) ` )
413
450
414
451
Eventually, it may be desirable to allow ` offset_of! ` to access the fields
@@ -417,7 +454,7 @@ with a primitive integer representation, such as `#[repr(C)]`, `#[repr(int)]`,
417
454
or ` #[repr(C, int)] ` -- where ` int ` is one of Rust's primitive integer types —
418
455
u8, isize, u128, etc).
419
456
420
- For example, in the future somthing like the following could be allowed:
457
+ For example, in the future something like the following could be allowed:
421
458
422
459
``` rs
423
460
use core :: mem :: offset_of;
@@ -440,27 +477,9 @@ While there are use-cases for this in low level FFI code (similar to the use
440
477
cases for ` #[repr(int)] ` and ` #[repr(C, int)] ` enums), this may need further
441
478
design work, and is left to the future.
442
479
443
- ## Nested Field Access
444
-
445
- In C, expressions like ` offsetof(struct some_struct, foo.bar.baz[3].quux) ` are
446
- allowed, where ` foo.bar.baz[3].quux ` denotes a path to a derived field. This can
447
- be of somewhat arbitrary complexity, accessing fields of nested structs,
448
- performing array indexing (often this is used to access past the end of the
449
- array even), and so on. Similar functionality is offered by
450
- ` MemoryLayout.offset ` in Swift, where more complex language features are used to
451
- achieve it.
452
-
453
- This was omitted from this proposal because it is not commonly used, and can
454
- generally be replaced (at the cost of convenience) by multiple invocations of
455
- the macro.
456
-
457
- Additionally, in the future similar functionality could be added in a fully
458
- backwards-compatible way, either by directly allowing usage like
459
- ` offset_of!(SomeStruct, foo.bar.baz[3].quux) ` , or by requiring each field be
460
- comma-separated, as in ` offset_of!(SomeStruct, foo, bar, baz, [3], quux) ` .
461
-
462
- Note that while this example shows a combination that supports array indexing,
463
- it's unclear if this is actually desirable for Rust.
480
+ A drawback is that it is unclear how to support these types in the "Nested Field
481
+ Access" proposed above, so in the future should we decide to support one of
482
+ these, a decision may need to be made about the other.
464
483
465
484
## ` memoffset::span_of! ` Functionality
466
485
@@ -474,9 +493,46 @@ would be simple to add a similar macro to `core::mem` in the future.
474
493
475
494
[ spanof ] : https://docs.rs/memoffset/0.6.5/memoffset/macro.span_of.html
476
495
477
- ## Support for types with ` ?Sized ` fields.
496
+ ## Support for types with unsized fields
497
+
498
+ ### ... via ` offset_of_val! `
499
+
500
+ Currently, we don't support use with unsized types. That is, ` (A, B, ... [T]) `
501
+ and/or ` (A, B, ..., dyn Foo) ` , or their equivalent in structs.
502
+
503
+ The reason for this is that the offset of the unsized field is not always known,
504
+ such as in the case of the last field in ` (Foo, dyn SomeTrait) ` , where the
505
+ offset depends on what the concrete type is. Notably, the compiler must read the
506
+ alignment out of the vtable when you access such a field.
507
+
508
+ This is equivalent to not being able to determine the the size and/or alignment
509
+ of ` ?Sized ` types, where we solve it by making the user provide the instance
510
+ they're interested in, as in ` core::mem::{size_of_val, align_of_val} ` , so we
511
+ could provide an analogous ` core::mem::offset_of_val!($val, $Type, $field) ` to
512
+ support this case.
513
+
514
+ It would be reasonable to add this in the future, but is left out for now.
515
+
516
+ ### ... by only forbidding the edge case
517
+
518
+ The only case where we currently do * not* know the offset of a field statically
519
+ is when the user has requested the offset of the unsized field, and the unsized
520
+ field is a trait object.
521
+
522
+ There are valid reasons to want to get the offset of:
523
+ 1 . The fields before the unsized field, as in ` offset_of!((i32, dyn Send), 0) ` .
524
+ 2 . The unsized field if it's a ` [T] ` , ` str ` , or other case where the offset does
525
+ not depend on reading the metadata, as in ` offset_of!((i32, [u16]), 1) ` .
526
+
527
+ Allowing these is somewhat inconsistent with ` align_of ` , which could provide the
528
+ alignment in some cases, but forbids it for all ` ?Sized ` types (admittedly,
529
+ allowing ` align_of::<[T]>() ` is not particularly compelling, as it's always the
530
+ same as ` align_of::<T>() ` ).
478
531
479
- Currently, we don't support ` offset_of!((u8, [i32]), 1) ` , as ` (u8, [i32]) ` does
480
- not implement ` Sized ` .
532
+ Either way, it's trivially backwards compatible for us to eventually start
533
+ allowing these, and for the trailing slice/str case, it seems difficult to pin
534
+ down the cases where it's allowed without risk of complicating potential future
535
+ features (like custom DSTs, extern types, or whatever other new unsized types we
536
+ might want to add).
481
537
482
- This is a mostly artificial restriction, and could be relaxed in the future.
538
+ As such, it's left for future work .
0 commit comments