oma_apt/iterators/
dependency.rs

1use std::cell::OnceCell;
2use std::collections::HashMap;
3use std::fmt;
4
5use cxx::UniquePtr;
6#[cfg(feature = "serde")]
7use serde::Serialize;
8
9use crate::raw::{DepIterator, VerIterator};
10use crate::{Cache, Package, Version};
11
12/// DepFlags defined in depcache.h
13#[allow(non_upper_case_globals, non_snake_case)]
14pub mod DepFlags {
15    pub const DepNow: u8 = 1;
16    pub const DepInstall: u8 = 2;
17    pub const DepCVer: u8 = 4;
18    pub const DepGNow: u8 = 8;
19    pub const DepGInstall: u8 = 16;
20    pub const DepGVer: u8 = 32;
21}
22
23#[cfg_attr(feature = "serde", derive(Serialize))]
24/// The different types of Dependencies.
25#[derive(Debug, Eq, PartialEq, Hash, Clone)]
26pub enum DepType {
27    Depends = 1,
28    PreDepends = 2,
29    Suggests = 3,
30    Recommends = 4,
31    Conflicts = 5,
32    Replaces = 6,
33    Obsoletes = 7,
34    DpkgBreaks = 8,
35    Enhances = 9,
36}
37
38impl From<u8> for DepType {
39    fn from(value: u8) -> Self {
40        match value {
41            1 => DepType::Depends,
42            2 => DepType::PreDepends,
43            3 => DepType::Suggests,
44            4 => DepType::Recommends,
45            5 => DepType::Conflicts,
46            6 => DepType::Replaces,
47            7 => DepType::Obsoletes,
48            8 => DepType::DpkgBreaks,
49            9 => DepType::Enhances,
50            _ => panic!("Dependency is malformed?"),
51        }
52    }
53}
54
55impl AsRef<str> for DepType {
56    fn as_ref(&self) -> &str {
57        self.to_str()
58    }
59}
60
61impl DepType {
62    pub fn to_str(&self) -> &'static str {
63        match self {
64            DepType::Depends => "Depends",
65            DepType::PreDepends => "PreDepends",
66            DepType::Suggests => "Suggests",
67            DepType::Recommends => "Recommends",
68            DepType::Conflicts => "Conflicts",
69            DepType::Replaces => "Replaces",
70            DepType::Obsoletes => "Obsoletes",
71            DepType::DpkgBreaks => "Breaks",
72            DepType::Enhances => "Enhances",
73        }
74    }
75}
76
77impl fmt::Display for DepType {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        write!(f, "{}", self.as_ref())
80    }
81}
82
83/// A struct representing a Base Dependency.
84pub struct BaseDep<'a> {
85    pub ptr: UniquePtr<DepIterator>,
86    cache: &'a Cache,
87    target: OnceCell<Package<'a>>,
88    parent_ver: OnceCell<UniquePtr<VerIterator>>,
89}
90
91impl Clone for BaseDep<'_> {
92    fn clone(&self) -> Self {
93        Self {
94            ptr: unsafe { self.ptr.unique() },
95            cache: self.cache,
96            target: self.target.clone(),
97            parent_ver: unsafe { self.parent_ver().into() },
98        }
99    }
100}
101
102impl<'a> BaseDep<'a> {
103    pub fn new(ptr: UniquePtr<DepIterator>, cache: &'a Cache) -> BaseDep<'a> {
104        BaseDep {
105            ptr,
106            cache,
107            target: OnceCell::new(),
108            parent_ver: OnceCell::new(),
109        }
110    }
111
112    /// This is the name of the dependency.
113    pub fn name(&self) -> &str {
114        self.target_package().name()
115    }
116
117    /// Return the target package.
118    ///
119    /// For Reverse Dependencies this will actually return the parent package
120    pub fn target_package(&self) -> &Package<'a> {
121        self.target.get_or_init(|| {
122            if self.is_reverse() {
123                Package::new(self.cache, unsafe { self.parent_pkg() })
124            } else {
125                Package::new(self.cache, unsafe { self.target_pkg() })
126            }
127        })
128    }
129
130    /// The target version &str of the dependency if specified.
131    pub fn version(&self) -> Option<&str> {
132        if self.is_reverse() {
133            Some(
134                self.parent_ver
135                    .get_or_init(|| unsafe { self.parent_ver() })
136                    .version(),
137            )
138        } else {
139            self.target_ver().ok()
140        }
141    }
142
143    /// The Dependency Type. Depends, Recommends, etc.
144    pub fn dep_type(&self) -> DepType {
145        DepType::from(self.ptr.dep_type())
146    }
147
148    /// Comparison type of the dependency version, if specified.
149    pub fn comp_type(&self) -> Option<&str> {
150        self.ptr.comp_type().ok()
151    }
152
153    // Iterate all Versions that are able to satisfy this dependency
154    pub fn all_targets(&self) -> Vec<Version<'_>> {
155        unsafe {
156            self.ptr
157                .all_targets()
158                .iter()
159                .map(|v| Version::new(v.unique(), self.cache))
160                .collect()
161        }
162    }
163}
164
165impl fmt::Display for BaseDep<'_> {
166    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167        if let (Some(comp), Some(version)) = (self.comp_type(), self.version()) {
168            write!(f, "({} {comp} {version})", self.name())
169        } else {
170            write!(f, "({})", self.name())
171        }
172    }
173}
174
175impl fmt::Debug for BaseDep<'_> {
176    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177        let parent = unsafe { self.parent_pkg() };
178        f.debug_struct("BaseDep")
179            .field("parent", &parent.name())
180            .field("name", &self.name())
181            .field("comp", &self.comp_type())
182            .field("version", &self.version())
183            .field("dep_type", &self.dep_type())
184            .field("is_reverse", &self.is_reverse())
185            .finish()
186    }
187}
188
189/// A struct representing a single Dependency record.
190///
191/// This can contain multiple Base Dependencies that can
192/// satisfy the same Dependency.
193#[derive(fmt::Debug, Clone)]
194pub struct Dependency<'a> {
195    pub(crate) ptr: Vec<BaseDep<'a>>,
196}
197
198impl<'a> Dependency<'a> {
199    /// Return the Dep Type of this group. Depends, Pre-Depends.
200    pub fn dep_type(&self) -> DepType {
201        self[0].dep_type()
202    }
203
204    /// Returns True if there are multiple dependencies that can satisfy this
205    pub fn is_or(&self) -> bool {
206        self.len() > 1
207    }
208
209    /// Returns a reference to the first BaseDep
210    pub fn first(&self) -> &BaseDep<'a> {
211        &self[0]
212    }
213}
214
215impl fmt::Display for Dependency<'_> {
216    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
217        let mut dep_str = String::new();
218
219        for (i, base_dep) in self.iter().enumerate() {
220            dep_str += &base_dep.to_string();
221            if i + 1 != self.len() {
222                dep_str += " | "
223            }
224        }
225
226        write!(
227            f,
228            "{} {:?} {dep_str}",
229            unsafe { self.first().parent_pkg().fullname(false) },
230            self.dep_type(),
231        )?;
232        Ok(())
233    }
234}
235
236pub fn create_depends_map(
237    cache: &Cache,
238    dep: Option<UniquePtr<DepIterator>>,
239) -> HashMap<DepType, Vec<Dependency<'_>>> {
240    let mut dependencies: HashMap<DepType, Vec<Dependency>> = HashMap::new();
241
242    if let Some(mut dep) = dep {
243        while !dep.end() {
244            let mut or_deps = vec![];
245            or_deps.push(BaseDep::new(unsafe { dep.unique() }, cache));
246
247            // This means that more than one thing can satisfy a dependency.
248            // For reverse dependencies we cannot get the or deps.
249            // This can cause a segfault
250            // See: https://gitlab.com/volian/rust-apt/-/merge_requests/36
251            if dep.or_dep() && !dep.is_reverse() {
252                loop {
253                    dep.pin_mut().raw_next();
254                    or_deps.push(BaseDep::new(unsafe { dep.unique() }, cache));
255                    // This is the last of the Or group
256                    if !dep.or_dep() {
257                        break;
258                    }
259                }
260            }
261
262            let dep_type = DepType::from(dep.dep_type());
263
264            // If the entry already exists in the map append it.
265            if let Some(vec) = dependencies.get_mut(&dep_type) {
266                vec.push(Dependency { ptr: or_deps })
267            } else {
268                // Doesn't exist so we create it
269                dependencies.insert(dep_type, vec![Dependency { ptr: or_deps }]);
270            }
271            dep.pin_mut().raw_next();
272        }
273    }
274    dependencies
275}
276
277#[cxx::bridge]
278pub(crate) mod raw {
279    unsafe extern "C++" {
280        include!("oma-apt/apt-pkg-c/package.h");
281
282        type DepIterator;
283
284        type PkgIterator = crate::raw::PkgIterator;
285        type VerIterator = crate::raw::VerIterator;
286
287        /// The Parent PkgIterator for this dependency
288        ///
289        /// # Safety
290        ///
291        /// If the inner pointer is null segfaults can occur.
292        ///
293        /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
294        /// is recommended.
295        ///
296        /// The returned UniquePtr cannot outlive the cache.
297        unsafe fn parent_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
298
299        /// The Parent VerIterator for this dependency
300        ///
301        /// # Safety
302        ///
303        /// If the inner pointer is null segfaults can occur.
304        ///
305        /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
306        /// is recommended.
307        ///
308        /// The returned UniquePtr cannot outlive the cache.
309        unsafe fn parent_ver(self: &DepIterator) -> UniquePtr<VerIterator>;
310
311        // Dependency Declarations
312        /// String representation of the dependency compare type
313        /// "","<=",">=","<",">","=","!="
314        ///
315        /// This returns Error for no compare type.
316        pub fn comp_type(self: &DepIterator) -> Result<&str>;
317
318        // Get the dependency type as a u8
319        // You can use `DepType::from(raw_dep.dep_type())` to convert to enum.
320        pub fn dep_type(self: &DepIterator) -> u8;
321
322        /// Returns true if the dependency type is critical.
323        ///
324        /// Depends, PreDepends, Conflicts, Obsoletes, Breaks
325        /// will return [true].
326        ///
327        /// Suggests, Recommends, Replaces and Enhances
328        /// will return [false].
329        #[cxx_name = "IsCritical"]
330        pub fn is_critical(self: &DepIterator) -> bool;
331
332        /// Return True if the dep is reverse, false if normal
333        #[cxx_name = "Reverse"]
334        pub fn is_reverse(self: &DepIterator) -> bool;
335
336        pub fn target_ver(self: &DepIterator) -> Result<&str>;
337
338        /// Return the Target Package for the dependency.
339        ///
340        /// # Safety
341        ///
342        /// If the inner pointer is null segfaults can occur.
343        ///
344        /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
345        /// is recommended.
346        ///
347        /// The returned UniquePtr cannot outlive the cache.
348        unsafe fn target_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
349
350        /// Returns a CxxVector of VerIterators.
351        ///
352        /// # Safety
353        ///
354        /// These can not be owned and will need to be Cloned with unique.
355        ///
356        /// If the inner pointer is null segfaults can occur.
357        ///
358        /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
359        /// is recommended.
360        ///
361        /// The returned UniquePtr cannot outlive the cache.
362        unsafe fn all_targets(self: &DepIterator) -> UniquePtr<CxxVector<VerIterator>>;
363
364        /// Return true if this dep is Or'd with the next. The last dep in the
365        /// or group will return False.
366        pub fn or_dep(self: &DepIterator) -> bool;
367
368        pub fn index(self: &DepIterator) -> usize;
369        /// Clone the pointer.
370        ///
371        /// # Safety
372        ///
373        /// If the inner pointer is null segfaults can occur.
374        ///
375        /// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
376        /// is recommended.
377        ///
378        /// The returned UniquePtr cannot outlive the cache.
379        unsafe fn unique(self: &DepIterator) -> UniquePtr<DepIterator>;
380        pub fn raw_next(self: Pin<&mut DepIterator>);
381        pub fn end(self: &DepIterator) -> bool;
382    }
383}