Path: blob/main/crates/bevy_asset/src/io/file/sync_file_asset.rs
6601 views
use futures_io::{AsyncRead, AsyncWrite};1use futures_lite::Stream;23use crate::io::{4get_meta_path, AssetReader, AssetReaderError, AssetWriter, AssetWriterError, AsyncSeekForward,5PathStream, Reader, Writer,6};78use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};9use core::{pin::Pin, task::Poll};10use std::{11fs::{read_dir, File},12io::{Read, Seek, Write},13path::{Path, PathBuf},14};1516use super::{FileAssetReader, FileAssetWriter};1718struct FileReader(File);1920impl AsyncRead for FileReader {21fn poll_read(22self: Pin<&mut Self>,23_cx: &mut core::task::Context<'_>,24buf: &mut [u8],25) -> Poll<std::io::Result<usize>> {26let this = self.get_mut();27let read = this.0.read(buf);28Poll::Ready(read)29}30}3132impl AsyncSeekForward for FileReader {33fn poll_seek_forward(34self: Pin<&mut Self>,35_cx: &mut core::task::Context<'_>,36offset: u64,37) -> Poll<std::io::Result<u64>> {38let this = self.get_mut();39let current = this.0.stream_position()?;40let seek = this.0.seek(std::io::SeekFrom::Start(current + offset));4142Poll::Ready(seek)43}44}4546impl Reader for FileReader {47fn read_to_end<'a>(48&'a mut self,49buf: &'a mut Vec<u8>,50) -> stackfuture::StackFuture<'a, std::io::Result<usize>, { crate::io::STACK_FUTURE_SIZE }>51{52stackfuture::StackFuture::from(async { self.0.read_to_end(buf) })53}54}5556struct FileWriter(File);5758impl AsyncWrite for FileWriter {59fn poll_write(60self: Pin<&mut Self>,61_cx: &mut core::task::Context<'_>,62buf: &[u8],63) -> Poll<std::io::Result<usize>> {64let this = self.get_mut();65let wrote = this.0.write(buf);66Poll::Ready(wrote)67}6869fn poll_flush(70self: Pin<&mut Self>,71_cx: &mut core::task::Context<'_>,72) -> Poll<std::io::Result<()>> {73let this = self.get_mut();74let flushed = this.0.flush();75Poll::Ready(flushed)76}7778fn poll_close(79self: Pin<&mut Self>,80_cx: &mut core::task::Context<'_>,81) -> Poll<std::io::Result<()>> {82Poll::Ready(Ok(()))83}84}8586struct DirReader(Vec<PathBuf>);8788impl Stream for DirReader {89type Item = PathBuf;9091fn poll_next(92self: Pin<&mut Self>,93_cx: &mut core::task::Context<'_>,94) -> Poll<Option<Self::Item>> {95let this = self.get_mut();96Poll::Ready(this.0.pop())97}98}99100impl AssetReader for FileAssetReader {101async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {102let full_path = self.root_path.join(path);103match File::open(&full_path) {104Ok(file) => Ok(FileReader(file)),105Err(e) => {106if e.kind() == std::io::ErrorKind::NotFound {107Err(AssetReaderError::NotFound(full_path))108} else {109Err(e.into())110}111}112}113}114115async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {116let meta_path = get_meta_path(path);117let full_path = self.root_path.join(meta_path);118match File::open(&full_path) {119Ok(file) => Ok(FileReader(file)),120Err(e) => {121if e.kind() == std::io::ErrorKind::NotFound {122Err(AssetReaderError::NotFound(full_path))123} else {124Err(e.into())125}126}127}128}129130async fn read_directory<'a>(131&'a self,132path: &'a Path,133) -> Result<Box<PathStream>, AssetReaderError> {134let full_path = self.root_path.join(path);135match read_dir(&full_path) {136Ok(read_dir) => {137let root_path = self.root_path.clone();138let mapped_stream = read_dir.filter_map(move |f| {139f.ok().and_then(|dir_entry| {140let path = dir_entry.path();141// filter out meta files as they are not considered assets142if let Some(ext) = path.extension().and_then(|e| e.to_str())143&& ext.eq_ignore_ascii_case("meta")144{145return None;146}147// filter out hidden files. they are not listed by default but are directly targetable148if path149.file_name()150.and_then(|file_name| file_name.to_str())151.map(|file_name| file_name.starts_with('.'))152.unwrap_or_default()153{154return None;155}156157let relative_path = path.strip_prefix(&root_path).unwrap();158Some(relative_path.to_owned())159})160});161let read_dir: Box<PathStream> = Box::new(DirReader(mapped_stream.collect()));162Ok(read_dir)163}164Err(e) => {165if e.kind() == std::io::ErrorKind::NotFound {166Err(AssetReaderError::NotFound(full_path))167} else {168Err(e.into())169}170}171}172}173174async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {175let full_path = self.root_path.join(path);176let metadata = full_path177.metadata()178.map_err(|_e| AssetReaderError::NotFound(path.to_owned()))?;179Ok(metadata.file_type().is_dir())180}181}182183impl AssetWriter for FileAssetWriter {184async fn write<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {185let full_path = self.root_path.join(path);186if let Some(parent) = full_path.parent() {187std::fs::create_dir_all(parent)?;188}189let file = File::create(&full_path)?;190let writer: Box<Writer> = Box::new(FileWriter(file));191Ok(writer)192}193194async fn write_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Writer>, AssetWriterError> {195let meta_path = get_meta_path(path);196let full_path = self.root_path.join(meta_path);197if let Some(parent) = full_path.parent() {198std::fs::create_dir_all(parent)?;199}200let file = File::create(&full_path)?;201let writer: Box<Writer> = Box::new(FileWriter(file));202Ok(writer)203}204205async fn remove<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {206let full_path = self.root_path.join(path);207std::fs::remove_file(full_path)?;208Ok(())209}210211async fn remove_meta<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {212let meta_path = get_meta_path(path);213let full_path = self.root_path.join(meta_path);214std::fs::remove_file(full_path)?;215Ok(())216}217218async fn create_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {219let full_path = self.root_path.join(path);220std::fs::create_dir_all(full_path)?;221Ok(())222}223224async fn remove_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {225let full_path = self.root_path.join(path);226std::fs::remove_dir_all(full_path)?;227Ok(())228}229230async fn remove_empty_directory<'a>(&'a self, path: &'a Path) -> Result<(), AssetWriterError> {231let full_path = self.root_path.join(path);232std::fs::remove_dir(full_path)?;233Ok(())234}235236async fn remove_assets_in_directory<'a>(237&'a self,238path: &'a Path,239) -> Result<(), AssetWriterError> {240let full_path = self.root_path.join(path);241std::fs::remove_dir_all(&full_path)?;242std::fs::create_dir_all(&full_path)?;243Ok(())244}245246async fn rename<'a>(247&'a self,248old_path: &'a Path,249new_path: &'a Path,250) -> Result<(), AssetWriterError> {251let full_old_path = self.root_path.join(old_path);252let full_new_path = self.root_path.join(new_path);253if let Some(parent) = full_new_path.parent() {254std::fs::create_dir_all(parent)?;255}256std::fs::rename(full_old_path, full_new_path)?;257Ok(())258}259260async fn rename_meta<'a>(261&'a self,262old_path: &'a Path,263new_path: &'a Path,264) -> Result<(), AssetWriterError> {265let old_meta_path = get_meta_path(old_path);266let new_meta_path = get_meta_path(new_path);267let full_old_path = self.root_path.join(old_meta_path);268let full_new_path = self.root_path.join(new_meta_path);269if let Some(parent) = full_new_path.parent() {270std::fs::create_dir_all(parent)?;271}272std::fs::rename(full_old_path, full_new_path)?;273Ok(())274}275}276277278