> From: Asahi Lina <lina@xxxxxxxxxxxxx> > > The XArray is an abstract data type which behaves like a very large > array of pointers. Add a Rust abstraction for this data type. > > The initial implementation uses explicit locking on get operations and > returns a guard which blocks mutation, ensuring that the referenced > object remains alive. To avoid excessive serialization, users are > expected to use an inner type that can be efficiently cloned (such as > Arc<T>), and eagerly clone and drop the guard to unblock other users > after a lookup. > > Future variants may support using RCU instead to avoid mutex locking. > > This abstraction also introduces a reservation mechanism, which can be > used by alloc-capable XArrays to reserve a free slot without immediately > filling it, and then do so at a later time. If the reservation is > dropped without being filled, the slot is freed again for other users, > which eliminates the need for explicit cleanup code. > > Signed-off-by: Asahi Lina <lina@xxxxxxxxxxxxx> > Co-developed-by: Maíra Canal <mcanal@xxxxxxxxxx> > Signed-off-by: Maíra Canal <mcanal@xxxxxxxxxx> Sorry for the delay in reviewing this. I have one important comment (the first one), and the rest are nits that are not so important. > +pub struct Guard<'a, T: ForeignOwnable>(NonNull<T>, &'a XArray<T>); This stores a pointer to a `T`, but really it's the pointer returned by `into_foreign`, correct? So e.g. in the case of `T = Box<U>`, you have an `NonNull<Box<U>>`, even though the pointer actually points at an `U`, not a `Box<U>`. I think it's better to keep this as `NonNull<c_void>`, since that's the type used by `into_foreign`. That also lets you remove a bunch of calls to `.cast()`. > +/// INVARIANT: All pointers stored in the array are pointers obtained by > +/// calling `T::into_foreign` or are NULL pointers. By using the pin-init > +/// initialization, `self.xa` is always an initialized and valid XArray. Nit: usually invariants listed on structs use this heading: /// # Invariants /// /// All pointers stored ... Nit: You also do not need to mention that you use pin-init to make `self.xa` be initialized and valid. It's enough to explain that it is always initialized and valid - the *how* is not necessary in this type of comment. > +/// Represents a reserved slot in an `XArray`, which does not yet have a value but has an assigned > +/// index and may not be allocated by any other user. If the Reservation is dropped without > +/// being filled, the entry is marked as available again. > +/// > +/// Users must ensure that reserved slots are not filled by other mechanisms, or otherwise their > +/// contents may be dropped and replaced (which will print a warning). > +pub struct Reservation<'a, T: ForeignOwnable>(&'a XArray<T>, usize, PhantomData<T>); Nit: I don't think the PhantomData is necessary here. > + if !new.is_null() { > + // SAFETY: If `new` is not NULL, it came from the `ForeignOwnable` we got > + // from the caller. > + unsafe { T::from_foreign(new) }; > + } Nit: Adding a call to `drop` here makes the code more clear to me. > + unsafe { > + bindings::xa_destroy(self.xa.get()); > + } Nit: Moving the semicolon outside of the unsafe block formats better. Alice