@@ -229,7 +229,16 @@ particular, the implementation should not allocate space for an instance of
229229 time) would otherwise be hard-coded, so in some cases it may reduce the risk
230230 of a compatibility hazard.
231231
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
233242 users unfamiliar with low level programming.
234243
235244# Rationale and alternatives
@@ -255,6 +264,12 @@ considered:
255264 implementation from ` memoffset ` , or the implementation they could implement
256265 if they computed it manually.
257266
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+
2582733 . Require that all fields of ` $Container ` be visible at the invocation site,
259274 rather than just requiring that ` $field ` is.
260275
@@ -409,6 +424,28 @@ functionality.
409424This proposal is intentionally minimal, so there are a number of future
410425possibilities.
411426
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+
412449## Enum support (` offset_of!(SomeEnum::StructVariant, field_on_variant) ` )
413450
414451Eventually, 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)]`,
417454or ` #[repr(C, int)] ` -- where ` int ` is one of Rust's primitive integer types —
418455u8, isize, u128, etc).
419456
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:
421458
422459``` rs
423460use core :: mem :: offset_of;
@@ -440,27 +477,9 @@ While there are use-cases for this in low level FFI code (similar to the use
440477cases for ` #[repr(int)] ` and ` #[repr(C, int)] ` enums), this may need further
441478design work, and is left to the future.
442479
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.
464483
465484## ` memoffset::span_of! ` Functionality
466485
@@ -474,9 +493,46 @@ would be simple to add a similar macro to `core::mem` in the future.
474493
475494[ spanof ] : https://docs.rs/memoffset/0.6.5/memoffset/macro.span_of.html
476495
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>() ` ).
478531
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).
481537
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