pub struct ProjectVfs {
pub root: PathBuf,
pub assets_root: PathBuf,
pub asset_service: AssetService,
pub watcher: AssetWatcher,
file_loader: FileLoader,
registry: AssetIdRegistry,
}Expand description
All project I/O, in one place.
open performs a recursive scan of <root>/assets/, builds an in-memory
VFS index (UUIDs derived from forward-slash relative paths via
AssetUUID::new_v5), constructs the AssetService with every default
decoder registered, and arms a recursive filesystem watcher for hot
reload. UUIDs match what a future pack-builder would produce, so the
dev/release transparency promise of the VFS is preserved.
Fields§
§root: PathBuf§assets_root: PathBuf§asset_service: AssetService§watcher: AssetWatcher§file_loader: FileLoader§registry: AssetIdRegistryStable-identity registry (<root>/.khora/asset-registry.ron). The editor
is the sole writer: file operations freeze/rename/remove entries so an
asset keeps its UUID across renames and every reference keeps resolving.
Implementations§
Source§impl ProjectVfs
impl ProjectVfs
Sourcepub fn open(root: PathBuf, metrics: Arc<MetricsRegistry>) -> Result<Self>
pub fn open(root: PathBuf, metrics: Arc<MetricsRegistry>) -> Result<Self>
Opens (or creates) <root>/assets/, builds the VFS, and arms the
watcher. Tolerates fresh projects whose assets/ directory hasn’t
been populated yet — the resulting service has zero indexed assets,
which is exactly what the asset browser will show.
Sourcepub fn rebuild_index(&mut self) -> Result<()>
pub fn rebuild_index(&mut self) -> Result<()>
Re-walks <root>/assets/ and atomically swaps the VFS index. Called
after a scene save (so the new file shows up) and from the
hot-reload pump on Created/Removed events.
Sourcepub fn read_project_json(&self) -> Result<Value>
pub fn read_project_json(&self) -> Result<Value>
Reads <root>/project.json as untyped JSON. Project metadata isn’t an
asset (lives outside assets/) so it deliberately bypasses the VFS.
Sourcepub fn write_asset(&self, rel_path: &Path, bytes: &[u8]) -> Result<()>
pub fn write_asset(&self, rel_path: &Path, bytes: &[u8]) -> Result<()>
Writes bytes to <root>/assets/<rel_path>. Creates intermediate
directories as needed. Caller is responsible for calling
Self::rebuild_index afterwards if the new path needs to be
resolvable through the VFS in the same frame.
Sourcepub fn uuid_for_rel_path(rel_path_fwd_slash: &str) -> AssetUUID
pub fn uuid_for_rel_path(rel_path_fwd_slash: &str) -> AssetUUID
Returns the UUID for a relative-path-with-forward-slashes string,
regardless of whether the path currently exists on disk. Used by
scene_io to look up scenes by canonical path even before a save
has triggered a reindex.
This is the raw path-derived default and ignores the identity
registry. Prefer Self::resolve_uuid whenever the asset may have been
renamed (frozen identity); use this only for paths that cannot have a
frozen entry (e.g. a file being written for the very first time).
Sourcepub fn resolve_uuid(&self, rel_path_fwd_slash: &str) -> AssetUUID
pub fn resolve_uuid(&self, rel_path_fwd_slash: &str) -> AssetUUID
Resolves a forward-slash relative path to its UUID through the identity
registry: the frozen identity if the asset has been renamed, otherwise
the new_v5 default. This is the registry-aware counterpart to
Self::uuid_for_rel_path and must be used whenever an asset the user
could have renamed is looked up by path (scene / prefab / material load).
Sourcefn abs_of(&self, rel_fwd: &str) -> PathBuf
fn abs_of(&self, rel_fwd: &str) -> PathBuf
Absolute path of an asset given its forward-slash relative path.
Sourcepub fn create_folder(&mut self, rel_dir: &str) -> Result<()>
pub fn create_folder(&mut self, rel_dir: &str) -> Result<()>
Creates an (empty) folder under assets/ at rel_dir (forward-slash).
Empty folders are surfaced by Self::list_dirs since the VFS itself
only indexes files.
Sourcepub fn rename_asset(&mut self, old_rel: &str, new_rel: &str) -> Result<()>
pub fn rename_asset(&mut self, old_rel: &str, new_rel: &str) -> Result<()>
Renames/moves an asset from old_rel to new_rel (both forward-slash,
under assets/), freezing its UUID so every existing reference keeps
resolving. Fails if the destination already exists. Rebuilds the index.
Sourcepub fn move_asset(&mut self, src_rel: &str, dest_dir: &str) -> Result<()>
pub fn move_asset(&mut self, src_rel: &str, dest_dir: &str) -> Result<()>
Moves an asset into dest_dir (forward-slash folder, "" = assets root),
keeping its file name. Thin wrapper over Self::rename_asset.
Sourcepub fn delete_to_trash(&mut self, rel: &str) -> Result<()>
pub fn delete_to_trash(&mut self, rel: &str) -> Result<()>
Sends an asset to the OS recycle bin (reversible), drops its registry entry, and rebuilds the index.
Sourcepub fn duplicate_asset(&mut self, rel: &str) -> Result<String>
pub fn duplicate_asset(&mut self, rel: &str) -> Result<String>
Duplicates an asset next to itself with a unique copy suffix. The copy
is a new asset (no registry entry → fresh new_v5 identity). Returns
the new forward-slash relative path.
Sourcepub fn list_dirs(&self) -> Vec<String>
pub fn list_dirs(&self) -> Vec<String>
Lists every directory under assets/ as forward-slash relative paths
(sorted, excluding the root). The VFS only indexes files, so empty
folders — including freshly created ones — are only visible through this.
Sourcepub fn poll_changes(&self) -> Vec<AssetChangeEvent>
pub fn poll_changes(&self) -> Vec<AssetChangeEvent>
Drains pending hot-reload events. Convenience wrapper so callers
don’t need to reach through pvfs.watcher.
Auto Trait Implementations§
impl Freeze for ProjectVfs
impl !RefUnwindSafe for ProjectVfs
impl Send for ProjectVfs
impl Sync for ProjectVfs
impl Unpin for ProjectVfs
impl UnsafeUnpin for ProjectVfs
impl !UnwindSafe for ProjectVfs
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> Pointable for T
impl<T> Pointable for T
§impl<F, T, S> SimdInto<T, S> for Fwhere
T: SimdFrom<F, S>,
S: Simd,
impl<F, T, S> SimdInto<T, S> for Fwhere
T: SimdFrom<F, S>,
S: Simd,
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.