fuchsia_archive/
async_utf8_reader.rs
1use crate::error::Error;
6use fuchsia_fs::file::{AsyncGetSize, AsyncReadAt};
7
8#[derive(Debug)]
11pub struct AsyncUtf8Reader<T>
12where
13 T: AsyncReadAt + AsyncGetSize + Unpin,
14{
15 reader: crate::async_read::AsyncReader<T>,
16}
17
18impl<T> AsyncUtf8Reader<T>
19where
20 T: AsyncReadAt + AsyncGetSize + Unpin,
21{
22 pub async fn new(source: T) -> Result<Self, Error> {
24 let ret = Self { reader: crate::async_read::AsyncReader::new(source).await? };
25 let () = ret.try_list().try_for_each(|r| r.map(|_| ()))?;
26 Ok(ret)
27 }
28
29 fn try_list(&self) -> impl ExactSizeIterator<Item = Result<crate::Utf8Entry<'_>, Error>> {
32 self.reader.list().map(|e| {
33 Ok(crate::Utf8Entry {
34 path: std::str::from_utf8(e.path).map_err(|err| Error::PathDataInvalidUtf8 {
35 source: err,
36 path: e.path.into(),
37 })?,
38 offset: e.offset,
39 length: e.length,
40 })
41 })
42 }
43
44 pub fn list(&self) -> impl ExactSizeIterator<Item = crate::Utf8Entry<'_>> {
46 self.try_list().map(|r| {
47 r.expect("AsyncUtf8Reader::new only succeeds if try_list succeeds for every element")
48 })
49 }
50
51 pub async fn read_file(&mut self, path: &str) -> Result<Vec<u8>, Error> {
54 self.reader.read_file(path.as_bytes()).await
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use assert_matches::assert_matches;
62 use fuchsia_async as fasync;
63 use fuchsia_fs::file::Adapter;
64 use futures::io::Cursor;
65
66 #[fasync::run_singlethreaded(test)]
67 async fn new_rejects_non_utf8_path() {
68 let mut far_bytes = vec![];
69 let () = crate::write::write(
70 &mut far_bytes,
71 std::collections::BTreeMap::from_iter([(
72 b"\xff",
73 (0, Box::new("".as_bytes()) as Box<dyn std::io::Read>),
74 )]),
75 )
76 .unwrap();
77
78 assert_matches!(
79 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes))).await,
80 Err(crate::Error::PathDataInvalidUtf8{source: _, path}) if path == b"\xff".to_vec()
81 );
82 }
83
84 #[fasync::run_singlethreaded(test)]
85 async fn list_does_not_panic() {
86 let mut far_bytes = vec![];
87 let () = crate::write::write(
88 &mut far_bytes,
89 std::collections::BTreeMap::from_iter([(
90 "valid-utf8",
91 (0, Box::new("".as_bytes()) as Box<dyn std::io::Read>),
92 )]),
93 )
94 .unwrap();
95
96 itertools::assert_equal(
97 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes))).await.unwrap().list(),
98 [crate::Utf8Entry { path: "valid-utf8", offset: 4096, length: 0 }],
99 );
100 }
101
102 #[fasync::run_singlethreaded(test)]
103 async fn read_file() {
104 let mut far_bytes = vec![];
105 let () = crate::write::write(
106 &mut far_bytes,
107 std::collections::BTreeMap::from_iter([(
108 "valid-utf8",
109 (12, Box::new("test-content".as_bytes()) as Box<dyn std::io::Read>),
110 )]),
111 )
112 .unwrap();
113
114 assert_eq!(
115 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes)))
116 .await
117 .unwrap()
118 .read_file("valid-utf8")
119 .await
120 .unwrap(),
121 b"test-content".to_vec()
122 );
123 }
124}