Skip to content

Commit

Permalink
Add file metadata to AssetIo (#2123)
Browse files Browse the repository at this point in the history
This is a replacement for #2106

This adds a `Metadata` struct which contains metadata information about a file, at the moment only the file type.
It also adds a `get_metadata` to `AssetIo` trait and an `asset_io` accessor method to `AssetServer` and `LoadContext`

I am not sure about the changes in `AndroidAssetIo ` and `WasmAssetIo`.
  • Loading branch information
geckoxx committed May 2, 2022
1 parent 8283db6 commit e29bd50
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 25 deletions.
15 changes: 7 additions & 8 deletions crates/bevy_asset/src/asset_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl AssetServer {
/// Enable watching of the filesystem for changes, if support is available, starting from after
/// the point of calling this function.
pub fn watch_for_changes(&self) -> Result<(), AssetServerError> {
self.server.asset_io.watch_for_changes()?;
self.asset_io().watch_for_changes()?;
Ok(())
}

Expand Down Expand Up @@ -301,7 +301,7 @@ impl AssetServer {
};

// load the asset bytes
let bytes = match self.server.asset_io.load_path(asset_path.path()).await {
let bytes = match self.asset_io().load_path(asset_path.path()).await {
Ok(bytes) => bytes,
Err(err) => {
set_asset_failed();
Expand All @@ -313,7 +313,7 @@ impl AssetServer {
let mut load_context = LoadContext::new(
asset_path.path(),
&self.server.asset_ref_counter.channel,
&*self.server.asset_io,
self.asset_io(),
version,
&self.server.task_pool,
);
Expand Down Expand Up @@ -361,8 +361,7 @@ impl AssetServer {
}
}

self.server
.asset_io
self.asset_io()
.watch_path_for_changes(asset_path.path())
.unwrap();
self.create_assets_in_load_context(&mut load_context);
Expand Down Expand Up @@ -403,15 +402,15 @@ impl AssetServer {
path: P,
) -> Result<Vec<HandleUntyped>, AssetServerError> {
let path = path.as_ref();
if !self.server.asset_io.is_directory(path) {
if !self.asset_io().is_dir(path) {
return Err(AssetServerError::AssetFolderNotADirectory(
path.to_str().unwrap().to_string(),
));
}

let mut handles = Vec::new();
for child_path in self.server.asset_io.read_directory(path.as_ref())? {
if self.server.asset_io.is_directory(&child_path) {
for child_path in self.asset_io().read_directory(path.as_ref())? {
if self.asset_io().is_dir(&child_path) {
handles.extend(self.load_folder(&child_path)?);
} else {
if self.get_path_asset_loader(&child_path).is_err() {
Expand Down
17 changes: 14 additions & 3 deletions crates/bevy_asset/src/io/android_asset_io.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{AssetIo, AssetIoError};
use crate::{AssetIo, AssetIoError, Metadata};
use anyhow::Result;
use bevy_utils::BoxedFuture;
use std::{
convert::TryFrom,
ffi::CString,
path::{Path, PathBuf},
};
Expand Down Expand Up @@ -46,7 +47,17 @@ impl AssetIo for AndroidAssetIo {
Ok(())
}

fn is_directory(&self, path: &Path) -> bool {
self.root_path.join(path).is_dir()
fn get_metadata(&self, path: &Path) -> Result<Metadata, AssetIoError> {
let full_path = self.root_path.join(path);
full_path
.metadata()
.and_then(Metadata::try_from)
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
AssetIoError::NotFound(full_path)
} else {
e.into()
}
})
}
}
17 changes: 14 additions & 3 deletions crates/bevy_asset/src/io/file_asset_io.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[cfg(feature = "filesystem_watcher")]
use crate::{filesystem_watcher::FilesystemWatcher, AssetServer};
use crate::{AssetIo, AssetIoError};
use crate::{AssetIo, AssetIoError, Metadata};
use anyhow::Result;
#[cfg(feature = "filesystem_watcher")]
use bevy_ecs::system::Res;
Expand All @@ -15,6 +15,7 @@ use parking_lot::RwLock;
#[cfg(feature = "filesystem_watcher")]
use std::sync::Arc;
use std::{
convert::TryFrom,
env, fs,
io::Read,
path::{Path, PathBuf},
Expand Down Expand Up @@ -128,8 +129,18 @@ impl AssetIo for FileAssetIo {
Ok(())
}

fn is_directory(&self, path: &Path) -> bool {
self.root_path.join(path).is_dir()
fn get_metadata(&self, path: &Path) -> Result<Metadata, AssetIoError> {
let full_path = self.root_path.join(path);
full_path
.metadata()
.and_then(Metadata::try_from)
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
AssetIoError::NotFound(full_path)
} else {
e.into()
}
})
}
}

Expand Down
77 changes: 77 additions & 0 deletions crates/bevy_asset/src/io/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::convert::{TryFrom, TryInto};

/// A enum representing a type of file.
#[non_exhaustive]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum FileType {
Directory,
File,
}

impl FileType {
#[inline]
pub const fn is_dir(&self) -> bool {
matches!(self, Self::Directory)
}

#[inline]
pub const fn is_file(&self) -> bool {
matches!(self, Self::File)
}
}

impl TryFrom<std::fs::FileType> for FileType {
type Error = std::io::Error;

fn try_from(file_type: std::fs::FileType) -> Result<Self, Self::Error> {
if file_type.is_dir() {
Ok(Self::Directory)
} else if file_type.is_file() {
Ok(Self::File)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"unknown file type",
))
}
}
}

/// Metadata information about a file.
///
/// This structure is returned from the [`AssetIo::get_metadata`](crate::AssetIo) method.
#[derive(Debug, Clone)]
pub struct Metadata {
file_type: FileType,
}

impl Metadata {
pub fn new(file_type: FileType) -> Self {
Self { file_type }
}

#[inline]
pub const fn file_type(&self) -> FileType {
self.file_type
}

#[inline]
pub const fn is_dir(&self) -> bool {
self.file_type.is_dir()
}

#[inline]
pub const fn is_file(&self) -> bool {
self.file_type.is_file()
}
}

impl TryFrom<std::fs::Metadata> for Metadata {
type Error = std::io::Error;

fn try_from(metadata: std::fs::Metadata) -> Result<Self, Self::Error> {
Ok(Self {
file_type: metadata.file_type().try_into()?,
})
}
}
20 changes: 19 additions & 1 deletion crates/bevy_asset/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ mod file_asset_io;
#[cfg(target_arch = "wasm32")]
mod wasm_asset_io;

mod metadata;

#[cfg(target_os = "android")]
pub use android_asset_io::*;
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
pub use file_asset_io::*;
#[cfg(target_arch = "wasm32")]
pub use wasm_asset_io::*;

pub use metadata::*;

use anyhow::Result;
use bevy_utils::BoxedFuture;
use downcast_rs::{impl_downcast, Downcast};
Expand Down Expand Up @@ -39,9 +43,23 @@ pub trait AssetIo: Downcast + Send + Sync + 'static {
&self,
path: &Path,
) -> Result<Box<dyn Iterator<Item = PathBuf>>, AssetIoError>;
fn is_directory(&self, path: &Path) -> bool;
fn get_metadata(&self, path: &Path) -> Result<Metadata, AssetIoError>;
fn watch_path_for_changes(&self, path: &Path) -> Result<(), AssetIoError>;
fn watch_for_changes(&self) -> Result<(), AssetIoError>;

fn is_dir(&self, path: &Path) -> bool {
self.get_metadata(path)
.as_ref()
.map(Metadata::is_dir)
.unwrap_or(false)
}

fn is_file(&self, path: &Path) -> bool {
self.get_metadata(path)
.as_ref()
.map(Metadata::is_file)
.unwrap_or(false)
}
}

impl_downcast!(AssetIo);
21 changes: 17 additions & 4 deletions crates/bevy_asset/src/io/wasm_asset_io.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use crate::{AssetIo, AssetIoError};
use crate::{AssetIo, AssetIoError, Metadata};
use anyhow::Result;
use bevy_utils::BoxedFuture;
use js_sys::Uint8Array;
use std::path::{Path, PathBuf};
use std::{
convert::TryFrom,
path::{Path, PathBuf},
};
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::Response;
Expand Down Expand Up @@ -50,7 +53,17 @@ impl AssetIo for WasmAssetIo {
Ok(())
}

fn is_directory(&self, path: &Path) -> bool {
self.root_path.join(path).is_dir()
fn get_metadata(&self, path: &Path) -> Result<Metadata, AssetIoError> {
let full_path = self.root_path.join(path);
full_path
.metadata()
.and_then(Metadata::try_from)
.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
AssetIoError::NotFound(full_path)
} else {
e.into()
}
})
}
}
4 changes: 4 additions & 0 deletions crates/bevy_asset/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ impl<'a> LoadContext<'a> {
pub fn task_pool(&self) -> &TaskPool {
self.task_pool
}

pub fn asset_io(&self) -> &dyn AssetIo {
self.asset_io
}
}

/// The result of loading an asset of type `T`
Expand Down
12 changes: 6 additions & 6 deletions examples/asset/custom_asset_io.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::{
asset::{AssetIo, AssetIoError},
asset::{AssetIo, AssetIoError, Metadata},
prelude::*,
utils::BoxedFuture,
};
Expand All @@ -26,11 +26,6 @@ impl AssetIo for CustomAssetIo {
self.0.read_directory(path)
}

fn is_directory(&self, path: &Path) -> bool {
info!("is_directory({:?})", path);
self.0.is_directory(path)
}

fn watch_path_for_changes(&self, path: &Path) -> Result<(), AssetIoError> {
info!("watch_path_for_changes({:?})", path);
self.0.watch_path_for_changes(path)
Expand All @@ -40,6 +35,11 @@ impl AssetIo for CustomAssetIo {
info!("watch_for_changes()");
self.0.watch_for_changes()
}

fn get_metadata(&self, path: &Path) -> Result<Metadata, AssetIoError> {
info!("get_metadata({:?})", path);
self.0.get_metadata(path)
}
}

/// A plugin used to execute the override of the asset io
Expand Down

0 comments on commit e29bd50

Please sign in to comment.