mod adapter;
mod group;
mod list;
mod map;
mod storage;
use core::{
alloc::{AllocError, Layout},
any::Any,
cell::{Cell, UnsafeCell},
fmt,
hash::Hash,
mem::MaybeUninit,
ops::{Deref, DerefMut},
ptr::NonNull,
};
pub use self::{
group::EntityGroup,
list::{
EntityList, EntityListCursor, EntityListCursorMut, EntityListItem, EntityListIter,
MaybeDefaultEntityListIter,
},
map::{
EntityMap, EntityMapCursor, EntityMapCursorMut, EntityMapItem, EntityMapIter,
EntityWithKey, MaybeDefaultEntityMapIter,
},
storage::{EntityRange, EntityRangeMut, EntityStorage},
};
use crate::any::*;
pub trait Entity: Any {}
pub trait EntityParent<Child: ?Sized>: Entity {
fn offset() -> usize;
}
pub trait EntityWithParent: Entity {
type Parent: EntityParent<Self>;
}
pub trait EntityWithId: Entity {
type Id: EntityId;
fn id(&self) -> Self::Id;
}
pub trait StorableEntity {
fn index(&self) -> usize;
unsafe fn set_index(&mut self, index: usize);
#[inline(always)]
fn unlink(&mut self) {}
}
pub trait EntityId: Copy + Clone + PartialEq + Eq + PartialOrd + Ord + Hash + fmt::Display {
fn as_usize(&self) -> usize;
}
#[non_exhaustive]
pub struct AliasingViolationError {
#[cfg(debug_assertions)]
location: &'static core::panic::Location<'static>,
kind: AliasingViolationKind,
}
#[derive(Debug)]
enum AliasingViolationKind {
Immutable,
Mutable,
}
impl fmt::Display for AliasingViolationKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Immutable => f.write_str("already mutably borrowed"),
Self::Mutable => f.write_str("already borrowed"),
}
}
}
impl fmt::Debug for AliasingViolationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("AliasingViolationError");
builder.field("kind", &self.kind);
#[cfg(debug_assertions)]
builder.field("location", &self.location);
builder.finish()
}
}
impl fmt::Display for AliasingViolationError {
#[cfg(debug_assertions)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} in file '{}' at line {} and column {}",
&self.kind,
self.location.file(),
self.location.line(),
self.location.column()
)
}
#[cfg(not(debug_assertions))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.kind)
}
}
pub type UnsafeEntityRef<T> = RawEntityRef<T, ()>;
pub type UnsafeIntrusiveEntityRef<T> = RawEntityRef<T, list::IntrusiveLink>;
pub type UnsafeIntrusiveMapEntityRef<T> = RawEntityRef<T, map::IntrusiveLink>;
pub struct RawEntityRef<T: ?Sized, Metadata = ()> {
inner: NonNull<RawEntityMetadata<T, Metadata>>,
}
impl<T: ?Sized, Metadata> Copy for RawEntityRef<T, Metadata> {}
impl<T: ?Sized, Metadata> Clone for RawEntityRef<T, Metadata> {
fn clone(&self) -> Self {
*self
}
}
impl<T, Metadata> RawEntityRef<T, Metadata> {
pub const fn dangling() -> Self {
Self {
inner: NonNull::dangling(),
}
}
}
impl<T: ?Sized, Metadata> RawEntityRef<T, Metadata> {
#[inline]
unsafe fn from_inner(inner: NonNull<RawEntityMetadata<T, Metadata>>) -> Self {
Self { inner }
}
#[inline]
unsafe fn from_ptr(ptr: *mut RawEntityMetadata<T, Metadata>) -> Self {
debug_assert!(!ptr.is_null());
unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
}
#[inline]
fn into_inner(this: Self) -> NonNull<RawEntityMetadata<T, Metadata>> {
this.inner
}
}
impl<T: 'static, Metadata: 'static> RawEntityRef<T, Metadata> {
pub fn new_with_metadata(value: T, metadata: Metadata, arena: &blink_alloc::Blink) -> Self {
unsafe {
Self::from_inner(NonNull::new_unchecked(
arena.put(RawEntityMetadata::new(value, metadata)),
))
}
}
pub fn new_uninit_with_metadata(
metadata: Metadata,
arena: &blink_alloc::Blink,
) -> RawEntityRef<MaybeUninit<T>, Metadata> {
unsafe {
RawEntityRef::from_ptr(RawEntityRef::allocate_for_layout(
metadata,
Layout::new::<T>(),
|layout| arena.allocator().allocate(layout).map_err(|_| AllocError),
<*mut u8>::cast,
))
}
}
}
impl<T: 'static> RawEntityRef<T, ()> {
pub fn new(value: T, arena: &blink_alloc::Blink) -> Self {
RawEntityRef::new_with_metadata(value, (), arena)
}
pub fn new_uninit(arena: &blink_alloc::Blink) -> RawEntityRef<MaybeUninit<T>, ()> {
RawEntityRef::new_uninit_with_metadata((), arena)
}
}
impl<T, Metadata> RawEntityRef<MaybeUninit<T>, Metadata> {
#[inline]
pub unsafe fn assume_init(self) -> RawEntityRef<T, Metadata> {
let ptr = Self::into_inner(self);
unsafe { RawEntityRef::from_inner(ptr.cast()) }
}
}
impl<T: ?Sized, Metadata> RawEntityRef<T, Metadata> {
pub fn into_raw(this: Self) -> *const T {
Self::as_ptr(&this)
}
pub fn as_ptr(this: &Self) -> *const T {
let ptr: *mut RawEntityMetadata<T, Metadata> = NonNull::as_ptr(this.inner);
let ptr = unsafe { core::ptr::addr_of_mut!((*ptr).entity.cell) };
UnsafeCell::raw_get(ptr).cast_const()
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
let offset = unsafe { RawEntityMetadata::<T, Metadata>::data_offset(ptr) };
let entity_ptr = unsafe { ptr.byte_sub(offset) as *mut RawEntityMetadata<T, Metadata> };
unsafe { Self::from_ptr(entity_ptr) }
}
#[track_caller]
pub fn borrow<'a, 'b: 'a>(&'a self) -> EntityRef<'b, T> {
let ptr: *mut RawEntityMetadata<T, Metadata> = NonNull::as_ptr(self.inner);
let borrow = unsafe { (*core::ptr::addr_of!((*ptr).entity)).borrow() };
let value = unsafe { NonNull::new_unchecked(Self::as_ptr(self).cast_mut()) };
EntityRef::from_raw_parts(value, borrow.into_borrow_ref())
}
#[track_caller]
pub fn borrow_mut<'a, 'b: 'a>(&'a mut self) -> EntityMut<'b, T> {
let ptr: *mut RawEntityMetadata<T, Metadata> = NonNull::as_ptr(self.inner);
let borrow = unsafe { (*core::ptr::addr_of!((*ptr).entity)).borrow_mut() };
let value = unsafe { NonNull::new_unchecked(Self::as_ptr(self).cast_mut()) };
EntityMut::from_raw_parts(value, borrow.into_borrow_ref_mut())
}
pub fn try_borrow_mut<'a, 'b: 'a>(&'a mut self) -> Option<EntityMut<'b, T>> {
let ptr: *mut RawEntityMetadata<T, Metadata> = NonNull::as_ptr(self.inner);
unsafe { (*core::ptr::addr_of!((*ptr).entity)).try_borrow_mut().ok() }.map(|borrow| {
let value = unsafe { NonNull::new_unchecked(Self::as_ptr(self).cast_mut()) };
EntityMut::from_raw_parts(value, borrow.into_borrow_ref_mut())
})
}
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
core::ptr::addr_eq(this.inner.as_ptr(), other.inner.as_ptr())
}
unsafe fn allocate_for_layout<F, F2>(
metadata: Metadata,
value_layout: Layout,
allocate: F,
mem_to_metadata: F2,
) -> *mut RawEntityMetadata<T, Metadata>
where
F: FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
F2: FnOnce(*mut u8) -> *mut RawEntityMetadata<T, Metadata>,
{
use alloc::alloc::handle_alloc_error;
let layout = raw_entity_metadata_layout_for_value_layout::<Metadata>(value_layout);
unsafe {
RawEntityRef::try_allocate_for_layout(metadata, value_layout, allocate, mem_to_metadata)
.unwrap_or_else(|_| handle_alloc_error(layout))
}
}
#[inline]
unsafe fn try_allocate_for_layout<F, F2>(
metadata: Metadata,
value_layout: Layout,
allocate: F,
mem_to_metadata: F2,
) -> Result<*mut RawEntityMetadata<T, Metadata>, AllocError>
where
F: FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
F2: FnOnce(*mut u8) -> *mut RawEntityMetadata<T, Metadata>,
{
let layout = raw_entity_metadata_layout_for_value_layout::<Metadata>(value_layout);
let ptr = allocate(layout)?;
let inner = mem_to_metadata(ptr.as_non_null_ptr().as_ptr());
unsafe {
debug_assert_eq!(Layout::for_value_raw(inner), layout);
core::ptr::addr_of_mut!((*inner).metadata).write(metadata);
core::ptr::addr_of_mut!((*inner).entity.borrow).write(Cell::new(BorrowFlag::UNUSED));
#[cfg(debug_assertions)]
core::ptr::addr_of_mut!((*inner).entity.borrowed_at).write(Cell::new(None));
}
Ok(inner)
}
}
impl<From: ?Sized, Metadata: 'static> RawEntityRef<From, Metadata> {
#[inline(always)]
pub(crate) unsafe fn cast_unchecked<To>(self) -> RawEntityRef<To, Metadata>
where
To: Sized,
{
unsafe { RawEntityRef::from_inner(self.inner.cast()) }
}
#[inline(always)]
pub(crate) unsafe fn cast_unsized_unchecked<To>(
self,
metadata: <To as core::ptr::Pointee>::Metadata,
) -> RawEntityRef<To, Metadata>
where
To: ?Sized + core::ptr::Pointee,
{
let inner = core::ptr::from_raw_parts_mut(self.inner.as_ptr().cast::<()>(), metadata);
unsafe { RawEntityRef::from_ptr(inner) }
}
#[inline]
pub fn upcast<To>(self) -> RawEntityRef<To, Metadata>
where
To: ?Sized,
From: core::marker::Unsize<To> + AsAny + 'static,
{
unsafe { RawEntityRef::<To, Metadata>::from_inner(self.inner) }
}
}
impl<T: crate::Op> RawEntityRef<T, list::IntrusiveLink> {
pub fn as_operation_ref(self) -> crate::OperationRef {
unsafe {
let ptr = Self::into_raw(self);
crate::OperationRef::from_raw(ptr.cast())
}
}
}
impl<T: crate::Attribute> RawEntityRef<T, list::IntrusiveLink> {
#[inline(always)]
pub fn as_attribute_ref(self) -> crate::AttributeRef {
self.upcast()
}
}
impl<T, U, Metadata> core::ops::CoerceUnsized<RawEntityRef<U, Metadata>>
for RawEntityRef<T, Metadata>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
{
}
impl<T: ?Sized, Metadata> Eq for RawEntityRef<T, Metadata> {}
impl<T: ?Sized, Metadata> PartialEq for RawEntityRef<T, Metadata> {
#[inline]
default fn eq(&self, other: &Self) -> bool {
Self::ptr_eq(self, other)
}
}
impl<T: ?Sized + EntityWithId, Metadata> PartialOrd for RawEntityRef<T, Metadata> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized + EntityWithId, Metadata> Ord for RawEntityRef<T, Metadata> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.borrow().id().cmp(&other.borrow().id())
}
}
impl<T: ?Sized, Metadata> core::hash::Hash for RawEntityRef<T, Metadata> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.inner.as_ptr().addr().hash(state);
}
}
impl<T: ?Sized, Metadata> fmt::Pointer for RawEntityRef<T, Metadata> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&Self::as_ptr(self), f)
}
}
impl<T: ?Sized + fmt::Display, Metadata> fmt::Display for RawEntityRef<T, Metadata> {
#[inline]
default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.borrow())
}
}
impl<T: ?Sized + fmt::Display + EntityWithId, Metadata> fmt::Display for RawEntityRef<T, Metadata> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.borrow().id())
}
}
impl<T: ?Sized + fmt::Debug, Metadata> fmt::Debug for RawEntityRef<T, Metadata> {
#[inline]
default fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.borrow(), f)
}
}
impl<T: ?Sized + fmt::Debug + EntityWithId, Metadata> fmt::Debug for RawEntityRef<T, Metadata> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.borrow().id())
}
}
impl<T: ?Sized + crate::formatter::PrettyPrint, Metadata> crate::formatter::PrettyPrint
for RawEntityRef<T, Metadata>
{
#[inline]
fn render(&self) -> crate::formatter::Document {
self.borrow().render()
}
}
impl<T: ?Sized + StorableEntity, Metadata> StorableEntity for RawEntityRef<T, Metadata> {
#[inline]
fn index(&self) -> usize {
self.borrow().index()
}
#[inline]
unsafe fn set_index(&mut self, index: usize) {
unsafe {
self.borrow_mut().set_index(index);
}
}
#[inline]
fn unlink(&mut self) {
self.borrow_mut().unlink()
}
}
impl<T: ?Sized + crate::Spanned, Metadata> crate::Spanned for RawEntityRef<T, Metadata> {
#[inline]
fn span(&self) -> crate::SourceSpan {
self.borrow().span()
}
}
pub struct EntityRef<'b, T: ?Sized + 'b> {
value: NonNull<T>,
borrow: BorrowRef<'b>,
}
impl<T: ?Sized> AsRef<T> for EntityRef<'_, T> {
default fn as_ref(&self) -> &T {
unsafe { self.value.as_ref() }
}
}
impl<T: super::Op> AsRef<super::Operation> for EntityRef<'_, T> {
fn as_ref(&self) -> &super::Operation {
unsafe { self.value.as_ref().as_operation() }
}
}
impl<T: ?Sized> core::ops::Deref for EntityRef<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.value.as_ref() }
}
}
impl<'b, T: ?Sized> EntityRef<'b, T> {
#[inline]
pub fn map<U: ?Sized, F>(orig: Self, f: F) -> EntityRef<'b, U>
where
F: FnOnce(&T) -> &U,
{
EntityRef {
value: NonNull::from(f(&*orig)),
borrow: orig.borrow,
}
}
pub fn project<'to, 'from: 'to, To, F>(
orig: EntityRef<'from, T>,
f: F,
) -> EntityProjection<'from, To>
where
F: FnOnce(&'to T) -> To,
To: 'to,
{
EntityProjection {
value: f(unsafe { orig.value.as_ref() }),
borrow: orig.borrow,
}
}
pub fn into_entity_mut(self) -> Result<EntityMut<'b, T>, Self> {
let value = self.value;
match self.borrow.try_into_mut() {
Ok(borrow) => Ok(EntityMut {
value,
borrow,
_marker: core::marker::PhantomData,
}),
Err(borrow) => Err(Self { value, borrow }),
}
}
pub fn into_borrow_ref(self) -> BorrowRef<'b> {
self.borrow
}
pub fn from_raw_parts(value: NonNull<T>, borrow: BorrowRef<'b>) -> Self {
Self { value, borrow }
}
}
impl<T: crate::Attribute> EntityRef<'_, T> {
pub fn as_attribute_ref(&self) -> crate::AttributeRef {
unsafe { RawEntityRef::<T, list::IntrusiveLink>::from_raw(self.value.as_ptr()) }
.as_attribute_ref()
}
}
impl EntityRef<'_, dyn crate::Attribute> {
pub fn as_attribute_ref(&self) -> crate::AttributeRef {
unsafe { crate::AttributeRef::from_raw(self.value.as_ptr()) }
}
}
impl<'b, T, U> core::ops::CoerceUnsized<EntityRef<'b, U>> for EntityRef<'b, T>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
{
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for EntityRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for EntityRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized + crate::formatter::PrettyPrint> crate::formatter::PrettyPrint for EntityRef<'_, T> {
#[inline]
fn render(&self) -> crate::formatter::Document {
(**self).render()
}
}
impl<T: ?Sized + Eq> Eq for EntityRef<'_, T> {}
impl<T: ?Sized + PartialEq> PartialEq for EntityRef<'_, T> {
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: ?Sized + PartialOrd> PartialOrd for EntityRef<'_, T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
fn ge(&self, other: &Self) -> bool {
**self >= **other
}
fn gt(&self, other: &Self) -> bool {
**self > **other
}
fn le(&self, other: &Self) -> bool {
**self <= **other
}
fn lt(&self, other: &Self) -> bool {
**self < **other
}
}
impl<T: ?Sized + Ord> Ord for EntityRef<'_, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + Hash> Hash for EntityRef<'_, T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
pub struct EntityMut<'b, T: ?Sized> {
value: NonNull<T>,
#[allow(unused)]
borrow: BorrowRefMut<'b>,
_marker: core::marker::PhantomData<&'b mut T>,
}
impl<'b, T: ?Sized> EntityMut<'b, T> {
#[inline]
pub fn map<U: ?Sized, F>(mut orig: Self, f: F) -> EntityMut<'b, U>
where
F: FnOnce(&mut T) -> &mut U,
{
let value = NonNull::from(f(&mut *orig));
EntityMut {
value,
borrow: orig.borrow,
_marker: core::marker::PhantomData,
}
}
pub fn project<'to, 'from: 'to, To, F>(
mut orig: EntityMut<'from, T>,
f: F,
) -> EntityProjectionMut<'from, To>
where
F: FnOnce(&'to mut T) -> To,
To: 'to,
{
EntityProjectionMut {
value: f(unsafe { orig.value.as_mut() }),
borrow: orig.borrow,
}
}
#[inline]
pub fn map_split<U: ?Sized, V: ?Sized, F>(
mut orig: Self,
f: F,
) -> (EntityMut<'b, U>, EntityMut<'b, V>)
where
F: FnOnce(&mut T) -> (&mut U, &mut V),
{
let borrow = orig.borrow.clone();
let (a, b) = f(&mut *orig);
(
EntityMut {
value: NonNull::from(a),
borrow,
_marker: core::marker::PhantomData,
},
EntityMut {
value: NonNull::from(b),
borrow: orig.borrow,
_marker: core::marker::PhantomData,
},
)
}
pub fn into_entity_ref(self) -> EntityRef<'b, T> {
let value = self.value;
let borrow = self.into_borrow_ref_mut();
EntityRef {
value,
borrow: borrow.into_borrow_ref(),
}
}
#[doc(hidden)]
pub(crate) fn into_borrow_ref_mut(self) -> BorrowRefMut<'b> {
self.borrow
}
#[allow(unused)]
pub(crate) fn from_raw_parts(value: NonNull<T>, borrow: BorrowRefMut<'b>) -> Self {
Self {
value,
borrow,
_marker: core::marker::PhantomData,
}
}
}
impl<T: ?Sized> Deref for EntityMut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.value.as_ref() }
}
}
impl<T: ?Sized> DerefMut for EntityMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.value.as_mut() }
}
}
impl<'b, T, U> core::ops::CoerceUnsized<EntityMut<'b, U>> for EntityMut<'b, T>
where
T: ?Sized + core::marker::Unsize<U>,
U: ?Sized,
{
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for EntityMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for EntityMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized + crate::formatter::PrettyPrint> crate::formatter::PrettyPrint for EntityMut<'_, T> {
#[inline]
fn render(&self) -> crate::formatter::Document {
(**self).render()
}
}
impl<T: ?Sized + Eq> Eq for EntityMut<'_, T> {}
impl<T: ?Sized + PartialEq> PartialEq for EntityMut<'_, T> {
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: ?Sized + PartialOrd> PartialOrd for EntityMut<'_, T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
fn ge(&self, other: &Self) -> bool {
**self >= **other
}
fn gt(&self, other: &Self) -> bool {
**self > **other
}
fn le(&self, other: &Self) -> bool {
**self <= **other
}
fn lt(&self, other: &Self) -> bool {
**self < **other
}
}
impl<T: ?Sized + Ord> Ord for EntityMut<'_, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + Hash> Hash for EntityMut<'_, T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
pub struct EntityProjection<'b, T: 'b> {
borrow: BorrowRef<'b>,
value: T,
}
impl<T> core::ops::Deref for EntityProjection<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> core::ops::DerefMut for EntityProjection<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<'b, T> EntityProjection<'b, T> {
pub fn map<U, F>(orig: Self, f: F) -> EntityProjection<'b, U>
where
F: FnOnce(T) -> U,
{
EntityProjection {
value: f(orig.value),
borrow: orig.borrow,
}
}
}
impl<T: fmt::Debug> fmt::Debug for EntityProjection<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.value, f)
}
}
impl<T: fmt::Display> fmt::Display for EntityProjection<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
impl<T: crate::formatter::PrettyPrint> crate::formatter::PrettyPrint for EntityProjection<'_, T> {
#[inline]
fn render(&self) -> crate::formatter::Document {
crate::formatter::PrettyPrint::render(&self.value)
}
}
impl<T: Eq> Eq for EntityProjection<'_, T> {}
impl<T: PartialEq> PartialEq for EntityProjection<'_, T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: PartialOrd> PartialOrd for EntityProjection<'_, T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.value.partial_cmp(&other.value)
}
fn ge(&self, other: &Self) -> bool {
self.value.ge(&other.value)
}
fn gt(&self, other: &Self) -> bool {
self.value.gt(&other.value)
}
fn le(&self, other: &Self) -> bool {
self.value.le(&other.value)
}
fn lt(&self, other: &Self) -> bool {
self.value.lt(&other.value)
}
}
impl<T: Ord> Ord for EntityProjection<'_, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.value.cmp(&other.value)
}
}
impl<T: Hash> Hash for EntityProjection<'_, T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state)
}
}
pub struct EntityProjectionMut<'b, T: 'b> {
borrow: BorrowRefMut<'b>,
value: T,
}
impl<T> core::ops::Deref for EntityProjectionMut<'_, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> core::ops::DerefMut for EntityProjectionMut<'_, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<'b, T> EntityProjectionMut<'b, T> {
pub fn map<U, F>(orig: Self, f: F) -> EntityProjectionMut<'b, U>
where
F: FnOnce(T) -> U,
{
EntityProjectionMut {
value: f(orig.value),
borrow: orig.borrow,
}
}
}
impl<T: fmt::Debug> fmt::Debug for EntityProjectionMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.value, f)
}
}
impl<T: fmt::Display> fmt::Display for EntityProjectionMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
impl<T: crate::formatter::PrettyPrint> crate::formatter::PrettyPrint
for EntityProjectionMut<'_, T>
{
#[inline]
fn render(&self) -> crate::formatter::Document {
crate::formatter::PrettyPrint::render(&self.value)
}
}
impl<T: Eq> Eq for EntityProjectionMut<'_, T> {}
impl<T: PartialEq> PartialEq for EntityProjectionMut<'_, T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: PartialOrd> PartialOrd for EntityProjectionMut<'_, T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.value.partial_cmp(&other.value)
}
fn ge(&self, other: &Self) -> bool {
self.value.ge(&other.value)
}
fn gt(&self, other: &Self) -> bool {
self.value.gt(&other.value)
}
fn le(&self, other: &Self) -> bool {
self.value.le(&other.value)
}
fn lt(&self, other: &Self) -> bool {
self.value.lt(&other.value)
}
}
impl<T: Ord> Ord for EntityProjectionMut<'_, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.value.cmp(&other.value)
}
}
impl<T: Hash> Hash for EntityProjectionMut<'_, T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state)
}
}
#[repr(C)]
#[doc(hidden)]
pub struct RawEntityMetadata<T: ?Sized, Metadata> {
metadata: Metadata,
entity: RawEntity<T>,
}
impl<T, Metadata> RawEntityMetadata<T, Metadata> {
pub(crate) fn new(value: T, metadata: Metadata) -> Self {
Self {
metadata,
entity: RawEntity::new(value),
}
}
}
impl<T: ?Sized, Metadata> RawEntityMetadata<T, Metadata> {
#[track_caller]
pub(crate) fn borrow(&self) -> EntityRef<'_, T> {
self.entity.borrow()
}
#[track_caller]
pub(crate) fn borrow_mut(&self) -> EntityMut<'_, T> {
self.entity.borrow_mut()
}
#[inline]
const fn metadata_offset() -> usize {
core::mem::offset_of!(RawEntityMetadata<(), Metadata>, metadata)
}
unsafe fn data_offset(ptr: *const T) -> usize {
use core::mem::align_of_val_raw;
unsafe { RawEntityMetadata::<(), Metadata>::data_offset_align(align_of_val_raw(ptr)) }
}
#[inline]
fn data_offset_align(align: usize) -> usize {
raw_entity_value_offset_for_align::<Metadata>(align)
}
}
fn raw_entity_metadata_layout_for_value_layout<Metadata>(layout: Layout) -> Layout {
let value_offset = raw_entity_value_offset_for_align::<Metadata>(layout.align());
let header_layout = Layout::new::<RawEntity<()>>();
let align = Layout::new::<Metadata>().align().max(header_layout.align()).max(layout.align());
Layout::from_size_align(value_offset + layout.size(), align)
.unwrap()
.pad_to_align()
}
fn raw_entity_value_offset_for_align<Metadata>(value_align: usize) -> usize {
let metadata_layout = Layout::new::<Metadata>();
let header_layout = Layout::new::<RawEntity<()>>();
let entity_align = header_layout.align().max(value_align);
let entity_offset = metadata_layout.size() + metadata_layout.padding_needed_for(entity_align);
let cell_offset = header_layout.size() + header_layout.padding_needed_for(value_align);
entity_offset + cell_offset
}
#[repr(C)]
pub struct RawEntity<T: ?Sized> {
borrow: Cell<BorrowFlag>,
#[cfg(debug_assertions)]
borrowed_at: Cell<Option<&'static core::panic::Location<'static>>>,
cell: UnsafeCell<T>,
}
impl<T> RawEntity<T> {
pub fn new(value: T) -> Self {
Self {
borrow: Cell::new(BorrowFlag::UNUSED),
#[cfg(debug_assertions)]
borrowed_at: Cell::new(None),
cell: UnsafeCell::new(value),
}
}
#[allow(unused)]
#[doc(hidden)]
#[inline(always)]
pub(crate) fn entity_addr(&self) -> *mut T {
self.cell.get()
}
#[allow(unused)]
#[doc(hidden)]
#[inline(always)]
pub(crate) const fn entity_offset(&self) -> usize {
core::mem::offset_of!(Self, cell)
}
}
impl<T, U> core::ops::CoerceUnsized<RawEntity<U>> for RawEntity<T> where
T: core::ops::CoerceUnsized<U>
{
}
impl<T: ?Sized> RawEntity<T> {
#[track_caller]
#[allow(unused)]
pub unsafe fn borrow_unsafe(&self) -> (NonNull<T>, BorrowRef<'_>) {
match self.try_borrow() {
Ok(b) => (b.value, b.into_borrow_ref()),
Err(err) => panic_aliasing_violation(err),
}
}
#[track_caller]
pub unsafe fn borrow_mut_unsafe(&self) -> (NonNull<T>, BorrowRefMut<'_>) {
match self.try_borrow_mut() {
Ok(b) => (b.value, b.into_borrow_ref_mut()),
Err(err) => panic_aliasing_violation(err),
}
}
#[track_caller]
#[inline]
pub fn borrow(&self) -> EntityRef<'_, T> {
match self.try_borrow() {
Ok(b) => b,
Err(err) => panic_aliasing_violation(err),
}
}
#[inline]
#[track_caller]
pub fn try_borrow(&self) -> Result<EntityRef<'_, T>, AliasingViolationError> {
match BorrowRef::new(&self.borrow) {
Some(b) => {
#[cfg(debug_assertions)]
{
if b.borrow.get() == BorrowFlag(1) {
self.borrowed_at.set(Some(core::panic::Location::caller()));
}
}
let value = unsafe { NonNull::new_unchecked(self.cell.get()) };
Ok(EntityRef { value, borrow: b })
}
None => Err(AliasingViolationError {
#[cfg(debug_assertions)]
location: self.borrowed_at.get().unwrap(),
kind: AliasingViolationKind::Immutable,
}),
}
}
#[inline]
#[track_caller]
pub fn borrow_mut(&self) -> EntityMut<'_, T> {
match self.try_borrow_mut() {
Ok(b) => b,
Err(err) => panic_aliasing_violation(err),
}
}
#[inline]
#[track_caller]
pub fn try_borrow_mut(&self) -> Result<EntityMut<'_, T>, AliasingViolationError> {
match BorrowRefMut::new(&self.borrow) {
Some(b) => {
#[cfg(debug_assertions)]
{
self.borrowed_at.set(Some(core::panic::Location::caller()));
}
let value = unsafe { NonNull::new_unchecked(self.cell.get()) };
Ok(EntityMut {
value,
borrow: b,
_marker: core::marker::PhantomData,
})
}
None => Err(AliasingViolationError {
#[cfg(debug_assertions)]
location: self.borrowed_at.get().unwrap(),
kind: AliasingViolationKind::Mutable,
}),
}
}
}
#[doc(hidden)]
pub struct BorrowRef<'b> {
borrow: &'b Cell<BorrowFlag>,
}
impl<'b> BorrowRef<'b> {
#[inline]
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<Self> {
let b = borrow.get().wrapping_add(1);
if !b.is_reading() {
None
} else {
borrow.set(b);
Some(Self { borrow })
}
}
pub fn try_into_mut(self) -> Result<BorrowRefMut<'b>, Self> {
use core::mem::ManuallyDrop;
let this = ManuallyDrop::new(self);
let b = this.borrow.get();
debug_assert!(b.is_reading());
if (b - 1).is_unused() {
this.borrow.set(BorrowFlag::UNUSED - 1);
Ok(BorrowRefMut {
borrow: this.borrow,
})
} else {
Err(ManuallyDrop::into_inner(this))
}
}
}
impl Drop for BorrowRef<'_> {
#[inline]
fn drop(&mut self) {
let borrow = self.borrow.get();
debug_assert!(borrow.is_reading());
self.borrow.set(borrow - 1);
}
}
impl Clone for BorrowRef<'_> {
#[inline]
fn clone(&self) -> Self {
let borrow = self.borrow.get();
debug_assert!(borrow.is_reading());
assert!(borrow != BorrowFlag::MAX);
self.borrow.set(borrow + 1);
BorrowRef {
borrow: self.borrow,
}
}
}
#[doc(hidden)]
pub struct BorrowRefMut<'b> {
borrow: &'b Cell<BorrowFlag>,
}
impl Drop for BorrowRefMut<'_> {
#[inline]
fn drop(&mut self) {
let borrow = self.borrow.get();
debug_assert!(borrow.is_writing());
self.borrow.set(borrow + 1);
}
}
impl<'b> BorrowRefMut<'b> {
pub fn into_borrow_ref(self) -> BorrowRef<'b> {
let borrow = self.borrow;
debug_assert!(borrow.get().is_writing());
borrow.set(borrow.get() + 2);
core::mem::forget(self);
BorrowRef { borrow }
}
#[inline]
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<Self> {
match borrow.get() {
BorrowFlag::UNUSED => {
borrow.set(BorrowFlag::UNUSED - 1);
Some(Self { borrow })
}
_ => None,
}
}
#[inline]
fn clone(&self) -> Self {
let borrow = self.borrow.get();
debug_assert!(borrow.is_writing());
assert!(borrow != BorrowFlag::MIN);
self.borrow.set(borrow - 1);
Self {
borrow: self.borrow,
}
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
struct BorrowFlag(isize);
impl BorrowFlag {
const MAX: Self = Self(isize::MAX);
const MIN: Self = Self(isize::MIN);
const UNUSED: Self = Self(0);
#[allow(unused)]
pub fn is_unused(&self) -> bool {
self.0 == Self::UNUSED.0
}
pub fn is_writing(&self) -> bool {
self.0 < Self::UNUSED.0
}
pub fn is_reading(&self) -> bool {
self.0 > Self::UNUSED.0
}
#[inline]
pub const fn wrapping_add(self, rhs: isize) -> Self {
Self(self.0.wrapping_add(rhs))
}
}
impl core::ops::Add<isize> for BorrowFlag {
type Output = BorrowFlag;
#[inline]
fn add(self, rhs: isize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl core::ops::Sub<isize> for BorrowFlag {
type Output = BorrowFlag;
#[inline]
fn sub(self, rhs: isize) -> Self::Output {
Self(self.0 - rhs)
}
}
#[cfg_attr(not(panic = "abort"), inline(never))]
#[track_caller]
#[cold]
fn panic_aliasing_violation(err: AliasingViolationError) -> ! {
panic!("{err:?}")
}