rust_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 { 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
79/// A struct representing a Base Dependency.
80pub 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	/// This is the name of the dependency.
109	pub fn name(&self) -> &str { self.target_package().name() }
110
111	/// Return the target package.
112	///
113	/// For Reverse Dependencies this will actually return the parent package
114	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	/// The target version &str of the dependency if specified.
125	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	/// The Dependency Type. Depends, Recommends, etc.
138	pub fn dep_type(&self) -> DepType { DepType::from(self.ptr.dep_type()) }
139
140	/// Comparison type of the dependency version, if specified.
141	pub fn comp_type(&self) -> Option<&str> { self.ptr.comp_type().ok() }
142
143	// Iterate all Versions that are able to satisfy this dependency
144	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/// A struct representing a single Dependency record.
179///
180/// This can contain multiple Base Dependencies that can
181/// satisfy the same Dependency.
182#[derive(fmt::Debug, Clone)]
183pub struct Dependency<'a> {
184	pub(crate) ptr: Vec<BaseDep<'a>>,
185}
186
187impl<'a> Dependency<'a> {
188	/// Return the Dep Type of this group. Depends, Pre-Depends.
189	pub fn dep_type(&self) -> DepType { self[0].dep_type() }
190
191	/// Returns True if there are multiple dependencies that can satisfy this
192	pub fn is_or(&self) -> bool { self.len() > 1 }
193
194	/// Returns a reference to the first BaseDep
195	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			// This means that more than one thing can satisfy a dependency.
231			// For reverse dependencies we cannot get the or deps.
232			// This can cause a segfault
233			// See: https://gitlab.com/volian/rust-apt/-/merge_requests/36
234			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					// This is the last of the Or group
239					if !dep.or_dep() {
240						break;
241					}
242				}
243			}
244
245			let dep_type = DepType::from(dep.dep_type());
246
247			// If the entry already exists in the map append it.
248			if let Some(vec) = dependencies.get_mut(&dep_type) {
249				vec.push(Dependency { ptr: or_deps })
250			} else {
251				// Doesn't exist so we create it
252				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		/// The Parent PkgIterator for this dependency
271		///
272		/// # Safety
273		///
274		/// If the inner pointer is null segfaults can occur.
275		///
276		/// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
277		/// is recommended.
278		///
279		/// The returned UniquePtr cannot outlive the cache.
280		unsafe fn parent_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
281
282		/// The Parent VerIterator for this dependency
283		///
284		/// # Safety
285		///
286		/// If the inner pointer is null segfaults can occur.
287		///
288		/// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
289		/// is recommended.
290		///
291		/// The returned UniquePtr cannot outlive the cache.
292		unsafe fn parent_ver(self: &DepIterator) -> UniquePtr<VerIterator>;
293
294		// Dependency Declarations
295		/// String representation of the dependency compare type
296		/// "","<=",">=","<",">","=","!="
297		///
298		/// This returns Error for no compare type.
299		pub fn comp_type(self: &DepIterator) -> Result<&str>;
300
301		// Get the dependency type as a u8
302		// You can use `DepType::from(raw_dep.dep_type())` to convert to enum.
303		pub fn dep_type(self: &DepIterator) -> u8;
304
305		/// Returns true if the dependency type is critical.
306		///
307		/// Depends, PreDepends, Conflicts, Obsoletes, Breaks
308		/// will return [true].
309		///
310		/// Suggests, Recommends, Replaces and Enhances
311		/// will return [false].
312		#[cxx_name = "IsCritical"]
313		pub fn is_critical(self: &DepIterator) -> bool;
314
315		/// Return True if the dep is reverse, false if normal
316		#[cxx_name = "Reverse"]
317		pub fn is_reverse(self: &DepIterator) -> bool;
318
319		pub fn target_ver(self: &DepIterator) -> Result<&str>;
320
321		/// Return the Target Package for the dependency.
322		///
323		/// # Safety
324		///
325		/// If the inner pointer is null segfaults can occur.
326		///
327		/// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
328		/// is recommended.
329		///
330		/// The returned UniquePtr cannot outlive the cache.
331		unsafe fn target_pkg(self: &DepIterator) -> UniquePtr<PkgIterator>;
332
333		/// Returns a CxxVector of VerIterators.
334		///
335		/// # Safety
336		///
337		/// These can not be owned and will need to be Cloned with unique.
338		///
339		/// If the inner pointer is null segfaults can occur.
340		///
341		/// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
342		/// is recommended.
343		///
344		/// The returned UniquePtr cannot outlive the cache.
345		unsafe fn all_targets(self: &DepIterator) -> UniquePtr<CxxVector<VerIterator>>;
346
347		/// Return true if this dep is Or'd with the next. The last dep in the
348		/// or group will return False.
349		pub fn or_dep(self: &DepIterator) -> bool;
350
351		#[cxx_name = "Index"]
352		pub fn index(self: &DepIterator) -> u64;
353		/// Clone the pointer.
354		///
355		/// # Safety
356		///
357		/// If the inner pointer is null segfaults can occur.
358		///
359		/// Using [`crate::raw::IntoRawIter::make_safe`] to convert to an Option
360		/// is recommended.
361		///
362		/// The returned UniquePtr cannot outlive the cache.
363		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}