1use std::str::FromStr;
3
4#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
6pub enum Priority {
7 Required,
9
10 Important,
12
13 Standard,
15
16 Optional,
18
19 Extra,
21}
22
23impl std::fmt::Display for Priority {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 f.write_str(match self {
26 Priority::Required => "required",
27 Priority::Important => "important",
28 Priority::Standard => "standard",
29 Priority::Optional => "optional",
30 Priority::Extra => "extra",
31 })
32 }
33}
34
35impl std::str::FromStr for Priority {
36 type Err = String;
37
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
39 match s {
40 "required" => Ok(Priority::Required),
41 "important" => Ok(Priority::Important),
42 "standard" => Ok(Priority::Standard),
43 "optional" => Ok(Priority::Optional),
44 "extra" => Ok(Priority::Extra),
45 _ => Err(format!("Invalid priority: {}", s)),
46 }
47 }
48}
49
50pub trait Checksum {
52 fn filename(&self) -> &str;
54
55 fn size(&self) -> usize;
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
61pub struct Sha1Checksum {
62 pub sha1: String,
64
65 pub size: usize,
67
68 pub filename: String,
70}
71
72impl Checksum for Sha1Checksum {
73 fn filename(&self) -> &str {
74 &self.filename
75 }
76
77 fn size(&self) -> usize {
78 self.size
79 }
80}
81
82impl std::fmt::Display for Sha1Checksum {
83 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
84 write!(f, "{} {} {}", self.sha1, self.size, self.filename)
85 }
86}
87
88impl std::str::FromStr for Sha1Checksum {
89 type Err = String;
90
91 fn from_str(s: &str) -> Result<Self, Self::Err> {
92 let mut parts = s.split_whitespace();
93 let sha1 = parts.next().ok_or_else(|| "Missing sha1".to_string())?;
94 let size = parts
95 .next()
96 .ok_or_else(|| "Missing size".to_string())?
97 .parse()
98 .map_err(|e: std::num::ParseIntError| e.to_string())?;
99 let filename = parts
100 .next()
101 .ok_or_else(|| "Missing filename".to_string())?
102 .to_string();
103 Ok(Self {
104 sha1: sha1.to_string(),
105 size,
106 filename,
107 })
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
113pub struct Sha256Checksum {
114 pub sha256: String,
116
117 pub size: usize,
119
120 pub filename: String,
122}
123
124impl Checksum for Sha256Checksum {
125 fn filename(&self) -> &str {
126 &self.filename
127 }
128
129 fn size(&self) -> usize {
130 self.size
131 }
132}
133
134impl std::fmt::Display for Sha256Checksum {
135 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136 write!(f, "{} {} {}", self.sha256, self.size, self.filename)
137 }
138}
139
140impl std::str::FromStr for Sha256Checksum {
141 type Err = String;
142
143 fn from_str(s: &str) -> Result<Self, Self::Err> {
144 let mut parts = s.split_whitespace();
145 let sha256 = parts.next().ok_or_else(|| "Missing sha256".to_string())?;
146 let size = parts
147 .next()
148 .ok_or_else(|| "Missing size".to_string())?
149 .parse()
150 .map_err(|e: std::num::ParseIntError| e.to_string())?;
151 let filename = parts
152 .next()
153 .ok_or_else(|| "Missing filename".to_string())?
154 .to_string();
155 Ok(Self {
156 sha256: sha256.to_string(),
157 size,
158 filename,
159 })
160 }
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
165pub struct Sha512Checksum {
166 pub sha512: String,
168
169 pub size: usize,
171
172 pub filename: String,
174}
175
176impl Checksum for Sha512Checksum {
177 fn filename(&self) -> &str {
178 &self.filename
179 }
180
181 fn size(&self) -> usize {
182 self.size
183 }
184}
185
186impl std::fmt::Display for Sha512Checksum {
187 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
188 write!(f, "{} {} {}", self.sha512, self.size, self.filename)
189 }
190}
191
192impl std::str::FromStr for Sha512Checksum {
193 type Err = String;
194
195 fn from_str(s: &str) -> Result<Self, Self::Err> {
196 let mut parts = s.split_whitespace();
197 let sha512 = parts.next().ok_or_else(|| "Missing sha512".to_string())?;
198 let size = parts
199 .next()
200 .ok_or_else(|| "Missing size".to_string())?
201 .parse()
202 .map_err(|e: std::num::ParseIntError| e.to_string())?;
203 let filename = parts
204 .next()
205 .ok_or_else(|| "Missing filename".to_string())?
206 .to_string();
207 Ok(Self {
208 sha512: sha512.to_string(),
209 size,
210 filename,
211 })
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
217pub struct Md5Checksum {
218 pub md5sum: String,
220 pub size: usize,
222 pub filename: String,
224}
225
226impl std::fmt::Display for Md5Checksum {
227 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
228 write!(f, "{} {} {}", self.md5sum, self.size, self.filename)
229 }
230}
231
232impl std::str::FromStr for Md5Checksum {
233 type Err = ();
234
235 fn from_str(s: &str) -> Result<Self, Self::Err> {
236 let mut parts = s.split_whitespace();
237 let md5sum = parts.next().ok_or(())?;
238 let size = parts.next().ok_or(())?.parse().map_err(|_| ())?;
239 let filename = parts.next().ok_or(())?.to_string();
240 Ok(Self {
241 md5sum: md5sum.to_string(),
242 size,
243 filename,
244 })
245 }
246}
247
248impl Checksum for Md5Checksum {
249 fn filename(&self) -> &str {
250 &self.filename
251 }
252
253 fn size(&self) -> usize {
254 self.size
255 }
256}
257
258#[derive(Debug, Clone, PartialEq, Eq)]
260pub struct PackageListEntry {
261 pub package: String,
263
264 pub package_type: String,
266
267 pub section: String,
269
270 pub priority: Priority,
272
273 pub extra: std::collections::HashMap<String, String>,
275}
276
277impl PackageListEntry {
278 pub fn new(package: &str, package_type: &str, section: &str, priority: Priority) -> Self {
280 Self {
281 package: package.to_string(),
282 package_type: package_type.to_string(),
283 section: section.to_string(),
284 priority,
285 extra: std::collections::HashMap::new(),
286 }
287 }
288}
289
290impl std::fmt::Display for PackageListEntry {
291 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
292 write!(
293 f,
294 "{} {} {} {}",
295 self.package, self.package_type, self.section, self.priority
296 )?;
297 for (k, v) in &self.extra {
298 write!(f, " {}={}", k, v)?;
299 }
300 Ok(())
301 }
302}
303
304impl std::str::FromStr for PackageListEntry {
305 type Err = String;
306
307 fn from_str(s: &str) -> Result<Self, Self::Err> {
308 let mut parts = s.split_whitespace();
309 let package = parts
310 .next()
311 .ok_or_else(|| "Missing package".to_string())?
312 .to_string();
313 let package_type = parts
314 .next()
315 .ok_or_else(|| "Missing package type".to_string())?
316 .to_string();
317 let section = parts
318 .next()
319 .ok_or_else(|| "Missing section".to_string())?
320 .to_string();
321 let priority = parts
322 .next()
323 .ok_or_else(|| "Missing priority".to_string())?
324 .parse()?;
325 let mut extra = std::collections::HashMap::new();
326 for part in parts {
327 let mut kv = part.split('=');
328 let k = kv
329 .next()
330 .ok_or_else(|| "Missing key".to_string())?
331 .to_string();
332 let v = kv
333 .next()
334 .ok_or_else(|| "Missing value".to_string())?
335 .to_string();
336 extra.insert(k, v);
337 }
338 Ok(Self {
339 package,
340 package_type,
341 section,
342 priority,
343 extra,
344 })
345 }
346}
347
348#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
350pub enum Urgency {
351 #[default]
353 Low,
354 Medium,
356 High,
358 Emergency,
360 Critical,
362}
363
364impl std::fmt::Display for Urgency {
365 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
366 match self {
367 Urgency::Low => f.write_str("low"),
368 Urgency::Medium => f.write_str("medium"),
369 Urgency::High => f.write_str("high"),
370 Urgency::Emergency => f.write_str("emergency"),
371 Urgency::Critical => f.write_str("critical"),
372 }
373 }
374}
375
376impl FromStr for Urgency {
377 type Err = String;
378
379 fn from_str(s: &str) -> Result<Self, Self::Err> {
380 match s.to_lowercase().as_str() {
381 "low" => Ok(Urgency::Low),
382 "medium" => Ok(Urgency::Medium),
383 "high" => Ok(Urgency::High),
384 "emergency" => Ok(Urgency::Emergency),
385 "critical" => Ok(Urgency::Critical),
386 _ => Err(format!("invalid urgency: {}", s)),
387 }
388 }
389}
390
391#[derive(PartialEq, Eq, Debug, Default)]
393pub enum MultiArch {
394 Same,
396 Foreign,
398 #[default]
400 No,
401 Allowed,
403}
404
405impl std::str::FromStr for MultiArch {
406 type Err = String;
407
408 fn from_str(s: &str) -> Result<Self, Self::Err> {
409 match s {
410 "same" => Ok(MultiArch::Same),
411 "foreign" => Ok(MultiArch::Foreign),
412 "no" => Ok(MultiArch::No),
413 "allowed" => Ok(MultiArch::Allowed),
414 _ => Err(format!("Invalid multiarch: {}", s)),
415 }
416 }
417}
418
419impl std::fmt::Display for MultiArch {
420 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
421 f.write_str(match self {
422 MultiArch::Same => "same",
423 MultiArch::Foreign => "foreign",
424 MultiArch::No => "no",
425 MultiArch::Allowed => "allowed",
426 })
427 }
428}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433
434 #[test]
435 fn test_sha1_checksum_filename() {
436 let checksum = Sha1Checksum {
437 sha1: "abc123".to_string(),
438 size: 1234,
439 filename: "test.deb".to_string(),
440 };
441 assert_eq!(checksum.filename(), "test.deb".to_string());
442 }
443
444 #[test]
445 fn test_md5_checksum_filename() {
446 let checksum = Md5Checksum {
447 md5sum: "abc123".to_string(),
448 size: 1234,
449 filename: "test.deb".to_string(),
450 };
451 assert_eq!(checksum.filename(), "test.deb".to_string());
452 }
453
454 #[test]
455 fn test_sha256_checksum_filename() {
456 let checksum = Sha256Checksum {
457 sha256: "abc123".to_string(),
458 size: 1234,
459 filename: "test.deb".to_string(),
460 };
461 assert_eq!(checksum.filename(), "test.deb".to_string());
462 }
463
464 #[test]
465 fn test_sha512_checksum_filename() {
466 let checksum = Sha512Checksum {
467 sha512: "abc123".to_string(),
468 size: 1234,
469 filename: "test.deb".to_string(),
470 };
471 assert_eq!(checksum.filename(), "test.deb".to_string());
472 }
473}