Skip to content

Commit

Permalink
updated resource manager docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mrDIMAS committed Aug 7, 2024
1 parent 28248c0 commit 6529236
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
4 changes: 2 additions & 2 deletions fyrox-resource/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub trait ResourceData: 'static + Debug + Visit + Send + Reflect {
/// Saves the resource data a file at the specified path. This method is free to
/// decide how the resource data is saved. This is needed, because there are multiple formats
/// that defines various kinds of resources. For example, a rectangular texture could be saved
/// into a whole bunch of formats, such as png, bmp, tga, jpg etc, but in the engine it is single
/// into a bunch of formats, such as png, bmp, tga, jpg etc., but in the engine it is single
/// Texture resource. In any case, produced file should be compatible with a respective resource
/// loader.
fn save(&mut self, #[allow(unused_variables)] path: &Path) -> Result<(), Box<dyn Error>>;
Expand Down Expand Up @@ -122,7 +122,7 @@ where
}

/// A resource of particular data type. It is a typed wrapper around [`UntypedResource`] which
/// does type checks at runtime.
/// does type checks at runtime. See [`UntypedResource`] for more info.
///
/// ## Default State
///
Expand Down
24 changes: 19 additions & 5 deletions fyrox-resource/src/manager.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Resource manager controls loading and lifetime of resource in the engine.
//! Resource manager controls loading and lifetime of resource in the engine. See [`ResourceManager`]
//! docs for more info.

use crate::untyped::ResourceKind;
use crate::{
collect_used_resources,
constructor::ResourceConstructorContainer,
Expand All @@ -21,6 +21,7 @@ use crate::{
loader::{ResourceLoader, ResourceLoadersContainer},
options::OPTIONS_EXTENSION,
state::{LoadError, ResourceState},
untyped::ResourceKind,
Resource, ResourceData, TypedResourceData, UntypedResource,
};
use fxhash::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -53,7 +54,7 @@ impl ResourceWaitContext {
}
}

