bevy_asset/io/
processor_gated.rs1use crate::{
7 io::{
8 AssetReader, AssetReaderError, AssetSourceId, PathStream, Reader, ReaderNotSeekableError,
9 SeekableReader,
10 },
11 processor::{ProcessStatus, ProcessingState},
12 AssetPath,
13};
14use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec::Vec};
15use async_lock::RwLockReadGuardArc;
16use core::{pin::Pin, task::Poll};
17use futures_io::AsyncRead;
18use std::path::Path;
19use tracing::trace;
20
21use super::ErasedAssetReader;
22
23pub(crate) struct ProcessorGatedReader {
28 reader: Arc<dyn ErasedAssetReader>,
29 source: AssetSourceId<'static>,
30 processing_state: Arc<ProcessingState>,
31}
32
33impl ProcessorGatedReader {
34 pub(crate) fn new(
36 source: AssetSourceId<'static>,
37 reader: Arc<dyn ErasedAssetReader>,
38 processing_state: Arc<ProcessingState>,
39 ) -> Self {
40 Self {
41 source,
42 reader,
43 processing_state,
44 }
45 }
46}
47
48impl AssetReader for ProcessorGatedReader {
49 async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
50 let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone());
51 trace!("Waiting for processing to finish before reading {asset_path}");
52 let process_result = self
53 .processing_state
54 .wait_until_processed(asset_path.clone())
55 .await;
56 match process_result {
57 ProcessStatus::Processed => {}
58 ProcessStatus::Failed | ProcessStatus::NonExistent => {
59 return Err(AssetReaderError::NotFound(path.to_owned()));
60 }
61 }
62 trace!("Processing finished with {asset_path}, reading {process_result:?}",);
63 let lock = self
64 .processing_state
65 .get_transaction_lock(&asset_path)
66 .await?;
67 let asset_reader = self.reader.read(path).await?;
68 let reader = TransactionLockedReader::new(asset_reader, lock);
69 Ok(reader)
70 }
71
72 async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
73 let asset_path = AssetPath::from(path.to_path_buf()).with_source(self.source.clone());
74 trace!("Waiting for processing to finish before reading meta for {asset_path}",);
75 let process_result = self
76 .processing_state
77 .wait_until_processed(asset_path.clone())
78 .await;
79 match process_result {
80 ProcessStatus::Processed => {}
81 ProcessStatus::Failed | ProcessStatus::NonExistent => {
82 return Err(AssetReaderError::NotFound(path.to_owned()));
83 }
84 }
85 trace!("Processing finished with {process_result:?}, reading meta for {asset_path}",);
86 let lock = self
87 .processing_state
88 .get_transaction_lock(&asset_path)
89 .await?;
90 let meta_reader = self.reader.read_meta(path).await?;
91 let reader = TransactionLockedReader::new(meta_reader, lock);
92 Ok(reader)
93 }
94
95 async fn read_directory<'a>(
96 &'a self,
97 path: &'a Path,
98 ) -> Result<Box<PathStream>, AssetReaderError> {
99 trace!(
100 "Waiting for processing to finish before reading directory {:?}",
101 path
102 );
103 self.processing_state.wait_until_finished().await;
104 trace!("Processing finished, reading directory {:?}", path);
105 let result = self.reader.read_directory(path).await?;
106 Ok(result)
107 }
108
109 async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {
110 trace!(
111 "Waiting for processing to finish before reading directory {:?}",
112 path
113 );
114 self.processing_state.wait_until_finished().await;
115 trace!("Processing finished, getting directory status {:?}", path);
116 let result = self.reader.is_directory(path).await?;
117 Ok(result)
118 }
119}
120
121pub struct TransactionLockedReader<'a> {
123 reader: Box<dyn Reader + 'a>,
124 _file_transaction_lock: RwLockReadGuardArc<()>,
125}
126
127impl<'a> TransactionLockedReader<'a> {
128 fn new(reader: Box<dyn Reader + 'a>, file_transaction_lock: RwLockReadGuardArc<()>) -> Self {
129 Self {
130 reader,
131 _file_transaction_lock: file_transaction_lock,
132 }
133 }
134}
135
136impl AsyncRead for TransactionLockedReader<'_> {
137 fn poll_read(
138 mut self: Pin<&mut Self>,
139 cx: &mut core::task::Context<'_>,
140 buf: &mut [u8],
141 ) -> Poll<futures_io::Result<usize>> {
142 Pin::new(&mut self.reader).poll_read(cx, buf)
143 }
144}
145
146impl Reader for TransactionLockedReader<'_> {
147 fn read_to_end<'a>(
148 &'a mut self,
149 buf: &'a mut Vec<u8>,
150 ) -> stackfuture::StackFuture<'a, std::io::Result<usize>, { super::STACK_FUTURE_SIZE }> {
151 self.reader.read_to_end(buf)
152 }
153
154 fn seekable(&mut self) -> Result<&mut dyn SeekableReader, ReaderNotSeekableError> {
155 self.reader.seekable()
156 }
157}