Path: blob/main/crates/bevy_asset/src/io/file/file_asset.rs
6601 views
use crate::io::{1get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, AsyncSeekForward,2PathStream, Reader, Writer,3};4use async_fs::{read_dir, File};5use futures_io::AsyncSeek;6use futures_lite::StreamExt;78use alloc::{borrow::ToOwned, boxed::Box};9use core::{pin::Pin, task, task::Poll};10use std::path::Path;1112use super::{FileAssetReader, FileAssetWriter};1314impl AsyncSeekForward for File {15fn poll_seek_forward(16mut self: Pin<&mut Self>,17cx: &mut task::Context<'_>,18offset: u64,19) -> Poll<futures_io::Result<u64>> {20let offset: Result<i64, _> = offset.try_into();2122if let Ok(offset) = offset {23Pin::new(&mut self).poll_seek(cx, futures_io::SeekFrom::Current(offset))24} else {25Poll::Ready(Err(std::io::Error::new(26std::io::ErrorKind::InvalidInput,27"seek position is out of range",28)))29}30}31}3233impl Reader for File {}3435impl AssetReader for FileAssetReader {36async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {37let full_path = self.root_path.join(path);38File::open(&full_path).await.map_err(|e| {39if e.kind() == std::io::ErrorKind::NotFound {40AssetReaderError::NotFound(full_path)41} else {42e.into()43}44})45}4647async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {48let meta_path = get_meta_path(path);49let full_path = self.root_path.join(meta_path);50File::open(&full_path).await.map_err(|e| {51if e.kind() == std::io::ErrorKind::NotFound {52AssetReaderError::NotFound(full_path)53} else {54e.into()55}56})57}5859async fn read_directory<'a>(60&'a self,61path: &'a Path,62) -> Result<Box<PathStream>, AssetReaderError> {63let full_path = self.root_path.join(path);64match read_dir(&full_path).await {65Ok(read_dir) => {66let root_path = self.root_path.clone();67let mapped_stream = read_dir.filter_map(move |f| {68f.ok().and_then(|dir_entry| {69let path = dir_entry.path();70// filter out meta files as they are not considered assets71if let Some(ext) = path.extension().and_then(|e| e.to_str())72&& ext.eq_ignore_ascii_case("meta")73{74return None;75}76// filter out hidden files. they are not listed by default but are directly targetable77if path78.file_name()79.and_then(|file_name| file_name.to_str())80.map(|file_name| file_name.starts_with('.'))81.unwrap_or_default()82{83return None;84}85let relative_path = path.strip_prefix(&root_path).unwrap();86Some(relative_path.to_owned())87})88});89let read_dir: Box<PathStream> = Box::new(mapped_stream);90Ok(read_dir)91}92Err(e) => {93if e.kind() == std::io::ErrorKind::NotFound {94Err(AssetReaderError::NotFound(full_path))95} else {96Err(e.into())97}98}99}100}101102async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {103let full_path = self.root_path.join(path);104let metadata = full_path105.metadata()106.map_err(|_e| AssetReaderError::NotFound(path.to_owned()))?;107Ok(metadata.file_type().is_dir())108}109}110111impl AssetWriter for FileAssetWriter {112async fn write<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {113let full_path = self.root_path.join(path);114if let Some(parent) = full_path.parent() {115async_fs::create_dir_all(parent).await?;116}117let file = File::create(&full_path).await?;118let writer: Box<Writer> = Box::new(file);119Ok(writer)120}121122async fn write_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {123let meta_path = get_meta_path(path);124let full_path = self.root_path.join(meta_path);125if let Some(parent) = full_path.parent() {126async_fs::create_dir_all(parent).await?;127}128let file = File::create(&full_path).await?;129let writer: Box<Writer> = Box::new(file);130Ok(writer)131}132133async fn remove<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {134let full_path = self.root_path.join(path);135async_fs::remove_file(full_path).await?;136Ok(())137}138139async fn remove_meta<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {140let meta_path = get_meta_path(path);141let full_path = self.root_path.join(meta_path);142async_fs::remove_file(full_path).await?;143Ok(())144}145146async fn rename<'a>(147&'a self,148old_path: &'a Path,149new_path: &'a Path,150) -> Result<(), AssetWriterError> {151let full_old_path = self.root_path.join(old_path);152let full_new_path = self.root_path.join(new_path);153if let Some(parent) = full_new_path.parent() {154async_fs::create_dir_all(parent).await?;155}156async_fs::rename(full_old_path, full_new_path).await?;157Ok(())158}159160async fn rename_meta<'a>(161&'a self,162old_path: &'a Path,163new_path: &'a Path,164) -> Result<(), AssetWriterError> {165let old_meta_path = get_meta_path(old_path);166let new_meta_path = get_meta_path(new_path);167let full_old_path = self.root_path.join(old_meta_path);168let full_new_path = self.root_path.join(new_meta_path);169if let Some(parent) = full_new_path.parent() {170async_fs::create_dir_all(parent).await?;171}172async_fs::rename(full_old_path, full_new_path).await?;173Ok(())174}175176async fn create_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {177let full_path = self.root_path.join(path);178async_fs::create_dir_all(full_path).await?;179Ok(())180}181182async fn remove_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {183let full_path = self.root_path.join(path);184async_fs::remove_dir_all(full_path).await?;185Ok(())186}187188async fn remove_empty_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {189let full_path = self.root_path.join(path);190async_fs::remove_dir(full_path).await?;191Ok(())192}193194async fn remove_assets_in_directory<'a>(195&'a self,196path: &'a Path,197) -> Result<(), AssetWriterError> {198let full_path = self.root_path.join(path);199async_fs::remove_dir_all(&full_path).await?;200async_fs::create_dir_all(&full_path).await?;201Ok(())202}203}204205206