1use crate::io::{AssetReader, AssetReaderError, PathStream, Reader};
2use bevy_utils::HashMap;
3use crossbeam_channel::{Receiver, Sender};
4use parking_lot::RwLock;
5use std::{path::Path, sync::Arc};
6
7pub struct GatedReader<R: AssetReader> {
12 reader: R,
13 gates: Arc<RwLock<HashMap<Box<Path>, (Sender<()>, Receiver<()>)>>>,
14}
15
16impl<R: AssetReader + Clone> Clone for GatedReader<R> {
17 fn clone(&self) -> Self {
18 Self {
19 reader: self.reader.clone(),
20 gates: self.gates.clone(),
21 }
22 }
23}
24
25pub struct GateOpener {
27 gates: Arc<RwLock<HashMap<Box<Path>, (Sender<()>, Receiver<()>)>>>,
28}
29
30impl GateOpener {
31 pub fn open<P: AsRef<Path>>(&self, path: P) {
34 let mut gates = self.gates.write();
35 let gates = gates
36 .entry_ref(path.as_ref())
37 .or_insert_with(crossbeam_channel::unbounded);
38 gates.0.send(()).unwrap();
39 }
40}
41
42impl<R: AssetReader> GatedReader<R> {
43 pub fn new(reader: R) -> (Self, GateOpener) {
46 let gates = Arc::new(RwLock::new(HashMap::new()));
47 (
48 Self {
49 reader,
50 gates: gates.clone(),
51 },
52 GateOpener { gates },
53 )
54 }
55}
56
57impl<R: AssetReader> AssetReader for GatedReader<R> {
58 async fn read<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
59 let receiver = {
60 let mut gates = self.gates.write();
61 let gates = gates
62 .entry_ref(path.as_ref())
63 .or_insert_with(crossbeam_channel::unbounded);
64 gates.1.clone()
65 };
66 receiver.recv().unwrap();
67 let result = self.reader.read(path).await?;
68 Ok(result)
69 }
70
71 async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<Box<Reader<'a>>, AssetReaderError> {
72 self.reader.read_meta(path).await
73 }
74
75 async fn read_directory<'a>(
76 &'a self,
77 path: &'a Path,
78 ) -> Result<Box<PathStream>, AssetReaderError> {
79 self.reader.read_directory(path).await
80 }
81
82 async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {
83 self.reader.is_directory(path).await
84 }
85}