//! This module defines and implements [`World`] storage within a [`Registry`].
//!
//! In order to store components within archetype tables in a `World`, we have to define recursive
//! functions over the components of the heterogeneous lists that are the registries. For most
//! functions an `identifier_iter` is provided which informs the `Registry` which components should
//! be acted upon for the columns of that table.
//!
//! Note that the majority of this code is `unsafe`. This is due to the component columns being
//! type-erased, requiring us to infer the type from the registry and identifier. This is not taken
//! lightly, and great care has been used in auditing the unsafe code blocks here.
//!
//! [`Registry`]: crate::registry::Registry
//! [`World`]: crate::world::World
use crate::{
archetype,
component::Component,
registry::{
Null,
Registry,
},
};
use alloc::vec::Vec;
use core::{
any::{
type_name,
TypeId,
},
fmt::DebugList,
marker::PhantomData,
mem::{
drop,
size_of,
ManuallyDrop,
MaybeUninit,
},
ptr,
};
pub trait Storage {
/// Populate a [`Vec`] with component columns corresponding to the given identifier, each with
/// the requested capacity.
///
/// # Safety
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
///
/// [`Vec`]: alloc::vec::Vec
unsafe fn new_components_with_capacity<R>(
components: &mut Vec<(*mut u8, usize)>,
capacity: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Returns the size of the components indicated within the `Registry` by an identifier.
///
/// # Safety
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn size_of_components_for_identifier<R>(
identifier_iter: archetype::identifier::Iter<R>,
) -> usize
where
R: Registry;
/// Remove the component at the given index from each component column.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn remove_component_row<R>(
index: usize,
components: &[(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Remove the component at the given index from each component column, appending it to the
/// provided bit buffer.
///
/// Note that the components stored in `buffer` are unaligned, and should be read as such when
/// the components are later read out of the buffer.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// `buffer` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for writes.
/// Note that even if the combined size of components being stored is of size zero, this
/// pointer still must be non-null.
///
/// `buffer` must point to an allocated buffer large enough to hold all components identified
/// by the `identifier_iter`. In other words, it must at least be of size
/// `R::size_of_components_for_identifier(identifier_iter)`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn pop_component_row<R>(
index: usize,
buffer: *mut u8,
components: &[(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Push components from a bit buffer, together with an additional component not in the bit
/// buffer, onto the end of their corresponding component columns.
///
/// Note that the components stored in `buffer` are expected to be unaligned, being packed one
/// immediately after another, and will be read as such.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// `buffer` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads.
/// Note that even if the combined size of components being stored is of size zero, this
/// pointer still must be non-null.
///
/// `buffer` must point to an allocated buffer of packed, properly initialized components
/// corresponding with the components identified by `identifier_iter`, in the same order as
/// they are specified by the `Registry` on which this method is being called, with the
/// exception of the component corresponding to the component `C`, which must not be provided
/// in the buffer, but instead by provided using the separate `component` parameter.
///
/// `component` must be a properly initialized value when called externally. When called
/// internally, `component` must be properly initialized if the bit corresponding to `C` has
/// not yet been read out of the `identifier_iter`.
///
/// The `Registry` `R` must not contain any duplicate component types.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn push_components_from_buffer_and_component<C, R>(
buffer: *const u8,
component: MaybeUninit<C>,
components: &mut [(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
C: Component,
R: Registry;
/// Push components from a bit buffer, skipping the component `C`, onto the end of their
/// corresponding component columns.
///
/// Note that the components stored in `buffer` are expected to be unaligned, being packed one
/// immediately after another, and will be read as such.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// `buffer` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads.
/// Note that even if the combined size of components being stored is of size zero, this
/// pointer still must be non-null.
///
/// `buffer` must point to an allocated buffer of packed, properly initialized components
/// corresponding with the components identified by `identifier_iter`, in the same order as
/// they are specified by the `Registry` on which this method is being called, with an
/// additional component of type `C` in its proper place in the ordering that is not identified
/// in the `identifier_iter`.
///
/// The `Registry` `R` must not contain any duplicate component types.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn push_components_from_buffer_skipping_component<C, R>(
buffer: *const u8,
component: PhantomData<C>,
components: &mut [(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
C: Component,
R: Registry;
/// Free the allocated memory for each component column.
///
/// This converts all component columns back into `Vec<C>` for each component `C`, and then
/// drops them, allowing the memory to be freed.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn free_components<R>(
components: &[(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Attempt to free the allocated memory for each component column.
///
/// By "attempt", this method frees the component columns until there are no more component
/// columns left in `components`. This is necessary for things like deserialization, where some
/// columns may have been created, but an invalid value was attempted to be deserialized and
/// now the whole collection must be deallocated before returning an error. Column length is
/// the only thing that is not expected to be correct here; all other requirements for
/// `free_components` are still expected to be upheld.
///
/// # Safety
/// `components` must contain up to the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn try_free_components<R>(
components: &[(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Clear all components from the component columns, saving the heap allocations to be reused.
///
/// Note that this does not free the component columns. It simply removes all elements from the
/// columns.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn clear_components<R>(
components: &mut [(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Shrink the component columns to the smallest required allocation.
///
/// This isn't guaranteed to shrink to the most optimal allocation, as it is dependent on the
/// allocator. The logic here relies on the implementation of `Vec::shrink_to_fit()`.
///
/// # Safety
/// `components` must contain the same number of values as there are set bits in the
/// `identifier_iter`.
///
/// Each `(*mut u8, usize)` in `components` must be the pointer and capacity respectively of a
/// `Vec<C>` of length `length`, where `C` is the component corresponding to the set bit in
/// `identifier_iter`.
///
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
unsafe fn shrink_components_to_fit<R>(
components: &mut [(*mut u8, usize)],
length: usize,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
/// Populate a [`DebugList`] with string forms of the names of every component type identified
/// by `identifier_iter`.
///
/// This is meant to be used for debugging purposes. The string names output by this method are
/// not stable.
///
/// # Safety
/// When called externally, the `Registry` `R` provided to the method must by the same as the
/// `Registry` on which this method is being called.
///
/// When called internally, the `identifier_iter` must have the same amount of bits left as
/// there are components remaining.
///
/// [`DebugList`]: core::fmt::DebugList
unsafe fn debug_identifier<R>(
debug_list: &mut DebugList,
identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry;
}
impl Storage for Null {
unsafe fn new_components_with_capacity<R>(
_components: &mut Vec<(*mut u8, usize)>,
_capacity: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn size_of_components_for_identifier<R>(
_identifier_iter: archetype::identifier::Iter<R>,
) -> usize
where
R: Registry,
{
0
}
unsafe fn remove_component_row<R>(
_index: usize,
_components: &[(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn pop_component_row<R>(
_index: usize,
_buffer: *mut u8,
_components: &[(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn push_components_from_buffer_and_component<C, R>(
_buffer: *const u8,
_component: MaybeUninit<C>,
_components: &mut [(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
C: Component,
R: Registry,
{
}
unsafe fn push_components_from_buffer_skipping_component<C, R>(
_buffer: *const u8,
_component: PhantomData<C>,
_components: &mut [(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
C: Component,
R: Registry,
{
}
unsafe fn free_components<R>(
_components: &[(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn try_free_components<R>(
_components: &[(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn clear_components<R>(
_components: &mut [(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn shrink_components_to_fit<R>(
_components: &mut [(*mut u8, usize)],
_length: usize,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
unsafe fn debug_identifier<R>(
_debug_list: &mut DebugList,
_identifier_iter: archetype::identifier::Iter<R>,
) where
R: Registry,
{
}
}
impl<C, R> Storage for (C, R)
where
C: Component,
R: Storage,
{
unsafe fn new_components_with_capacity<R_>(
components: &mut Vec<(*mut u8, usize)>,
capacity: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let mut v = ManuallyDrop::new(Vec::<C>::with_capacity(capacity));
components.push((v.as_mut_ptr().cast::<u8>(), v.capacity()));
}
// SAFETY: One bit of `identifier_iter` has been consumed, and since `R` is one component
// smaller than `(C, R)`, `identifier_iter` has the same number of bits remaining as `R`
// has components remaining.
unsafe { R::new_components_with_capacity(components, capacity, identifier_iter) };
}
unsafe fn size_of_components_for_identifier<R_>(
mut identifier_iter: archetype::identifier::Iter<R_>,
) -> usize
where
R_: Registry,
{
(usize::from(
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() }) * size_of::<C>())
+
// SAFETY: One bit of `identifier_iter` has been consumed, and since `R` is one
// component smaller than `(C, R)`, `identifier_iter` has the same number of bits
// remaining as `R` has components remaining.
unsafe { R::size_of_components_for_identifier(identifier_iter) }
}
unsafe fn remove_component_row<R_>(
index: usize,
mut components: &[(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(0) };
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety contract
// of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
v.swap_remove(index);
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain the same number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`.
//
// If the bit was not set, then `components` is unaltered, and there are still the same
// number of elements as there are set bits in `identifier_iter`, which still make valid
// `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::remove_component_row(index, components, length, identifier_iter) };
}
unsafe fn pop_component_row<R_>(
index: usize,
mut buffer: *mut u8,
mut components: &[(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(0) };
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety contract
// of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
// SAFETY: `buffer` is valid for writes and points within an allocation that is large
// enough to store the component `C`, as guaranteed by the safety contract of this
// method.
unsafe {
ptr::write_unaligned(buffer.cast::<C>(), v.swap_remove(index));
}
buffer =
// SAFETY: Since `buffer` points within an allocation that is large enough to store
// a component of size `C`, then moving it `size_of::<C>()` bytes means the pointer
// will still be within the same allocation, or one byte past the allocated object
// if there are no more components remaining.
unsafe { buffer.add(size_of::<C>()) };
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain the same number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`. Also, `buffer` will be offset by the
// size of `C`, which means it will have enough space left in its allocation for all
// remaining components identified by `identifier_iter`, and will therefore be valid for
// writes still.
//
// If the bit was not set, then `components` is unaltered, and there are still the same
// number of elements as there are set bits in `identifier_iter`, which still make valid
// `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`. Also,
// `buffer` will remain unchanged and still point to an allocation with enough space to
// write all remaining components identified.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::pop_component_row(index, buffer, components, length, identifier_iter) };
}
unsafe fn push_components_from_buffer_and_component<C_, R_>(
mut buffer: *const u8,
mut component: MaybeUninit<C_>,
mut components: &mut [(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
C_: Component,
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(0) };
if TypeId::of::<C>() == TypeId::of::<C_>() {
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C_>::from_raw_parts(
component_column.0.cast::<C_>(),
length,
component_column.1,
)
},
);
v.push(
// SAFETY: Since each component within a registry must be unique, we can
// guarantee that we will only read `component` one time, at which point it
// be a valid properly initialized value.
unsafe { component.assume_init() },
);
// Since the component won't be read again, we can set it to an uninitialized
// value.
component = MaybeUninit::uninit();
*component_column = (v.as_mut_ptr().cast::<u8>(), v.capacity());
} else {
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
v.push(
// SAFETY: `buffer` is guaranteed by the safety contract of the method to be
// valid for reads and to point to all components identified by
// `identifier_iter` (except for the `component` parameter) in the order they
// are specified in the `Registry`. Therefore, the pointer must point to a
// valid, properly initialized value of type `C`.
unsafe { buffer.cast::<C>().read_unaligned() },
);
buffer =
// SAFETY: `buffer` is guaranteed by the safety contract of the method to point
// to a packed buffer of components corresponding to all components identified
// by `identifier_iter` within the registry, except the component `component`.
// Therefore, offsetting the buffer by `size_of::<C>()` will point it to the
// next component within the same allocation, or it will point it to one byte
// past the end of the allocation if no more components are in the buffer.
unsafe { buffer.add(size_of::<C>()) };
*component_column = (v.as_mut_ptr().cast::<u8>(), v.capacity());
}
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain the same number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`. Also, `buffer` is still guaranteed to
// hold the remaining components identified, save for the `component` parameter, whether or
// not a value was actually read from `buffer`.
//
// If the bit was not set, then `components` is unaltered, and there are still the same
// number of elements as there are set bits in `identifier_iter`, which still make valid
// `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`. Also,
// `buffer` will remain unchanged and still point to an allocation of valid components
// identified by `identier_iter`.
//
// If `component` had not been read yet, it will still be a valid value. If it has been
// read, it will no longer be valid but it will also no longer be read, since
// `identifier_iter` will not identify the same unique component type twice.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
//
// Finally, since `(C, R)` contains no duplicate components, neither does `R`.
unsafe {
R::push_components_from_buffer_and_component(
buffer,
component,
components,
length,
identifier_iter,
);
}
}
unsafe fn push_components_from_buffer_skipping_component<C_, R_>(
mut buffer: *const u8,
component: PhantomData<C_>,
mut components: &mut [(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
C_: Component,
R_: Registry,
{
if TypeId::of::<C>() == TypeId::of::<C_>() {
// Skip this component in the buffer.
buffer =
// SAFETY: The bit buffer is guaranteed to have a value of type `C` at this point
// because the components within the bit buffer are guaranteed to be ordered in the
// same order as the registry.
unsafe { buffer.add(size_of::<C>()) };
// Pop the next identifier bit. We don't need to look at it, since the component is
// being skipped anyway. We also know the bit was not set because of the safety
// contract on this method, which is why we know we don't need to pop any component
// pointer-capacity tuples from `components`.
identifier_iter.next();
} else if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(0) };
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
v.push(
// SAFETY: `buffer` is guaranteed by the safety contract of the method to be
// valid for reads and to point to all components identified by
// `identifier_iter` (except for the `component` parameter) in the order they
// are specified in the `Registry`. Therefore, the pointer must point to a
// valid, properly initialized value of type `C`.
unsafe { buffer.cast::<C>().read_unaligned() },
);
buffer =
// SAFETY: `buffer` is guaranteed by the safety contract of the method to point
// to a packed buffer of components corresponding to all components identified
// by `identifier_iter` within the registry, except the component `component`.
// Therefore, offsetting the buffer by `size_of::<C>()` will point it to the
// next component within the same allocation, or it will point it to one byte
// past the end of the allocation if no more components are in the buffer.
unsafe { buffer.add(size_of::<C>()) };
*component_column = (v.as_mut_ptr().cast::<u8>(), v.capacity());
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain the same number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`. Also, `buffer` is still guaranteed to
// hold the remaining components identified, save for the `component` parameter, whether or
// not a value was actually read from `buffer`.
//
// If the bit was not set, then `components` is unaltered, and there are still the same
// number of elements as there are set bits in `identifier_iter`, which still make valid
// `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`. Also,
// `buffer` will remain unchanged and still point to an allocation of valid components
// identified by `identier_iter`.
//
// If the bit was not set but the component was of type `C_`, then the bit buffer will have
// been offset by `size_of::<C_>()`. This fills the safety contract of the next call, as it
// guarantees the rest of the components in the buffer will be components specified in the
// identifier, which will match the registry since there are no duplicate components in the
// registry.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
//
// Finally, since `(C, R)` contains no duplicate components, neither does `R`.
unsafe {
R::push_components_from_buffer_skipping_component(
buffer,
component,
components,
length,
identifier_iter,
);
}
}
unsafe fn free_components<R_>(
mut components: &[(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(0) };
drop(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain the same number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`.
//
// If the bit was not set, then `components` is unaltered, and there are still the same
// number of elements as there are set bits in `identifier_iter`, which still make valid
// `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::free_components(components, length, identifier_iter) };
}
unsafe fn try_free_components<R_>(
mut components: &[(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let Some(component_column) = components.get(0) else {
return;
};
drop(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
components =
// SAFETY: Since we didn't return on the `get(0)` call above, we know `components`
// has at least one element.
unsafe {
components.get_unchecked(1..)
};
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain up to the number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`.
//
// If the bit was not set, then `components` is unaltered, and there are still up to the
// same number of elements as there are set bits in `identifier_iter`, which still make
// valid `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::try_free_components(components, length, identifier_iter) };
}
unsafe fn clear_components<R_>(
mut components: &mut [(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(0) };
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
v.clear();
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain up to the number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`.
//
// If the bit was not set, then `components` is unaltered, and there are still up to the
// same number of elements as there are set bits in `identifier_iter`, which still make
// valid `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::clear_components(components, length, identifier_iter) };
}
unsafe fn shrink_components_to_fit<R_>(
mut components: &mut [(*mut u8, usize)],
length: usize,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
let component_column =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(0) };
let mut v = ManuallyDrop::new(
// SAFETY: The pointer, capacity, and length are guaranteed by the safety
// contract of this method to define a valid `Vec<C>`.
unsafe {
Vec::<C>::from_raw_parts(
component_column.0.cast::<C>(),
length,
component_column.1,
)
},
);
v.shrink_to_fit();
*component_column = (v.as_mut_ptr().cast::<u8>(), v.capacity());
components =
// SAFETY: `components` is guaranteed to have the same number of values as there
// set bits in `identifier_iter`. Since a bit must have been set to enter this
// block, there must be at least one component column.
unsafe { components.get_unchecked_mut(1..) };
}
// SAFETY: At this point, one bit of `identifier_iter` has been consumed. There are two
// possibilities here: either the bit was set or it was not.
//
// If the bit was set, then the `components` slice will no longer include the first value,
// which means the slice will still contain up to the number of pointer and capacity tuples
// as there are set bits in `identifier_iter`. Additionally, since the first value was
// removed from the slice, which corresponded to the component identified by the consumed
// bit, all remaining component values will still correspond to valid `Vec<C>`s identified
// by the remaining set bits in `identifier_iter`.
//
// If the bit was not set, then `components` is unaltered, and there are still up to the
// same number of elements as there are set bits in `identifier_iter`, which still make
// valid `Vec<C>`s for each `C` identified by the remaining set bits in `identifier_iter`.
//
// Furthermore, regardless of whether the bit was set or not, `R` is one component smaller
// than `(C, R)`, and since `identifier_iter` has had one bit consumed, it still has the
// same number of bits remaining as `R` has components remaining.
unsafe { R::shrink_components_to_fit(components, length, identifier_iter) }
}
unsafe fn debug_identifier<R_>(
debug_list: &mut DebugList,
mut identifier_iter: archetype::identifier::Iter<R_>,
) where
R_: Registry,
{
if
// SAFETY: `identifier_iter` is guaranteed by the safety contract of this method to
// return a value for every component within the registry.
unsafe { identifier_iter.next().unwrap_unchecked() } {
debug_list.entry(&type_name::<C>());
}
// SAFETY: One bit of `identifier_iter` has been consumed, and since `R` is one component
// smaller than `(C, R)`, `identifier_iter` has the same number of bits remaining as `R`
// has components remaining.
unsafe { R::debug_identifier(debug_list, identifier_iter) };
}
}
#[cfg(test)]
mod tests {
use super::Storage;
use crate::{
archetype::Identifier,
Registry,
};
use alloc::{
vec,
vec::Vec,
};
use core::{
marker::PhantomData,
mem::{
size_of,
ManuallyDrop,
MaybeUninit,
},
};
#[test]
fn new_components_with_capacity_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let mut components = Vec::new();
unsafe { Registry::new_components_with_capacity(&mut components, 100, identifier.iter()) };
assert!(components.is_empty());
}
#[test]
fn new_components_with_capacity_all_components() {
struct A(usize);
struct B(usize);
struct C(usize);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
const CAPACITY: usize = 100;
let mut components = Vec::new();
unsafe {
Registry::new_components_with_capacity(&mut components, CAPACITY, identifier.iter())
};
assert_eq!(components.get(0).unwrap().1, CAPACITY);
assert_eq!(components.get(1).unwrap().1, CAPACITY);
assert_eq!(components.get(2).unwrap().1, CAPACITY);
// Free components to avoid leaking memory.
unsafe { Registry::free_components(&mut components, 0, identifier.iter()) }
}
#[test]
fn new_components_with_capacity_some_components() {
struct A(usize);
struct B(usize);
struct C(usize);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
const CAPACITY: usize = 100;
let mut components = Vec::new();
unsafe {
Registry::new_components_with_capacity(&mut components, CAPACITY, identifier.iter())
};
assert_eq!(components.get(0).unwrap().1, CAPACITY);
assert_eq!(components.get(1).unwrap().1, CAPACITY);
// Free components to avoid leaking memory.
unsafe { Registry::free_components(&mut components, 0, identifier.iter()) }
}
#[test]
fn new_components_with_capacity_no_components() {
struct A(usize);
struct B(usize);
struct C(usize);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![0]) };
const CAPACITY: usize = 100;
let mut components = Vec::new();
unsafe {
Registry::new_components_with_capacity(&mut components, CAPACITY, identifier.iter())
};
assert!(components.is_empty());
}
#[test]
fn size_of_components_for_identifier_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
assert_eq!(size, 0);
}
#[test]
fn size_of_components_for_identifier_all_components() {
struct A;
struct B(f32);
struct C(u8);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
assert_eq!(size, 5);
}
#[test]
fn size_of_components_for_identifier_some_components() {
struct A;
struct B(f32);
struct C(u8);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
assert_eq!(size, 1);
}
#[test]
fn size_of_components_for_empty_identifier() {
struct A;
struct B(f32);
struct C(u8);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![0]) };
let size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
assert_eq!(size, 0);
}
#[test]
fn remove_component_row_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
// `components` must be empty because there are no components in the registry.
let mut components = Vec::new();
unsafe { Registry::remove_component_row(0, &mut components, 1, identifier.iter()) };
assert!(components.is_empty());
}
#[test]
fn remove_component_row_all_components() {
#[derive(Debug, Eq, PartialEq)]
struct A(usize);
#[derive(Debug, Eq, PartialEq)]
struct B(bool);
#[derive(Debug, Eq, PartialEq)]
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![B(false), B(true), B(true)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::remove_component_row(0, &mut components, 3, identifier.iter()) };
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
2,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
2,
components.get(1).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(2).unwrap().0.cast::<C>(),
2,
components.get(2).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(2), A(1)]);
assert_eq!(new_b_column, vec![B(true), B(true)]);
assert_eq!(new_c_column, vec![C, C]);
}
#[test]
fn remove_component_row_some_components() {
#[derive(Debug, Eq, PartialEq)]
struct A(usize);
#[derive(Debug, Eq, PartialEq)]
struct B(bool);
#[derive(Debug, Eq, PartialEq)]
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::remove_component_row(0, &mut components, 3, identifier.iter()) };
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
2,
components.get(0).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<C>(),
2,
components.get(1).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(2), A(1)]);
assert_eq!(new_c_column, vec![C, C]);
}
#[test]
fn remove_component_row_no_components() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![0]) };
// `components` must be empty because there are no components in the identifier.
let mut components = Vec::new();
unsafe { Registry::remove_component_row(0, &mut components, 1, identifier.iter()) };
assert!(components.is_empty());
}
#[test]
#[should_panic]
fn remove_component_row_out_of_bounds() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = vec![A(0), A(1), A(2)];
let mut b_column = vec![B(false), B(true), B(true)];
let mut c_column = vec![C, C, C];
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::remove_component_row(3, &mut components, 3, identifier.iter()) };
}
#[test]
fn pop_component_row_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
// `components` must be empty because there are no components in the registry.
let mut components = Vec::new();
let buffer_size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
let mut buffer = Vec::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
unsafe {
Registry::pop_component_row(
0,
buffer.as_mut_ptr(),
&mut components,
1,
identifier.iter(),
)
};
assert!(components.is_empty());
assert!(buffer.is_empty());
}
#[test]
fn pop_component_row_all_components() {
#[derive(Debug, Eq, PartialEq)]
struct A(usize);
#[derive(Debug, Eq, PartialEq)]
struct B(bool);
#[derive(Debug, Eq, PartialEq)]
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![B(false), B(true), B(true)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
let buffer_size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
let mut buffer = Vec::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
unsafe {
Registry::pop_component_row(
0,
buffer.as_mut_ptr(),
&mut components,
3,
identifier.iter(),
)
};
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
2,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
2,
components.get(1).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(2).unwrap().0.cast::<C>(),
2,
components.get(2).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(2), A(1)]);
assert_eq!(new_b_column, vec![B(true), B(true)]);
assert_eq!(new_c_column, vec![C, C]);
let mut buffer_ptr = buffer.as_ptr();
let popped_a = unsafe { buffer_ptr.cast::<A>().read_unaligned() };
buffer_ptr = unsafe { buffer_ptr.add(size_of::<A>()) };
let popped_b = unsafe { buffer_ptr.cast::<B>().read_unaligned() };
buffer_ptr = unsafe { buffer_ptr.add(size_of::<B>()) };
let popped_c = unsafe { buffer_ptr.cast::<C>().read_unaligned() };
assert_eq!(popped_a, A(0));
assert_eq!(popped_b, B(false));
assert_eq!(popped_c, C);
}
#[test]
fn pop_component_row_some_components() {
#[derive(Debug, Eq, PartialEq)]
struct A(usize);
#[derive(Debug, Eq, PartialEq)]
struct B(bool);
#[derive(Debug, Eq, PartialEq)]
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
let buffer_size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
let mut buffer = Vec::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
unsafe {
Registry::pop_component_row(
0,
buffer.as_mut_ptr(),
&mut components,
3,
identifier.iter(),
)
};
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
2,
components.get(0).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<C>(),
2,
components.get(1).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(2), A(1)]);
assert_eq!(new_c_column, vec![C, C]);
let mut buffer_ptr = buffer.as_ptr();
let popped_a = unsafe { buffer_ptr.cast::<A>().read_unaligned() };
buffer_ptr = unsafe { buffer_ptr.add(size_of::<A>()) };
let popped_c = unsafe { buffer_ptr.cast::<C>().read_unaligned() };
assert_eq!(popped_a, A(0));
assert_eq!(popped_c, C);
}
#[test]
fn pop_component_row_no_components() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![0]) };
// `components` must be empty because there are no components in the identifier.
let mut components = Vec::new();
let buffer_size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
let mut buffer = Vec::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
unsafe {
Registry::pop_component_row(
0,
buffer.as_mut_ptr(),
&mut components,
1,
identifier.iter(),
)
};
assert!(components.is_empty());
assert!(buffer.is_empty());
}
#[test]
#[should_panic]
fn pop_component_row_out_of_bounds() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = vec![A(0), A(1), A(2)];
let mut b_column = vec![B(false), B(true), B(true)];
let mut c_column = vec![C, C, C];
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
let buffer_size = unsafe { Registry::size_of_components_for_identifier(identifier.iter()) };
let mut buffer = Vec::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
unsafe {
Registry::pop_component_row(
3,
buffer.as_mut_ptr(),
&mut components,
3,
identifier.iter(),
)
};
}
#[test]
fn push_components_from_buffer_and_component() {
#[derive(Debug, PartialEq)]
struct A(usize);
#[derive(Debug, PartialEq)]
struct B(bool);
#[derive(Debug, PartialEq)]
struct C(f32);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![B(false), B(true), B(true)]);
let mut c_column = ManuallyDrop::new(vec![C(1.0), C(1.1), C(1.2)]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
// Initialize input buffer.
let input_identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let buffer_size =
unsafe { Registry::size_of_components_for_identifier(input_identifier.iter()) };
let mut buffer = Vec::<u8>::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
let buffer_ptr = buffer.as_mut_ptr();
unsafe { buffer_ptr.cast::<A>().write_unaligned(A(3)) };
unsafe {
buffer_ptr
.add(size_of::<A>())
.cast::<C>()
.write_unaligned(C(1.3))
};
unsafe {
Registry::push_components_from_buffer_and_component(
buffer_ptr,
MaybeUninit::new(B(false)),
&mut components,
3,
identifier.iter(),
)
};
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
4,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
4,
components.get(1).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(2).unwrap().0.cast::<C>(),
4,
components.get(2).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(0), A(1), A(2), A(3)]);
assert_eq!(new_b_column, vec![B(false), B(true), B(true), B(false)]);
assert_eq!(new_c_column, vec![C(1.0), C(1.1), C(1.2), C(1.3)]);
}
#[test]
fn push_components_from_buffer_skipping_component() {
#[derive(Debug, PartialEq)]
struct A(usize);
#[derive(Debug, PartialEq)]
struct B(bool);
#[derive(Debug, PartialEq)]
struct C(f32);
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut c_column = ManuallyDrop::new(vec![C(1.0), C(1.1), C(1.2)]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
// Initialize input buffer.
let input_identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let buffer_size =
unsafe { Registry::size_of_components_for_identifier(input_identifier.iter()) };
let mut buffer = Vec::<u8>::with_capacity(buffer_size);
unsafe { buffer.set_len(buffer_size) };
let buffer_ptr = buffer.as_mut_ptr();
unsafe { buffer_ptr.cast::<A>().write_unaligned(A(3)) };
unsafe {
buffer_ptr
.add(size_of::<A>())
.cast::<B>()
.write_unaligned(B(false))
};
unsafe {
buffer_ptr
.add(size_of::<A>())
.add(size_of::<B>())
.cast::<C>()
.write_unaligned(C(1.3))
};
unsafe {
Registry::push_components_from_buffer_skipping_component(
buffer_ptr,
PhantomData::<B>,
&mut components,
3,
identifier.iter(),
)
};
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
4,
components.get(0).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<C>(),
4,
components.get(1).unwrap().1,
)
};
assert_eq!(new_a_column, vec![A(0), A(1), A(2), A(3)]);
assert_eq!(new_c_column, vec![C(1.0), C(1.1), C(1.2), C(1.3)]);
}
#[test]
fn free_components_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let mut components = Vec::new();
unsafe { Registry::free_components(&mut components, 0, identifier.iter()) };
}
#[test]
fn free_components() {
static mut DROP_COUNT: usize = 0;
struct A;
impl Drop for A {
fn drop(&mut self) {
unsafe { DROP_COUNT += 1 };
}
}
type Registry = Registry!(A);
let identifier = unsafe { Identifier::<Registry>::new(vec![1]) };
let mut a_column = ManuallyDrop::new(vec![A]);
let mut components = vec![(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity())];
unsafe { Registry::free_components(&mut components, 1, identifier.iter()) };
assert_eq!(unsafe { DROP_COUNT }, 1);
}
#[test]
fn try_free_components_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let mut components = Vec::new();
unsafe { Registry::try_free_components(&mut components, 0, identifier.iter()) };
}
#[test]
fn try_free_components() {
static mut DROP_COUNT: usize = 0;
struct A;
impl Drop for A {
fn drop(&mut self) {
unsafe { DROP_COUNT += 1 };
}
}
type Registry = Registry!(A);
let identifier = unsafe { Identifier::<Registry>::new(vec![1]) };
let mut a_column = ManuallyDrop::new(vec![A]);
let mut components = vec![(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity())];
unsafe { Registry::try_free_components(&mut components, 1, identifier.iter()) };
assert_eq!(unsafe { DROP_COUNT }, 1);
}
#[test]
fn try_free_components_incomplete() {
static mut DROP_COUNT: usize = 0;
struct A;
impl Drop for A {
fn drop(&mut self) {
unsafe { DROP_COUNT += 1 };
}
}
struct B;
type Registry = Registry!(A, B);
let identifier = unsafe { Identifier::<Registry>::new(vec![3]) };
let mut a_column = ManuallyDrop::new(vec![A]);
let mut components = vec![(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity())];
unsafe { Registry::try_free_components(&mut components, 1, identifier.iter()) };
assert_eq!(unsafe { DROP_COUNT }, 1);
}
#[test]
fn clear_components_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let mut components = Vec::new();
unsafe { Registry::clear_components(&mut components, 0, identifier.iter()) };
assert!(components.is_empty());
}
#[test]
fn clear_components_all() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![B(false), B(true), B(true)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::clear_components(&mut components, 3, identifier.iter()) };
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
0,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
0,
components.get(1).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(2).unwrap().0.cast::<C>(),
0,
components.get(2).unwrap().1,
)
};
assert!(new_a_column.is_empty());
assert!(new_b_column.is_empty());
assert!(new_c_column.is_empty());
}
#[test]
fn clear_components_some() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![5]) };
let mut a_column = ManuallyDrop::new(vec![A(0), A(1), A(2)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::clear_components(&mut components, 3, identifier.iter()) };
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
0,
components.get(0).unwrap().1,
)
};
let new_c_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<C>(),
0,
components.get(1).unwrap().1,
)
};
assert!(new_a_column.is_empty());
assert!(new_c_column.is_empty());
}
#[test]
fn shrink_components_to_fit_empty_registry() {
type Registry = Registry!();
let identifier = unsafe { Identifier::<Registry>::new(Vec::new()) };
let mut components = Vec::new();
unsafe { Registry::shrink_components_to_fit(&mut components, 0, identifier.iter()) };
assert!(components.is_empty());
}
#[test]
fn shrink_components_to_fit_all() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![7]) };
let mut a_column = ManuallyDrop::new(vec![
A(0),
A(1),
A(2),
A(10),
A(10),
A(10),
A(10),
A(10),
A(10),
A(10),
]);
a_column.clear();
a_column.extend(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![
B(false),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
]);
b_column.clear();
b_column.extend(vec![B(false), B(true), B(true)]);
let mut c_column = ManuallyDrop::new(vec![C, C, C, C, C, C, C, C, C, C]);
c_column.clear();
c_column.extend(vec![C, C, C]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
(c_column.as_mut_ptr().cast::<u8>(), c_column.capacity()),
];
unsafe { Registry::shrink_components_to_fit(&mut components, 3, identifier.iter()) };
// Only check columns A and B, because C is zero-sized.
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
0,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
0,
components.get(1).unwrap().1,
)
};
assert_eq!(new_a_column.capacity(), 3);
assert_eq!(new_b_column.capacity(), 3);
}
#[test]
fn shrink_components_to_fit_some() {
struct A(usize);
struct B(bool);
struct C;
type Registry = Registry!(A, B, C);
let identifier = unsafe { Identifier::<Registry>::new(vec![3]) };
let mut a_column = ManuallyDrop::new(vec![
A(0),
A(1),
A(2),
A(10),
A(10),
A(10),
A(10),
A(10),
A(10),
A(10),
]);
a_column.clear();
a_column.extend(vec![A(0), A(1), A(2)]);
let mut b_column = ManuallyDrop::new(vec![
B(false),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
B(true),
]);
b_column.clear();
b_column.extend(vec![B(false), B(true), B(true)]);
let mut components = vec![
(a_column.as_mut_ptr().cast::<u8>(), a_column.capacity()),
(b_column.as_mut_ptr().cast::<u8>(), b_column.capacity()),
];
unsafe { Registry::shrink_components_to_fit(&mut components, 3, identifier.iter()) };
let new_a_column = unsafe {
Vec::from_raw_parts(
components.get(0).unwrap().0.cast::<A>(),
0,
components.get(0).unwrap().1,
)
};
let new_b_column = unsafe {
Vec::from_raw_parts(
components.get(1).unwrap().0.cast::<B>(),
0,
components.get(1).unwrap().1,
)
};
assert_eq!(new_a_column.capacity(), 3);
assert_eq!(new_b_column.capacity(), 3);
}
}