Skip to content

Commit

Permalink
Add UniqueOr views
Browse files Browse the repository at this point in the history
These views can initialize unique components

Related issue: #209
  • Loading branch information
leudz committed Nov 13, 2024
1 parent 8ab5e27 commit 82e6e30
Show file tree
Hide file tree
Showing 7 changed files with 558 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,9 @@ pub use tracking::{
};
pub use unique::UniqueStorage;
pub use views::{
AllStoragesView, AllStoragesViewMut, EntitiesView, EntitiesViewMut, UniqueView, UniqueViewMut,
View, ViewMut,
AllStoragesView, AllStoragesViewMut, EntitiesView, EntitiesViewMut, UniqueOrDefaultView,
UniqueOrDefaultViewMut, UniqueOrInitView, UniqueOrInitViewMut, UniqueView, UniqueViewMut, View,
ViewMut,
};
pub use world::{World, WorldBuilder};

Expand Down
8 changes: 8 additions & 0 deletions src/views.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
mod all_storages;
mod entities;
mod unique_or_default;
mod unique_or_default_mut;
mod unique_or_init;
mod unique_or_init_mut;
mod unique_view;
mod unique_view_mut;
mod view;
mod view_mut;

pub use all_storages::{AllStoragesView, AllStoragesViewMut};
pub use entities::{EntitiesView, EntitiesViewMut};
pub use unique_or_default::UniqueOrDefaultView;
pub use unique_or_default_mut::UniqueOrDefaultViewMut;
pub use unique_or_init::UniqueOrInitView;
pub use unique_or_init_mut::UniqueOrInitViewMut;
pub use unique_view::UniqueView;
pub use unique_view_mut::UniqueViewMut;
pub use view::View;
Expand Down
61 changes: 61 additions & 0 deletions src/views/unique_or_default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::all_storages::AllStorages;
use crate::atomic_refcell::ARef;
use crate::borrow::{Borrow, WorldBorrow};
use crate::component::Unique;
use crate::info::TypeInfo;
use crate::tracking::TrackingTimestamp;
use crate::views::UniqueView;
use crate::world::World;
use crate::{error, BorrowInfo};
use std::ops::Deref;

/// Shared view over a unique component storage.
///
/// If the component is not already present, its default value will be inserted.
pub struct UniqueOrDefaultView<'v, T: Unique + Default>(UniqueView<'v, T>);

impl<'v, T: Unique + Default> Deref for UniqueOrDefaultView<'v, T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'v, T: Unique + Default + Send + Sync> WorldBorrow for UniqueOrDefaultView<'v, T> {
type WorldView<'a> = UniqueOrDefaultView<'a, T>;

fn world_borrow(
world: &World,
last_run: Option<TrackingTimestamp>,
current: TrackingTimestamp,
) -> Result<Self::WorldView<'_>, error::GetStorage> {
let all_storages = world
.all_storages()
.map_err(error::GetStorage::AllStoragesBorrow)?;

match all_storages.borrow::<UniqueView<'_, T>>() {
Ok(_) => {}
Err(error::GetStorage::MissingStorage { .. }) => all_storages.add_unique(T::default()),
Err(err) => return Err(err),
};

let (all_storages, all_borrow) = unsafe { ARef::destructure(all_storages) };

let view = UniqueView::borrow(all_storages, Some(all_borrow), last_run, current)?;

Ok(UniqueOrDefaultView(view))
}
}

unsafe impl<'v, T: Unique + Default + Send + Sync> BorrowInfo for UniqueOrDefaultView<'v, T> {
fn borrow_info(info: &mut Vec<TypeInfo>) {
UniqueView::<T>::borrow_info(info);
}

fn enable_tracking(
enable_tracking_fn: &mut Vec<fn(&AllStorages) -> Result<(), error::GetStorage>>,
) {
UniqueView::<T>::enable_tracking(enable_tracking_fn);
}
}
67 changes: 67 additions & 0 deletions src/views/unique_or_default_mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use crate::all_storages::AllStorages;
use crate::atomic_refcell::ARef;
use crate::borrow::{Borrow, WorldBorrow};
use crate::component::Unique;
use crate::info::TypeInfo;
use crate::tracking::TrackingTimestamp;
use crate::views::UniqueViewMut;
use crate::world::World;
use crate::{error, BorrowInfo};
use std::ops::{Deref, DerefMut};

/// Exclusive view over a unique component storage.
///
/// If the component is not already present, its default value will be inserted.
pub struct UniqueOrDefaultViewMut<'v, T: Unique + Default>(UniqueViewMut<'v, T>);

impl<'v, T: Unique + Default> Deref for UniqueOrDefaultViewMut<'v, T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'v, T: Unique + Default> DerefMut for UniqueOrDefaultViewMut<'v, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<'v, T: Unique + Default + Send + Sync> WorldBorrow for UniqueOrDefaultViewMut<'v, T> {
type WorldView<'a> = UniqueOrDefaultViewMut<'a, T>;

fn world_borrow(
world: &World,
last_run: Option<TrackingTimestamp>,
current: TrackingTimestamp,
) -> Result<Self::WorldView<'_>, error::GetStorage> {
let all_storages = world
.all_storages()
.map_err(error::GetStorage::AllStoragesBorrow)?;

match all_storages.borrow::<UniqueViewMut<'_, T>>() {
Ok(_) => {}
Err(error::GetStorage::MissingStorage { .. }) => all_storages.add_unique(T::default()),
Err(err) => return Err(err),
};

let (all_storages, all_borrow) = unsafe { ARef::destructure(all_storages) };

let view = UniqueViewMut::borrow(all_storages, Some(all_borrow), last_run, current)?;

Ok(UniqueOrDefaultViewMut(view))
}
}

