debian_packaging/repository/
contents.rs1use {
8 crate::error::Result,
9 futures::{AsyncBufRead, AsyncBufReadExt},
10 pin_project::pin_project,
11 std::{
12 collections::{BTreeMap, BTreeSet},
13 io::{BufRead, Write},
14 },
15};
16
17#[derive(Clone, Debug, Default)]
25pub struct ContentsFile {
26 paths: BTreeMap<String, BTreeSet<String>>,
28 packages: BTreeMap<String, BTreeSet<String>>,
30}
31
32impl ContentsFile {
33 fn parse_and_add_line(&mut self, line: &str) -> Result<()> {
34 let words = line.split_ascii_whitespace().collect::<Vec<_>>();
39
40 if words.len() != 2 {
41 return Ok(());
42 }
43
44 let path = words[0];
45 let packages = words[1];
46
47 for package in packages.split(',') {
48 self.paths
49 .entry(path.to_string())
50 .or_default()
51 .insert(package.to_string());
52 self.packages
53 .entry(package.to_string())
54 .or_default()
55 .insert(path.to_string());
56 }
57
58 Ok(())
59 }
60
61 pub fn add_package_path(&mut self, path: String, package: String) {
63 self.paths
64 .entry(path.clone())
65 .or_default()
66 .insert(package.clone());
67 self.packages.entry(package).or_default().insert(path);
68 }
69
70 pub fn packages_with_path(&self, path: &str) -> Box<dyn Iterator<Item = &str> + '_> {
72 if let Some(packages) = self.paths.get(path) {
73 Box::new(packages.iter().map(|x| x.as_str()))
74 } else {
75 Box::new(std::iter::empty())
76 }
77 }
78
79 pub fn package_paths(&self, package: &str) -> Box<dyn Iterator<Item = &str> + '_> {
81 if let Some(paths) = self.packages.get(package) {
82 Box::new(paths.iter().map(|x| x.as_str()))
83 } else {
84 Box::new(std::iter::empty())
85 }
86 }
87
88 pub fn as_lines(&self) -> impl Iterator<Item = String> + '_ {
90 self.paths.iter().map(|(path, packages)| {
91 let packages = packages.iter().map(|s| s.as_str()).collect::<Vec<_>>();
93
94 format!("{} {}\n", path, packages.join(",'"))
95 })
96 }
97
98 pub fn write_to(&self, writer: &mut impl Write) -> Result<usize> {
102 let mut bytes_count = 0;
103
104 for line in self.as_lines() {
105 writer.write_all(line.as_bytes())?;
106 bytes_count += line.as_bytes().len();
107 }
108
109 Ok(bytes_count)
110 }
111}
112
113#[derive(Clone, Debug)]
114pub struct ContentsFileReader<R> {
115 reader: R,
116 contents: ContentsFile,
117}
118
119impl<R: BufRead> ContentsFileReader<R> {
120 pub fn new(reader: R) -> Self {
122 Self {
123 reader,
124 contents: ContentsFile::default(),
125 }
126 }
127
128 pub fn into_inner(self) -> R {
130 self.reader
131 }
132
133 pub fn read_all(&mut self) -> Result<usize> {
135 let mut bytes_read = 0;
136
137 while let Ok(read_size) = self.read_line() {
138 if read_size == 0 {
139 break;
140 }
141
142 bytes_read += read_size;
143 }
144
145 Ok(bytes_read)
146 }
147
148 pub fn read_line(&mut self) -> Result<usize> {
150 let mut line = String::new();
151 let read_size = self.reader.read_line(&mut line)?;
152
153 if read_size != 0 {
154 self.contents.parse_and_add_line(&line)?;
155 }
156
157 Ok(read_size)
158 }
159
160 pub fn consume(self) -> (ContentsFile, R) {
162 (self.contents, self.reader)
163 }
164}
165
166#[pin_project]
167pub struct ContentsFileAsyncReader<R> {
168 #[pin]
169 reader: R,
170 contents: ContentsFile,
171}
172
173impl<R> ContentsFileAsyncReader<R>
174where
175 R: AsyncBufRead + Unpin,
176{
177 pub fn new(reader: R) -> Self {
179 Self {
180 reader,
181 contents: ContentsFile::default(),
182 }
183 }
184
185 pub fn into_inner(self) -> R {
187 self.reader
188 }
189
190 pub async fn read_all(&mut self) -> Result<usize> {
192 let mut bytes_read = 0;
193
194 while let Ok(read_size) = self.read_line().await {
195 if read_size == 0 {
196 break;
197 }
198
199 bytes_read += read_size;
200 }
201
202 Ok(bytes_read)
203 }
204
205 pub async fn read_line(&mut self) -> Result<usize> {
207 let mut line = String::new();
208 let read_size = self.reader.read_line(&mut line).await?;
209
210 if read_size != 0 {
211 self.contents.parse_and_add_line(&line)?;
212 }
213
214 Ok(read_size)
215 }
216
217 pub fn consume(self) -> (ContentsFile, R) {
219 (self.contents, self.reader)
220 }
221}