AnimationStore

Struct AnimationStore 

Source
pub struct AnimationStore {
    anims: RefCell<Vec<Box<dyn CoreItemAnimation>>>,
}
Expand description

A store of animations

It has interior mutability, because when pushing an animation into it, we need to return a reference to the animation, which is bound to the store’s lifetime.

To allow the mutation, we use a RefCell<Vec<Box<dyn AnyAnimation>>> in its inner.

§Safety Contract

The following invariants must be maintained:

  • No mutation after push: Once an animation is pushed into the store, it should never be mutated or removed. The only allowed mutation is pushing new animations into the store.

  • No Vec reallocation issues: The returned references from push_eval_dynamic point directly to the heap-allocated AnimationCell<T> data inside the Box<dyn AnyAnimation>. Even if the Vec reallocates (which moves the Boxes), the heap data itself doesn’t move, so the pointers remain valid. This is safe because Box owns heap-allocated data, and the data doesn’t move when the Box is moved within the Vec.

Fields§

§anims: RefCell<Vec<Box<dyn CoreItemAnimation>>>

Implementations§

Source§

impl AnimationStore

Source

pub fn new() -> Self

Create a new store.

Source

pub fn push_animation<T: AnyExtractCoreItem>( &self, anim: AnimationCell<T>, ) -> &AnimationCell<T>

Push an AnimationCell<T> into the store and return a reference to it.

The returned reference is bound to &self’s lifetime, which means it will be invalidated when the store is dropped. Since we use RefCell for interior mutability, we can modify the internal Vec while holding a shared reference &self.

§Safety

This function uses unsafe code to return a reference that outlives the RefCell borrow. The safety relies on the following guarantees:

  1. Pointer validity: The raw pointer ptr points to the heap-allocated AnimationCell<T> that is now owned by the Vec<Box<dyn AnyAnimation>> inside self.anims.

  2. Memory layout: When we coerce Box<AnimationCell<T>> to Box<dyn AnyAnimation>, only the vtable pointer changes. The data pointer (pointing to the actual AnimationCell<T> on the heap) remains the same, so ptr is still valid.

  3. Vec reallocation safety: Even if the Vec reallocates (which moves the Boxes), the heap-allocated AnimationCell<T> data inside each Box does not move. The pointer ptr points directly to this heap data, not to the Box itself, so it remains valid regardless of Vec reallocations. This is a key property of Box: moving the Box doesn’t move the data it points to on the heap.

  4. Lifetime binding: The returned reference &AnimationCell<T> has a lifetime that is inferred from &self, ensuring it cannot outlive the store. This is enforced by Rust’s borrow checker.

  5. No mutation after push: Once pushed, the animation is never mutated or removed, so the pointer remains valid for the lifetime of the store.

Trait Implementations§

Source§

impl Default for AnimationStore

Source§

fn default() -> AnimationStore

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

Auto Trait Implementations§

Blanket Implementations§

§

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

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

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

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

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

§

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

Mutably borrows from an owned value. Read more
Source§

impl<T> Discard for T

Source§

fn discard(&self)

Simply returns ()
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
§

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

§

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

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

§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

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

§

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

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

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

Performs the conversion.
Source§

impl<T> With for T

Source§

fn with(self, f: impl Fn(&mut Self)) -> Self
where Self: Sized,

Mutating a value in place
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more