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 {
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
83pub 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 pub fn name(&self) -> &str {
114 self.target_package().name()
115 }
116
117 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 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 pub fn dep_type(&self) -> DepType {
145 DepType::from(self.ptr.dep_type())
146 }
147
148 pub fn comp_type(&self) -> Option<&str> {
150 self.ptr.comp_type().ok()
151 }
152
153 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#[derive(fmt::Debug, Clone)]
194pub struct Dependency<'a> {
195 pub(crate) ptr: Vec<BaseDep<'a>>,
196}
197
198impl<'a> Dependency<'a> {
199 pub fn dep_type(&self) -> DepType {
201 self[0].dep_type()
202 }
203
204 pub fn is_or(&self) -> bool {
206 self.len() > 1
207 }
208
209 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 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 if !dep.or_dep() {
257 break;
258 }
259 }
260 }
261
262 let dep_type = DepType::from(dep.dep_type());
263
264 if let Some(vec) = dependencies.get_mut(&dep_type) {
266 vec.push(Dependency { ptr: or_deps })
267 } else {
268 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 unsafe fn parent_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
298
299 unsafe fn parent_ver(self: &DepIterator) -> UniquePtr<VerIterator>;
310
311 pub fn comp_type(self: &DepIterator) -> Result<&str>;
317
318 pub fn dep_type(self: &DepIterator) -> u8;
321
322 #[cxx_name = "IsCritical"]
330 pub fn is_critical(self: &DepIterator) -> bool;
331
332 #[cxx_name = "Reverse"]
334 pub fn is_reverse(self: &DepIterator) -> bool;
335
336 pub fn target_ver(self: &DepIterator) -> Result<&str>;
337
338 unsafe fn target_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
349
350 unsafe fn all_targets(self: &DepIterator) -> UniquePtr<CxxVector<VerIterator>>;
363
364 pub fn or_dep(self: &DepIterator) -> bool;
367
368 pub fn index(self: &DepIterator) -> usize;
369 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}