owned this note changed 2 years ago
Published Linked with GitHub

Reading notes: RFC 3318, Field Projection

Link to document: https://github.com/y86-dev/rfcs/blob/field-projection/text/3318-field-projection.md

tags: reading-club

Leave questions, observations, discussion topics below.


Topic

name: prompt


Composability

(might be addressed in RFC text, not yet sure)

pnkfelix: Can the projections described here be composed with themselves, such that e.g. &MaybeUninit<Cell<Struct>> can be projectred to &MaybeUninit<Cell<Field>>? Or does this only go "one level deep" ?

vincenzopalazzo: this is unclear also to me, and it is unclear also how the solution proposed in the RFC works at implementation level

https://github.com/y86-dev/rfcs/blob/field-projection/text/3318-field-projection.md#reference-level-explanation and "Supported pointers"

Distinction between P pointer types and Wrapper types (both happen to include Pin)

tmandry: Don't see a reason why not I guess

How to express non-magic-projecting access?

(might be addressed in RFC text, not yet sure)

pnkfelix: If one of the types in question already a struct, do we need to continue to support the previous access? If so, how is that expressed via a new operator? Or by some thing analogous to UFCS, but now for field access rather than method calls? (E.g. how does one express what would today be denoted by .inner for a given #[repr(transparent)] type)

pnkfelix: I could imagine support for the previous kind of access might still be expressable via match oh lets ask about that too Update: RFC as written does not allow for the old semantics to be expressed via let and presumably via match either, see below

pnkfelix: Maybe the intention is that you can get access to the original fields by first turning your &Wrapper into a *const Wrapper and then the .-projection operator acts on the Wrapper type, not on the projected type?

Field access has higher priority than projection:
https://github.com/y86-dev/rfcs/blob/field-projection/text/3318-field-projection.md#deref-and-derefmut

pnkfelix: But then if I try to access some field inner (and that's in Pin) then we have privacy-dependent name resolution? Maybe we want/have this anyway.

tmandry: Probably should be called out in the RFC.

does this impact match/let semantics (answer: yes)

Update: The intention is that this will affect bindings; let is demonstrated in the RFC text, and presumably match is affected as well.

pnkfelix: I can understand how foo.field ends up projecting out the internals of field within foo. But does that also mean that this is impacted:

let foo: &Cell<Struct> = ...; match foo { Struct { field } => ... // does this *start working*, where `field` now has type `&Cell<Field>` ? }

https://github.com/y86-dev/rfcs/blob/field-projection/text/3318-field-projection.md#bindings

pnkfelix: "Enum bindings cannot be supported with the wrappers MaybeUninit<T> and Cell<T>". What's the actual constraint here?

eholk: They don't explain what to do about the UB here.

pnkfelix: Seems like you get clear benefits from . and (things you can put on rhs of a let), don't know why they attempted to do matches in the first go-round.

pnkfelix: Seems simplest to punt, but then again, maybe it's so valuable to match on an enum etc that we should work it out.

Implementation details

(vincenzopalazzo) Why project one filed if you can prepare the code to project with an infinite struct filed?

The code could be

#[project(Pin)]
struct MyStruct {
    buf: [u8; 64],
    ptr: *const u8,
    _pin: PhantomPinned,
}

// gen by the macros

trait ProjectPinForMyStruct {
    fn buf_as_pin(&self) -> Pin<[u8; 64]>; // not sure that compile :)
    
   fn ptr_as_pin(&self) -> Pin<....>
}

impl ProjectPinForMyStruct for MyStruct {
   fn buf_as_pin(&self) -> Pin<[u8; 64]>; // not sure that compile :)
    
   fn ptr_as_pin(&self) -> Pin<....>
    
    ... so on
}

pnkfelix: (Something about disjoint fields, sorry bad notes)

eholk: It also talks about Arc projection

Relation to dyn*

tmandry: The NoMetadataPtr trait and some operations proposed for projection look kind of like dyn* if you squint. Is there some kind of relationship here or is that just surface-level resemblance?

eholk: I was wondering the same thing.

pnkfelix: dyn* is not google-able :)

eholk: I almost called in dyn⭐ when I was making the parsing change

tmandry: dyn* Future is pointer+vtable-sized object that implements Future; has a conversion trait like IntoRawPointer that looks just like NoMetadataPtr.

tmandry: One possible difference is that dyn* can represent Box (pnkfelix: also Arc) and ownership, whereas this is about borrowed data exclusively

pnkfelix: More utility for this is projection of field where you erase the knowledge of original struct?

tmandry: I guess I don't see a reason why they can't be the same trait.

eholk: If you squint, dyn* might be able to represent a lot of these projection.

Select a repo