fuchsia_archive/
async_utf8_reader.rs1use 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 pub fn into_source(self) -> T {
58 self.reader.into_source()
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use assert_matches::assert_matches;
66 use fuchsia_async as fasync;
67 use fuchsia_fs::file::Adapter;
68 use futures::io::Cursor;
69
70 #[fasync::run_singlethreaded(test)]
71 async fn new_rejects_non_utf8_path() {
72 let mut far_bytes = vec![];
73 let () = crate::write::write(
74 &mut far_bytes,
75 std::collections::BTreeMap::from_iter([(
76 b"\xff",
77 (0, Box::new("".as_bytes()) as Box<dyn std::io::Read>),
78 )]),
79 )
80 .unwrap();
81
82 assert_matches!(
83 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes))).await,
84 Err(crate::Error::PathDataInvalidUtf8{source: _, path}) if path == b"\xff".to_vec()
85 );
86 }
87
88 #[fasync::run_singlethreaded(test)]
89 async fn list_does_not_panic() {
90 let mut far_bytes = vec![];
91 let () = crate::write::write(
92 &mut far_bytes,
93 std::collections::BTreeMap::from_iter([(
94 "valid-utf8",
95 (0, Box::new("".as_bytes()) as Box<dyn std::io::Read>),
96 )]),
97 )
98 .unwrap();
99
100 itertools::assert_equal(
101 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes))).await.unwrap().list(),
102 [crate::Utf8Entry { path: "valid-utf8", offset: 4096, length: 0 }],
103 );
104 }
105
106 #[fasync::run_singlethreaded(test)]
107 async fn read_file() {
108 let mut far_bytes = vec![];
109 let () = crate::write::write(
110 &mut far_bytes,
111 std::collections::BTreeMap::from_iter([(
112 "valid-utf8",
113 (12, Box::new("test-content".as_bytes()) as Box<dyn std::io::Read>),
114 )]),
115 )
116 .unwrap();
117
118 assert_eq!(
119 AsyncUtf8Reader::new(Adapter::new(Cursor::new(far_bytes)))
120 .await
121 .unwrap()
122 .read_file("valid-utf8")
123 .await
124 .unwrap(),
125 b"test-content".to_vec()
126 );
127 }
128}