lyra-engine/lyra-resource/src/resource.rs

148 lines
4.3 KiB
Rust
Raw Normal View History

2024-01-15 18:07:47 -05:00
use std::sync::{Arc, RwLock};
2023-09-12 14:25:33 -04:00
use uuid::Uuid;
2023-09-21 09:36:44 -04:00
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
2023-09-12 14:25:33 -04:00
pub enum ResourceState {
Loading,
Ready,
}
2024-01-15 18:07:47 -05:00
pub struct ResourceDataRef<'a, T> {
guard: std::sync::RwLockReadGuard<'a, Resource<T>>,
2023-09-12 14:25:33 -04:00
}
2024-01-15 18:07:47 -05:00
impl<'a, T> std::ops::Deref for ResourceDataRef<'a, T> {
type Target = T;
2024-01-15 18:07:47 -05:00
fn deref(&self) -> &Self::Target {
// safety: this struct must only be created if the resource is loaded
self.guard.data.as_ref().unwrap()
}
}
pub(crate) struct Resource<T> {
path: String,
pub(crate) data: Option<T>,
pub(crate) version: usize,
pub(crate) state: ResourceState,
uuid: Uuid,
}
/// A handle to a resource.
///
/// # Note
/// This struct has an inner [`RwLock`] to the resource data, so most methods may be blocking.
/// However, the only times it will be blocking is if another thread is reloading the resource
/// and has a write lock on the data. This means that most of the time, it is not blocking.
pub struct ResHandle<T> {
pub(crate) data: Arc<RwLock<Resource<T>>>,
}
impl<T> Clone for ResHandle<T> {
fn clone(&self) -> Self {
Self { data: self.data.clone() }
}
}
impl<T> ResHandle<T> {
2023-09-12 14:25:33 -04:00
/// Create the resource with data, its assumed the state is `Ready`
pub fn with_data(path: &str, data: T) -> Self {
2024-01-15 18:07:47 -05:00
let res_version = Resource {
2023-09-12 14:25:33 -04:00
path: path.to_string(),
2024-01-15 18:07:47 -05:00
data: Some(data),
version: 0,
2023-09-12 14:25:33 -04:00
state: ResourceState::Ready,
2024-01-15 18:07:47 -05:00
uuid: Uuid::new_v4(),
};
Self {
data: Arc::new(RwLock::new(res_version)),
2023-09-12 14:25:33 -04:00
}
}
2024-01-15 18:07:47 -05:00
/// Returns a boolean indicated if this resource is loaded
pub fn is_loaded(&self) -> bool {
let d = self.data.read().expect("Resource mutex was poisoned!");
d.state == ResourceState::Ready
}
/// Returns the current state of the resource.
pub fn state(&self) -> ResourceState {
let d = self.data.read().expect("Resource mutex was poisoned!");
d.state
}
/// Returns the path that the resource was loaded from.
pub fn path(&self) -> String {
let d = self.data.read().expect("Resource mutex was poisoned!");
d.path.to_string()
}
/// Returns the uuid of the resource.
pub fn uuid(&self) -> Uuid {
let d = self.data.read().expect("Resource mutex was poisoned!");
d.uuid
}
/// Retrieves the current version of the resource. This gets incremented when the resource
/// is reloaded.
pub fn version(&self) -> usize {
let d = self.data.read().expect("Resource mutex was poisoned!");
d.version
}
/// Get a reference to the data in the resource
///
/// # Panics
/// Panics if the resource was not loaded yet.
pub fn data_ref<'a>(&'a self) -> ResourceDataRef<'a, T> {
let d = self.data.read().expect("Resource mutex was poisoned!");
ResourceDataRef {
guard: d
}
}
/// Attempt to get a borrow to the resource data. Returns `None` if the resource is not loaded.
pub fn try_data_ref<'a>(&'a self) -> Option<ResourceDataRef<'a, T>> {
if self.is_loaded() {
let d = self.data.read().expect("Resource mutex was poisoned!");
Some(ResourceDataRef {
guard: d
})
} else {
None
}
}
/* /// Get a reference to the data in the resource
///
/// # Panics
/// Panics if the resource was not loaded yet.
pub fn data_ref(&self) -> &T {
self.data.as_ref()
.expect("Resource is not loaded yet (use try_data_ref, or wait until its loaded)!")
}
/// If the resource is loaded, returns `Some` reference to the data in the resource,
/// else it will return `None`
pub fn try_data_ref(&self) -> Option<&T> {
self.data.as_ref()
}
/// Get a **mutable** reference to the data in the resource
///
/// # Panics
/// Panics if the resource was not loaded yet.
pub fn data_mut(&mut self) -> &mut T {
self.data.as_mut()
.expect("Resource is not loaded yet (use try_data_ref, or wait until its loaded)!")
}
/// If the resource is loaded, returns `Some` **mutable** reference to the data in the resource,
/// else it will return `None`
pub fn try_data_mut(&mut self) -> Option<&mut T> {
self.data.as_mut()
} */
}