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#[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#[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 { self.to_str() }
57}
58
59impl DepType {
60 pub fn to_str(&self) -> &'static str {
61 match self {
62 DepType::Depends => "Depends",
63 DepType::PreDepends => "PreDepends",
64 DepType::Suggests => "Suggests",
65 DepType::Recommends => "Recommends",
66 DepType::Conflicts => "Conflicts",
67 DepType::Replaces => "Replaces",
68 DepType::Obsoletes => "Obsoletes",
69 DepType::DpkgBreaks => "Breaks",
70 DepType::Enhances => "Enhances",
71 }
72 }
73}
74
75impl fmt::Display for DepType {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.as_ref()) }
77}
78
79pub struct BaseDep<'a> {
81 pub ptr: UniquePtr<DepIterator>,
82 cache: &'a Cache,
83 target: OnceCell<Package<'a>>,
84 parent_ver: OnceCell<UniquePtr<VerIterator>>,
85}
86
87impl Clone for BaseDep<'_> {
88 fn clone(&self) -> Self {
89 Self {
90 ptr: unsafe { self.ptr.unique() },
91 cache: self.cache,
92 target: self.target.clone(),
93 parent_ver: unsafe { self.parent_ver().into() },
94 }
95 }
96}
97
98impl<'a> BaseDep<'a> {
99 pub fn new(ptr: UniquePtr<DepIterator>, cache: &'a Cache) -> BaseDep<'a> {
100 BaseDep {
101 ptr,
102 cache,
103 target: OnceCell::new(),
104 parent_ver: OnceCell::new(),
105 }
106 }
107
108 pub fn name(&self) -> &str { self.target_package().name() }
110
111 pub fn target_package(&self) -> &Package<'a> {
115 self.target.get_or_init(|| {
116 if self.is_reverse() {
117 Package::new(self.cache, unsafe { self.parent_pkg() })
118 } else {
119 Package::new(self.cache, unsafe { self.target_pkg() })
120 }
121 })
122 }
123
124 pub fn version(&self) -> Option<&str> {
126 if self.is_reverse() {
127 Some(
128 self.parent_ver
129 .get_or_init(|| unsafe { self.parent_ver() })
130 .version(),
131 )
132 } else {
133 self.target_ver().ok()
134 }
135 }
136
137 pub fn dep_type(&self) -> DepType { DepType::from(self.ptr.dep_type()) }
139
140 pub fn comp_type(&self) -> Option<&str> { self.ptr.comp_type().ok() }
142
143 pub fn all_targets(&self) -> Vec<Version<'_>> {
145 unsafe {
146 self.ptr
147 .all_targets()
148 .iter()
149 .map(|v| Version::new(v.unique(), self.cache))
150 .collect()
151 }
152 }
153}
154
155impl fmt::Display for BaseDep<'_> {
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157 if let (Some(comp), Some(version)) = (self.comp_type(), self.version()) {
158 write!(f, "({} {comp} {version})", self.name())
159 } else {
160 write!(f, "({})", self.name())
161 }
162 }
163}
164
165impl fmt::Debug for BaseDep<'_> {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 f.debug_struct("BaseDep")
168 .field("parent", unsafe { &self.parent_pkg().name() })
169 .field("name", &self.name())
170 .field("comp", &self.comp_type())
171 .field("version", &self.version())
172 .field("dep_type", &self.dep_type())
173 .field("is_reverse", &self.is_reverse())
174 .finish()
175 }
176}
177
178#[derive(fmt::Debug, Clone)]
183pub struct Dependency<'a> {
184 pub(crate) ptr: Vec<BaseDep<'a>>,
185}
186
187impl<'a> Dependency<'a> {
188 pub fn dep_type(&self) -> DepType { self[0].dep_type() }
190
191 pub fn is_or(&self) -> bool { self.len() > 1 }
193
194 pub fn first(&self) -> &BaseDep<'a> { &self[0] }
196}
197
198impl fmt::Display for Dependency<'_> {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 let mut dep_str = String::new();
201
202 for (i, base_dep) in self.iter().enumerate() {
203 dep_str += &base_dep.to_string();
204 if i + 1 != self.len() {
205 dep_str += " | "
206 }
207 }
208
209 write!(
210 f,
211 "{} {:?} {dep_str}",
212 unsafe { self.first().parent_pkg().fullname(false) },
213 self.dep_type(),
214 )?;
215 Ok(())
216 }
217}
218
219pub fn create_depends_map(
220 cache: &Cache,
221 dep: Option<UniquePtr<DepIterator>>,
222) -> HashMap<DepType, Vec<Dependency<'_>>> {
223 let mut dependencies: HashMap<DepType, Vec<Dependency<'_>>> = HashMap::new();
224
225 if let Some(mut dep) = dep {
226 while !dep.end() {
227 let mut or_deps = vec![];
228 or_deps.push(BaseDep::new(unsafe { dep.unique() }, cache));
229
230 if dep.or_dep() && !dep.is_reverse() {
235 loop {
236 dep.pin_mut().raw_next();
237 or_deps.push(BaseDep::new(unsafe { dep.unique() }, cache));
238 if !dep.or_dep() {
240 break;
241 }
242 }
243 }
244
245 let dep_type = DepType::from(dep.dep_type());
246
247 if let Some(vec) = dependencies.get_mut(&dep_type) {
249 vec.push(Dependency { ptr: or_deps })
250 } else {
251 dependencies.insert(dep_type, vec![Dependency { ptr: or_deps }]);
253 }
254 dep.pin_mut().raw_next();
255 }
256 }
257 dependencies
258}
259
260#[cxx::bridge]
261pub(crate) mod raw {
262 unsafe extern "C++" {
263 include!("rust-apt/apt-pkg-c/package.h");
264
265 type DepIterator;
266
267 type PkgIterator = crate::raw::PkgIterator;
268 type VerIterator = crate::raw::VerIterator;
269
270 unsafe fn parent_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
281
282 unsafe fn parent_ver(self: &DepIterator) -> UniquePtr<VerIterator>;
293
294 pub fn comp_type(self: &DepIterator) -> Result<&str>;
300
301 pub fn dep_type(self: &DepIterator) -> u8;
304
305 #[cxx_name = "IsCritical"]
313 pub fn is_critical(self: &DepIterator) -> bool;
314
315 #[cxx_name = "Reverse"]
317 pub fn is_reverse(self: &DepIterator) -> bool;
318
319 pub fn target_ver(self: &DepIterator) -> Result<&str>;
320
321 unsafe fn target_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
332
333 unsafe fn all_targets(self: &DepIterator) -> UniquePtr<CxxVector<VerIterator>>;
346
347 pub fn or_dep(self: &DepIterator) -> bool;
350
351 #[cxx_name = "Index"]
352 pub fn index(self: &DepIterator) -> u64;
353 unsafe fn unique(self: &DepIterator) -> UniquePtr<DepIterator>;
364 pub fn raw_next(self: Pin<&mut DepIterator>);
365 pub fn end(self: &DepIterator) -> bool;
366 }
367}