Nice read!! A few comments:
The entire instance is pinned: this method takes
Pin<&mut Self>
.
Careful with Pin
, and careful with making too much publicity for it: it is a subtle wrapper. For instance, the statement alone "it is pinned because Pin<&mut Self>
" is wrong: something is pinned if behind a Pin
-wrapped pointer, such as Pin<&mut Self>
, and is Pin
-aware / is unable to unpin itself / is !Unpin
.
- And then once you get something correctly pinned, the whole thing becomes less ergonomic to work with. So I'd definitely favor the getter approach (which gets to be shared for all
Instance
s of a sameClass
, where the self-referential pointer required that all pinnedInstance
s carried them with them.
An alternative to self-referential pointers are offset-based pointers, which in this case, now that I think of it, could make a lot of sense:
-
the offsets are type-based, so they can be stored within the class,
-
they single1-handedly solve the issues pointed out by:
1 At the meager cost of a #[repr(C)]
attribute
Obviously, all this would be a micro-optimization more than anything else, but maybe one worth keeping in the back of the one's head
Another micro-optimization (super tiny, to be fair): I feel like this could be using fn(&Instance) -> PolarValue
pointer-types rather than Arc<dyn Fn...>
. It will save a few atomic {in,de}crements and one level of pointer indirection, and reduce the size of its containing struct by one usize
- It is easy to implement with
const
generics, but without them, you need to hack your way into them with some type-level programming hacks.