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::scheduler::info::TypeInfo;
use crate::tracking::TrackingTimestamp;
use crate::views::UniqueView;
use crate::world::World;
use alloc::vec::Vec;
use core::cell::OnceCell;
pub struct UniqueOrInitView<'v, T: Unique> {
cell: OnceCell<UniqueView<'v, T>>,
all_storages: &'v AllStorages,
all_borrow: SharedBorrow<'v>,
last_run: Option<TrackingTimestamp>,
current: TrackingTimestamp,
}
impl<'v, T: Unique + Send + Sync> UniqueOrInitView<'v, T> {
pub fn get(&self) -> Option<&UniqueView<'v, T>> {
self.cell.get()
}
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)
}
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)
}
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 + 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 + 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);
}
}