debian_packaging/
binary_package_list.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5/*! Interface with a collection of binary package control definitions. */
6
7use {
8    crate::binary_package_control::BinaryPackageControlFile,
9    std::ops::{Deref, DerefMut},
10};
11
12/// Represents a collection of binary package control files.
13///
14/// Various operations in Debian packaging operate against a collection of
15/// binary package control files. For example, resolving dependencies of a
16/// package requires finding packages from an available set. This type facilitates
17/// the implementation of said operations.
18#[derive(Clone, Debug, Default)]
19pub struct BinaryPackageList<'a> {
20    packages: Vec<BinaryPackageControlFile<'a>>,
21}
22
23impl<'a> Deref for BinaryPackageList<'a> {
24    type Target = Vec<BinaryPackageControlFile<'a>>;
25
26    fn deref(&self) -> &Self::Target {
27        &self.packages
28    }
29}
30
31impl<'a> DerefMut for BinaryPackageList<'a> {
32    fn deref_mut(&mut self) -> &mut Self::Target {
33        &mut self.packages
34    }
35}
36
37impl<'a> IntoIterator for BinaryPackageList<'a> {
38    type Item = BinaryPackageControlFile<'a>;
39    type IntoIter = std::vec::IntoIter<Self::Item>;
40
41    fn into_iter(self) -> Self::IntoIter {
42        self.packages.into_iter()
43    }
44}
45
46impl<'a> BinaryPackageList<'a> {
47    /// Find instances of a package within this collection.
48    pub fn find_packages_with_name(
49        &self,
50        package: String,
51    ) -> impl Iterator<Item = &BinaryPackageControlFile<'a>> {
52        self.packages
53            .iter()
54            .filter(move |cf| matches!(cf.package(), Ok(name) if name == package))
55    }
56}
57
58#[cfg(test)]
59mod test {
60    use {
61        super::*,
62        crate::{control::ControlParagraphReader, error::Result},
63        indoc::indoc,
64        std::io::Cursor,
65    };
66
67    const FOO_1_2: &str = indoc! {"
68        Package: foo
69        Version: 1.2
70        Installed-Size: 20268
71        Architecture: amd64
72    "};
73
74    const BAR_1_0: &str = indoc! {"
75        Package: bar
76        Version: 1.0
77        Architecture: amd64
78        Depends: foo (>= 1.2)
79    "};
80
81    const BAZ_1_1: &str = indoc! {"
82        Package: baz
83        Version: 1.1
84        Architecture: amd64
85        Depends: bar (>= 1.0)
86    "};
87
88    #[test]
89    fn find_package() -> Result<()> {
90        let foo_para = ControlParagraphReader::new(Cursor::new(FOO_1_2.as_bytes()))
91            .next()
92            .unwrap()?;
93
94        let bar_para = ControlParagraphReader::new(Cursor::new(BAR_1_0.as_bytes()))
95            .next()
96            .unwrap()?;
97
98        let baz_para = ControlParagraphReader::new(Cursor::new(BAZ_1_1.as_bytes()))
99            .next()
100            .unwrap()?;
101
102        let mut l = BinaryPackageList::default();
103        l.push(BinaryPackageControlFile::from(foo_para));
104        l.push(BinaryPackageControlFile::from(bar_para));
105        l.push(BinaryPackageControlFile::from(baz_para));
106
107        assert_eq!(l.find_packages_with_name("other".into()).count(), 0);
108
109        let packages = l.find_packages_with_name("foo".into()).collect::<Vec<_>>();
110        assert_eq!(packages.len(), 1);
111        assert_eq!(packages[0].version_str()?, "1.2");
112
113        let packages = l.find_packages_with_name("bar".into()).collect::<Vec<_>>();
114        assert_eq!(packages.len(), 1);
115
116        Ok(())
117    }
118}