unsafe impl<'v, T: Unique + Default + Send + Sync> BorrowInfo for UniqueOrDefaultViewMut<'v, T> {
fn borrow_info(info: &mut Vec<TypeInfo>) {
UniqueViewMut::<T>::borrow_info(info);
}

fn enable_tracking(
enable_tracking_fn: &mut Vec<fn(&AllStorages) -> Result<(), error::GetStorage>>,
) {
UniqueViewMut::<T>::enable_tracking(enable_tracking_fn);
}
}
181 changes: 181 additions & 0 deletions src/views/unique_or_init.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use crate::all_storages::AllStorages;
use crate::atomic_refcell::{ARef, SharedBorrow};
use crate::borrow::{Borrow, BorrowInfo, WorldBorrow};
use crate::component::Unique;
use crate::error;
use crate::info::TypeInfo;
use crate::tracking::TrackingTimestamp;
use crate::views::UniqueView;
use crate::world::World;
use core::cell::OnceCell;

/// Shared view over a unique component storage.
///
/// The component can be initialized with this view.
pub struct UniqueOrInitView<'v, T: Unique + Default> {
cell: OnceCell<UniqueView<'v, T>>,
all_storages: &'v AllStorages,
all_borrow: SharedBorrow<'v>,
last_run: Option<TrackingTimestamp>,
current: TrackingTimestamp,
}

impl<'v, T: Unique + Default + Send + Sync> UniqueOrInitView<'v, T> {
/// Gets a reference to the inner [`UniqueView`].
///
/// Returns `None` if this view doesn't contains the inner [`UniqueView`].
pub fn get(&self) -> Option<&UniqueView<'v, T>> {
self.cell.get()
}

/// Adds the unique component to the `World`.
///
/// Returns `true` if the component was inserted.
///
/// ### Borrows
///
/// - `Unique<T>` storage (shared)
///
/// ### Errors
///
/// - `Unique<T>` storage borrow failed (it can be initialized and borrowed elsewhere).
pub fn set(&self, unique: T) -> Result<bool, error::GetStorage> {
if self.cell.get().is_some() {
return Ok(false);
}

self.all_storages.add_unique(unique);

self.cell
.set(UniqueView::borrow(
self.all_storages,
Some(self.all_borrow.clone()),
self.last_run,
self.current,
)?)
.unwrap_or_else(|_| unreachable!("Cell is expected to be empty"));

Ok(true)
}

/// Fetches the unique component from the `World`.
///
/// Returns `true` if the component was fetched.
///
/// ### Borrows
///
/// - `Unique<T>` storage (shared)
///
/// ### Errors
///
/// - `Unique<T>` storage borrow failed (it can be initialized and borrowed elsewhere).
pub fn fetch(&self) -> Result<bool, error::GetStorage> {
if self.cell.get().is_some() {
return Ok(false);
}

self.cell
.set(UniqueView::borrow(
self.all_storages,
Some(self.all_borrow.clone()),
self.last_run,
self.current,
)?)
.unwrap_or_else(|_| unreachable!("Cell is expected to be empty"));

Ok(true)
}

/// Gets the unique component from the `World`.\
/// Adds it to the `World` if not present.
///
/// ### Borrows
///
/// - `Unique<T>` storage (shared)
///
/// ### Errors
///
/// - `Unique<T>` storage borrow failed (it can be initialized and borrowed elsewhere).
pub fn get_or_init(
&self,
f: impl FnOnce() -> T,
) -> Result<&UniqueView<'v, T>, error::GetStorage> {
if let Some(view) = self.cell.get() {
return Ok(view);
}

let view = match UniqueView::borrow(
self.all_storages,
Some(self.all_borrow.clone()),
self.last_run,
self.current,
) {
Ok(view) => view,
Err(error::GetStorage::MissingStorage { .. }) => {
self.all_storages.add_unique(f());

UniqueView::borrow(
self.all_storages,
Some(self.all_borrow.clone()),
self.last_run,
self.current,
)?
}
Err(err) => return Err(err),
};

self.cell
.set(view)
.unwrap_or_else(|_| unreachable!("Cell is expected to be empty"));

Ok(self
.cell
.get()
.unwrap_or_else(|| unreachable!("Cell is expected to be initialized")))
}
}

impl<'v, T: Unique + Default + Send + Sync> WorldBorrow for UniqueOrInitView<'v, T> {
type WorldView<'a> = UniqueOrInitView<'a, T>;

fn world_borrow(
world: &World,
last_run: Option<TrackingTimestamp>,
current: TrackingTimestamp,
) -> Result<Self::WorldView<'_>, error::GetStorage> {
let all_storages = world
.all_storages()
.map_err(error::GetStorage::AllStoragesBorrow)?;

let (all_storages, all_borrow) = unsafe { ARef::destructure(all_storages) };
let cell = OnceCell::new();

match UniqueView::borrow(all_storages, Some(all_borrow.clone()), last_run, current) {
Ok(view) => cell
.set(view)
.unwrap_or_else(|_| unreachable!("Cell is expected to be empty")),
Err(error::GetStorage::MissingStorage { .. }) => {}
Err(err) => return Err(err),
};

Ok(UniqueOrInitView {
cell,
all_storages,
all_borrow,
last_run,
current,
})
}
}

unsafe impl<'v, T: Unique + Default + Send + Sync> BorrowInfo for UniqueOrInitView<'v, T> {
fn borrow_info(info: &mut Vec<TypeInfo>) {
UniqueView::<T>::borrow_info(info);
}

fn enable_tracking(
enable_tracking_fn: &mut Vec<fn(&AllStorages) -> Result<(), error::GetStorage>>,
) {
UniqueView::<T>::enable_tracking(enable_tracking_fn);
}
}
Loading

0 comments on commit 82e6e30

Please sign in to comment.