/// See module docs.
/// Internal state of the resource manager.
pub struct ResourceManagerState {
/// A set of resource loaders. Use this field to register your own resource loader.
pub loaders: ResourceLoadersContainer,
Expand All @@ -63,15 +64,28 @@ pub struct ResourceManagerState {
pub constructors_container: ResourceConstructorContainer,
/// A set of built-in resources, that will be used to resolve references on deserialization.
pub built_in_resources: FxHashMap<PathBuf, UntypedResource>,
/// The resource acccess interface
/// File system abstraction interface. Could be used to support virtual file systems.
pub resource_io: Arc<dyn ResourceIo>,

resources: Vec<TimedEntry<UntypedResource>>,
task_pool: Arc<TaskPool>,
watcher: Option<FileSystemWatcher>,
}

/// See module docs.
/// Resource manager controls loading and lifetime of resource in the engine. Resource manager can hold
/// resources of arbitrary types via type erasure mechanism.
///
/// ## Built-in Resources
///
/// Built-in resources are special kinds of resources, whose data is packed in the executable (i.e. via
/// [`include_bytes`] macro). Such resources reference the data that cannot be "loaded" from external
/// source. To support such kind of resource the manager provides `built_in_resources` hash map where
/// you can register your own built-in resource and access existing ones.
///
/// ## Internals
///
/// It is a simple wrapper over [`ResourceManagerState`] that can be shared (cloned). In other words,
/// it is just a strong reference to the inner state.
#[derive(Clone)]
pub struct ResourceManager {
state: Arc<Mutex<ResourceManagerState>>,
Expand Down
58 changes: 54 additions & 4 deletions fyrox-resource/src/untyped.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! A module for untyped resources. See [`UntypedResource`] docs for more info.

#![allow(missing_docs)]

use crate::{
core::{
math::curve::Curve, parking_lot::Mutex, reflect::prelude::*, uuid, uuid::Uuid,
Expand Down Expand Up @@ -63,10 +61,22 @@ fn guess_uuid(region: &mut RegionGuard) -> Uuid {
Default::default()
}

/// Kind of a resource. It defines how the resource manager will treat a resource content on serialization.
#[derive(Default, Reflect, Debug, Visit, Clone, PartialEq, Eq, Hash)]
pub enum ResourceKind {
/// The content of embedded resources will be fully serialized.
#[default]
Embedded,
/// The content of external resources will not be serialized, instead only the path to the content
/// will be serialized and the content will be loaded from it when needed.
///
/// ## Built-in Resources
///
/// This resource kind could also be used to create built-in resources (the data of which is
/// embedded directly in the executable using [`include_bytes`] macro). All that is needed is to
/// create a static resource variable and register it in built-in resources of the resource manager.
/// In this case, the path becomes an identifier and it must be unique. See [`ResourceManager`] docs
/// for more info about built-in resources.
External(PathBuf),
}

Expand All @@ -92,26 +102,31 @@ impl<'a> From<&'a str> for ResourceKind {
}

impl ResourceKind {
/// Switches the resource kind to [`Self::External`].
#[inline]
pub fn make_external(&mut self, path: PathBuf) {
*self = ResourceKind::External(path);
}

/// Switches the resource kind to [`Self::Embedded`]
#[inline]
pub fn make_embedded(&mut self) {
*self = ResourceKind::Embedded;
}

/// Checks, if the resource kind is [`Self::Embedded`]
#[inline]
pub fn is_embedded(&self) -> bool {
matches!(self, Self::Embedded)
}

/// Checks, if the resource kind is [`Self::External`]
#[inline]
pub fn is_external(&self) -> bool {
!self.is_embedded()
}

/// Tries to fetch a resource path, returns [`None`] for [`Self::Embedded`] resources.
#[inline]
pub fn path(&self) -> Option<&Path> {
match self {
Expand All @@ -120,11 +135,14 @@ impl ResourceKind {
}
}

/// Tries to fetch a resource path, returns [`None`] for [`Self::Embedded`] resources.
#[inline]
pub fn path_owned(&self) -> Option<PathBuf> {
self.path().map(|p| p.to_path_buf())
}

/// Tries to convert the resource kind into its path, returns [`None`] for [`Self::Embedded`]
/// resources.
#[inline]
pub fn into_path(self) -> Option<PathBuf> {
match self {
Expand All @@ -147,10 +165,15 @@ impl Display for ResourceKind {
}
}

/// Header of a resource, it contains a common data about the resource, such as its data type uuid,
/// its kind, etc.
#[derive(Reflect, Debug)]
pub struct ResourceHeader {
/// UUID of the internal data type.
pub type_uuid: Uuid,
/// Kind of the resource. See [`ResourceKind`] for more info.
pub kind: ResourceKind,
/// Actual state of the resource. See [`ResourceState`] for more info.
pub state: ResourceState,
}

Expand Down Expand Up @@ -232,9 +255,36 @@ impl Visit for ResourceHeader {
/// Untyped resource is a universal way of storing arbitrary resource types. Internally it wraps
/// [`ResourceState`] in a `Arc<Mutex<>` so the untyped resource becomes shareable. In most of the
/// cases you don't need to deal with untyped resources, use typed [`Resource`] wrapper instead.
/// Untyped resource could be useful in cases when you need to collect a set resources of different
/// Untyped resource could be useful in cases when you need to collect a set of resources of different
/// types in a single collection and do something with them.
///
/// ## Handle
///
/// Since untyped resources stores the actual data in a shared storage, the resource instance could
/// be considered as a handle. Such "handles" have special behaviour on serialization and
/// deserialization to keep pointing to the same storage.
///
/// ## Serialization and Deserialization
///
/// Every resource writes its own kind, type uuid of the data and optionally the data itself.
///
/// Serialization/deserialization of the data is different depending on the actual resource kind
/// (see [`ResourceKind`]):
///
/// 1) [`ResourceKind::Embedded`] - the resource data will be serialized together with the resource
/// handle. The data will be loaded back on deserialization stage from the backing storage.
/// 2) [`ResourceKind::External`] - the resource data won't be serialized and will be reloaded from
/// the external source.
///
/// When the resource is deserialized, the resource system at first looks for an already loaded
/// resource with the same kind and if it is found, replaces current instance with the loaded one.
/// If not - loads the resource and also replaces the instance. This step is crucial for uniqueness
/// of the resource handles.
///
/// To put everything simple: when you save a resource handle, it writes only path to it, then when
/// you load it you need to make sure that all references to a resource points to the same resource
/// instance.
///
/// ## Default state
///
/// Default state of every untyped resource is [`ResourceState::LoadError`] with a warning message,
Expand Down Expand Up @@ -402,7 +452,7 @@ impl UntypedResource {
}

/// Changes ResourceState::Pending state to ResourceState::Ok(data) with given `data`.
/// Additionally it wakes all futures.
/// Additionally, it wakes all futures.
#[inline]
pub fn commit(&self, state: ResourceState) {
self.0.lock().state.commit(state);
Expand Down

0 comments on commit 6529236

Please sign in to comment.