Skip to main content

TemplateRegistry

Struct TemplateRegistry 

Source
pub struct TemplateRegistry { /* private fields */ }
Expand description

Task 7’s owned, 'static substitute for dedup::TemplateTable<'d> (see this module’s top doc comment) — the minimal (TemplateKey, StateLayout) registry StateEngine actually needs after elaboration, once the sv_lang::Design-borrowing dedup walk itself is done.

Review fix (Task 7 r1): each StateLayout is individually boxed, and templates is UnsafeCell-wrapped so register never needs &mut self. allocate_instance hands out a *const StateLayout pointing directly into this registry’s backing storage (see InstanceHandle::layout). Two independent hazards, both now fixed:

  • With templates: Vec<(TemplateKey, StateLayout)> (the pre-fix shape), that pointer targeted the Vec’s own tuple element storage — a later register call growing this pub (via StateEngine.templates), and therefore externally reachable, Vec could reallocate it and silently dangle every previously-minted layout pointer, exactly the hazard register’s old doc comment warned about without preventing it. Vec<(TemplateKey, Box<StateLayout>)> instead gives each StateLayout its own, independent heap allocation: growing the outer Vec moves the Box pointers around, never the StateLayout values those pointers point at.
  • Separately (see StateEngine’s doc comment for the full argument): under Rust’s Stacked/Tree Borrows aliasing model, a Box<T> value being moved — including as a field of a larger struct moved by value, e.g. a StateEngine returned from a constructor — recursively retags (as freshly, exclusively owned) everything reachable through nested Box/&/&mut fields, which would silently invalidate a layout pointer minted before the move even though Box<StateLayout> itself never reallocates. templates therefore uses UnsafeCell (mutated only through &self, never &mut self, exactly like Arena) so that StateEngine.templates itself can be an Rc, not a Box — Rc’s move doesn’t carry that same recursive-retag semantics (it isn’t a uniquely-owning reference-like type), so Miri’s retag walk never descends into (and therefore never invalidates) the boxed StateLayouts nested inside.

Implementations§

Source§

impl TemplateRegistry

Source

pub fn new() -> Self

Source

pub unsafe fn register(&self, key: TemplateKey, layout: StateLayout)

Registers one template’s layout. Callable at any time, including after StateEngine::allocate_instance has already minted one or more InstanceHandles against this registry (see this struct’s doc comment for why growing templates no longer moves any already-registered StateLayout, and never needs to invalidate a previously-minted layout pointer via a StateEngine move either).

§Safety

The caller must ensure no other live &/&mut borrow into this registry’s backing Vec (in particular, no live &StateLayout returned by Self::layout_of) is held across this call, and that at most one logical writer registers templates at a time — the same single-logical-writer discipline Arena’s mutating accessors document. &self, not &mut self, so this can be called through a Rc<TemplateRegistry> (see StateEngine’s doc comment for why templates is an Rc, not a Box).

Source

pub fn layout_of(&self, key: &TemplateKey) -> Option<&StateLayout>

Template-relative layout lookup (ST-066-style: never a per-instance storage offset). Safe: any number of live &StateLayout reads coexist without aliasing; the aliasing obligation is on the unsafe Self::register instead (see its doc comment).

Trait Implementations§

Source§

impl Debug for TemplateRegistry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TemplateRegistry

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V