pkgcraft/dep/
pkg.rs

1use std::borrow::Cow;
2use std::cmp::Ordering;
3use std::ffi::{c_char, c_int};
4use std::{ptr, slice};
5
6use pkgcraft::dep::{Blocker, Cpn, Cpv, Dep, DepField, SlotOperator, Version};
7use pkgcraft::eapi::Eapi;
8use pkgcraft::restrict::{Restrict, Restriction};
9use pkgcraft::traits::Intersects;
10use pkgcraft::utils::hash;
11
12use crate::eapi::eapi_or_default;
13use crate::macros::*;
14use crate::panic::ffi_catch_panic;
15use crate::utils::{boxed, obj_to_str};
16
17use super::use_dep::UseDep;
18
19/// Parse a string into a package dependency using a specific EAPI. Pass NULL for the eapi argument
20/// in order to parse using the latest EAPI with extensions (e.g. support for repo deps).
21///
22/// Returns NULL on error.
23///
24/// # Safety
25/// The eapi argument may be NULL to use the default EAPI.
26#[no_mangle]
27pub unsafe extern "C" fn pkgcraft_dep_new(s: *const c_char, eapi: *const Eapi) -> *mut Dep {
28    ffi_catch_panic! {
29        let s = try_str_from_ptr!(s);
30        let eapi = eapi_or_default!(eapi);
31        let dep = unwrap_or_panic!(eapi.dep(s));
32        Box::into_raw(Box::new(dep))
33    }
34}
35
36/// Determine if a string is a valid package dependency.
37///
38/// Returns NULL on error.
39///
40/// # Safety
41/// The eapi argument may be NULL to use the default EAPI.
42#[no_mangle]
43pub unsafe extern "C" fn pkgcraft_dep_parse(s: *const c_char, eapi: *const Eapi) -> *const c_char {
44    ffi_catch_panic! {
45        let val = try_str_from_ptr!(s);
46        let eapi = option_from_ptr!(eapi).unwrap_or_default();
47        unwrap_or_panic!(eapi.dep(val));
48        s
49    }
50}
51
52/// Return a package dependency without the specified fields.
53///
54/// Returns NULL on error.
55///
56/// # Safety
57/// The arguments must a valid Dep pointer and DepField values.
58#[no_mangle]
59pub unsafe extern "C" fn pkgcraft_dep_without(
60    d: *mut Dep,
61    fields: *mut DepField,
62    len: usize,
63) -> *mut Dep {
64    ffi_catch_panic! {
65        let dep = try_ref_from_ptr!(d);
66        let fields = unsafe { slice::from_raw_parts(fields, len) };
67        let dep = dep.without(fields.iter().copied());
68
69        if let Cow::Owned(d) = unwrap_or_panic!(dep) {
70            Box::into_raw(Box::new(d))
71        } else {
72            d
73        }
74    }
75}
76
77/// Return a package dependency without optional fields.
78///
79/// # Safety
80/// The argument must a valid Dep pointer.
81#[no_mangle]
82pub unsafe extern "C" fn pkgcraft_dep_unversioned(d: *mut Dep) -> *mut Dep {
83    let dep = try_ref_from_ptr!(d);
84    if let Cow::Owned(d) = dep.unversioned() {
85        Box::into_raw(Box::new(d))
86    } else {
87        d
88    }
89}
90
91/// Return a package dependency without optional fields except version.
92///
93/// # Safety
94/// The argument must a valid Dep pointer.
95#[no_mangle]
96pub unsafe extern "C" fn pkgcraft_dep_versioned(d: *mut Dep) -> *mut Dep {
97    let dep = try_ref_from_ptr!(d);
98    if let Cow::Owned(d) = dep.versioned() {
99        Box::into_raw(Box::new(d))
100    } else {
101        d
102    }
103}
104
105/// Return a package dependency without USE dependencies.
106///
107/// # Safety
108/// The argument must a valid Dep pointer.
109#[no_mangle]
110pub unsafe extern "C" fn pkgcraft_dep_no_use_deps(d: *mut Dep) -> *mut Dep {
111    let dep = try_ref_from_ptr!(d);
112    if let Cow::Owned(d) = dep.no_use_deps() {
113        Box::into_raw(Box::new(d))
114    } else {
115        d
116    }
117}
118
119/// Return a package dependency modifying the specified fields with corresponding string values.
120/// Use null pointers for string values to unset a given field.
121///
122/// Returns NULL on error.
123///
124/// # Safety
125/// The fields and values arguments must be equal length arrays of DepFields with
126/// corresponding string values.
127#[no_mangle]
128pub unsafe extern "C" fn pkgcraft_dep_modify(
129    d: *mut Dep,
130    fields: *mut DepField,
131    values: *mut *mut c_char,
132    len: usize,
133) -> *mut Dep {
134    ffi_catch_panic! {
135        let dep = try_ref_from_ptr!(d);
136        let fields = unsafe { slice::from_raw_parts(fields, len) };
137        let values = unsafe { slice::from_raw_parts(values, len) };
138        let iterable = fields.iter().zip(values.iter())
139            .map(|(f, p)| (*f, option_from_ptr!(p).map(|_| try_str_from_ptr!(p))));
140
141        if let Cow::Owned(d) = unwrap_or_panic!(dep.modify(iterable)) {
142            Box::into_raw(Box::new(d))
143        } else {
144            d
145        }
146    }
147}
148
149/// Parse a string into a Blocker's raw value.
150///
151/// Returns a value of 0 for nonexistence.
152///
153/// # Safety
154/// The argument must be a UTF-8 string.
155#[no_mangle]
156pub unsafe extern "C" fn pkgcraft_dep_blocker_from_str(s: *const c_char) -> u32 {
157    let s = try_str_from_ptr!(s);
158    s.parse::<Blocker>().map(|x| x as u32).unwrap_or_default()
159}
160
161/// Return the string for a Blocker.
162#[no_mangle]
163pub extern "C" fn pkgcraft_dep_blocker_str(b: Blocker) -> *mut c_char {
164    try_ptr_from_str!(b.as_ref())
165}
166
167/// Parse a string into a SlotOperator's raw value.
168///
169/// Returns a value of 0 for nonexistence.
170///
171/// # Safety
172/// The argument must be a UTF-8 string.
173#[no_mangle]
174pub unsafe extern "C" fn pkgcraft_dep_slot_op_from_str(s: *const c_char) -> u32 {
175    let s = try_str_from_ptr!(s);
176    s.parse::<SlotOperator>()
177        .map(|x| x as u32)
178        .unwrap_or_default()
179}
180
181/// Return the string for a SlotOperator.
182#[no_mangle]
183pub extern "C" fn pkgcraft_dep_slot_op_str(op: SlotOperator) -> *mut c_char {
184    try_ptr_from_str!(op.as_ref())
185}
186
187/// Compare two package dependencies returning -1, 0, or 1 if the first is less than, equal to, or
188/// greater than the second, respectively.
189///
190/// # Safety
191/// The arguments must be non-null Dep pointers.
192#[no_mangle]
193pub unsafe extern "C" fn pkgcraft_dep_cmp(d1: *mut Dep, d2: *mut Dep) -> c_int {
194    let d1 = try_ref_from_ptr!(d1);
195    let d2 = try_ref_from_ptr!(d2);
196
197    match d1.cmp(d2) {
198        Ordering::Less => -1,
199        Ordering::Equal => 0,
200        Ordering::Greater => 1,
201    }
202}
203
204/// Determine if two package dependencies intersect.
205///
206/// # Safety
207/// The arguments must be non-null Dep pointers.
208#[no_mangle]
209pub unsafe extern "C" fn pkgcraft_dep_intersects(d1: *mut Dep, d2: *mut Dep) -> bool {
210    let d1 = try_ref_from_ptr!(d1);
211    let d2 = try_ref_from_ptr!(d2);
212    d1.intersects(d2)
213}
214
215/// Determine if a package dependency intersects with a Cpv.
216///
217/// # Safety
218/// The arguments must be non-null Cpv and Dep pointers.
219#[no_mangle]
220pub unsafe extern "C" fn pkgcraft_dep_intersects_cpv(d: *mut Dep, c: *mut Cpv) -> bool {
221    let d = try_ref_from_ptr!(d);
222    let c = try_ref_from_ptr!(c);
223    d.intersects(c)
224}
225
226/// Get the category of a package dependency.
227/// For example, the package dependency "=cat/pkg-1-r2" returns "cat".
228///
229/// # Safety
230/// The argument must be a non-null Dep pointer.
231#[no_mangle]
232pub unsafe extern "C" fn pkgcraft_dep_category(d: *mut Dep) -> *mut c_char {
233    let dep = try_ref_from_ptr!(d);
234    try_ptr_from_str!(dep.category())
235}
236
237/// Get the package name of a package dependency.
238/// For example, the package dependency "=cat/pkg-1-r2" returns "pkg".
239///
240/// # Safety
241/// The argument must be a non-null Dep pointer.
242#[no_mangle]
243pub unsafe extern "C" fn pkgcraft_dep_package(d: *mut Dep) -> *mut c_char {
244    let dep = try_ref_from_ptr!(d);
245    try_ptr_from_str!(dep.package())
246}
247
248/// Get a package dependency's raw blocker value.
249/// For example, the package dependency "!cat/pkg" has a weak blocker.
250///
251/// Returns a value of 0 for nonexistence.
252///
253/// # Safety
254/// The argument must be a non-null Dep pointer.
255#[no_mangle]
256pub unsafe extern "C" fn pkgcraft_dep_blocker(d: *mut Dep) -> u32 {
257    let dep = try_ref_from_ptr!(d);
258    dep.blocker().map(|x| x as u32).unwrap_or_default()
259}
260
261/// Get the version of a package dependency.
262/// For example, the package dependency "=cat/pkg-1-r2" returns "1-r2".
263///
264/// Returns NULL on nonexistence.
265///
266/// # Safety
267/// The argument must be a non-null Dep pointer.
268#[no_mangle]
269pub unsafe extern "C" fn pkgcraft_dep_version(d: *mut Dep) -> *mut Version {
270    let dep = try_ref_from_ptr!(d);
271    match dep.version() {
272        Some(v) => Box::into_raw(Box::new(v.clone())),
273        None => ptr::null_mut(),
274    }
275}
276
277/// Get the slot of a package dependency.
278/// For example, the package dependency "=cat/pkg-1-r2:3" returns "3".
279///
280/// Returns NULL on nonexistence.
281///
282/// # Safety
283/// The argument must be a non-null Dep pointer.
284#[no_mangle]
285pub unsafe extern "C" fn pkgcraft_dep_slot(d: *mut Dep) -> *mut c_char {
286    let dep = try_ref_from_ptr!(d);
287    match dep.slot() {
288        Some(s) => try_ptr_from_str!(s),
289        None => ptr::null_mut(),
290    }
291}
292
293/// Get the subslot of a package dependency.
294/// For example, the package dependency "=cat/pkg-1-r2:3/4" returns "4".
295///
296/// Returns NULL on nonexistence.
297///
298/// # Safety
299/// The argument must be a non-null Dep pointer.
300#[no_mangle]
301pub unsafe extern "C" fn pkgcraft_dep_subslot(d: *mut Dep) -> *mut c_char {
302    let dep = try_ref_from_ptr!(d);
303    match dep.subslot() {
304        Some(s) => try_ptr_from_str!(s),
305        None => ptr::null_mut(),
306    }
307}
308
309/// Get a package dependency's raw slot operator value.
310/// For example, the package dependency "=cat/pkg-1-r2:0=" has an equal slot operator.
311///
312/// Returns a value of 0 for nonexistence.
313///
314/// # Safety
315/// The argument must be a non-null Dep pointer.
316#[no_mangle]
317pub unsafe extern "C" fn pkgcraft_dep_slot_op(d: *mut Dep) -> u32 {
318    let dep = try_ref_from_ptr!(d);
319    dep.slot_op().map(|x| x as u32).unwrap_or_default()
320}
321
322/// Get the USE dependencies of a package dependency.
323/// For example, the package dependency "=cat/pkg-1-r2[a,b,c]" has USE dependencies of "a, b, c".
324///
325/// Returns NULL on nonexistence.
326///
327/// # Safety
328/// The argument must be a non-null Dep pointer.
329#[no_mangle]
330pub unsafe extern "C" fn pkgcraft_dep_use_deps(d: *mut Dep, len: *mut usize) -> *mut *mut UseDep {
331    // TODO: switch from usize to std::os::raw::c_size_t when it's stable.
332    let dep = try_ref_from_ptr!(d);
333    match dep.use_deps() {
334        Some(use_deps) => iter_to_array!(use_deps.iter(), len, |u| boxed(u.clone().into())),
335        None => ptr::null_mut(),
336    }
337}
338
339/// Get the USE dependencies of a package dependency as raw strings.
340/// For example, the package dependency "=cat/pkg-1-r2[a,b,c]" has USE dependencies of "a, b, c".
341///
342/// Returns NULL on nonexistence.
343///
344/// # Safety
345/// The argument must be a non-null Dep pointer.
346#[no_mangle]
347pub unsafe extern "C" fn pkgcraft_dep_use_deps_str(
348    d: *mut Dep,
349    len: *mut usize,
350) -> *mut *mut c_char {
351    // TODO: switch from usize to std::os::raw::c_size_t when it's stable.
352    let dep = try_ref_from_ptr!(d);
353    match dep.use_deps() {
354        Some(use_deps) => iter_to_array!(use_deps.iter(), len, obj_to_str),
355        None => ptr::null_mut(),
356    }
357}
358
359/// Get the repo of a package dependency.
360/// For example, the package dependency "=cat/pkg-1-r2:3/4::repo" returns "repo".
361///
362/// Returns NULL on nonexistence.
363///
364/// # Safety
365/// The argument must be a non-null Dep pointer.
366#[no_mangle]
367pub unsafe extern "C" fn pkgcraft_dep_repo(d: *mut Dep) -> *mut c_char {
368    let dep = try_ref_from_ptr!(d);
369    match dep.repo() {
370        Some(s) => try_ptr_from_str!(s),
371        None => ptr::null_mut(),
372    }
373}
374
375/// Get the Cpn of a package dependency.
376///
377/// # Safety
378/// The argument must be a non-null Dep pointer.
379#[no_mangle]
380pub unsafe extern "C" fn pkgcraft_dep_cpn(d: *mut Dep) -> *mut Cpn {
381    let dep = try_ref_from_ptr!(d);
382    Box::into_raw(Box::new(dep.cpn().clone()))
383}
384
385/// Get the Cpv of a package dependency if one exists.
386///
387/// Returns NULL on nonexistence.
388///
389/// # Safety
390/// The argument must be a non-null Dep pointer.
391#[no_mangle]
392pub unsafe extern "C" fn pkgcraft_dep_cpv(d: *mut Dep) -> *mut Cpv {
393    let dep = try_ref_from_ptr!(d);
394    match dep.cpv() {
395        Some(cpv) => Box::into_raw(Box::new(cpv)),
396        None => ptr::null_mut(),
397    }
398}
399
400/// Return the string for a package dependency.
401///
402/// # Safety
403/// The argument must be a non-null Dep pointer.
404#[no_mangle]
405pub unsafe extern "C" fn pkgcraft_dep_str(d: *mut Dep) -> *mut c_char {
406    let dep = try_ref_from_ptr!(d);
407    try_ptr_from_str!(dep.to_string())
408}
409
410/// Return the hash value for a package dependency.
411///
412/// # Safety
413/// The argument must be a non-null Dep pointer.
414#[no_mangle]
415pub unsafe extern "C" fn pkgcraft_dep_hash(d: *mut Dep) -> u64 {
416    let dep = try_ref_from_ptr!(d);
417    hash(dep)
418}
419
420/// Return the restriction for a package dependency.
421///
422/// # Safety
423/// The argument must be a non-null Dep pointer.
424#[no_mangle]
425pub unsafe extern "C" fn pkgcraft_dep_restrict(d: *mut Dep) -> *mut Restrict {
426    let dep = try_ref_from_ptr!(d);
427    Box::into_raw(Box::new(dep.into()))
428}
429
430/// Determine if a restriction matches a package dependency.
431///
432/// # Safety
433/// The arguments must be valid Restrict and Dep pointers.
434#[no_mangle]
435pub unsafe extern "C" fn pkgcraft_dep_restrict_matches(d: *mut Dep, r: *mut Restrict) -> bool {
436    let dep = try_ref_from_ptr!(d);
437    let restrict = try_ref_from_ptr!(r);
438    restrict.matches(dep)
439}
440
441/// Free a package dependency.
442///
443/// # Safety
444/// The argument must be a Dep pointer or NULL.
445#[no_mangle]
446pub unsafe extern "C" fn pkgcraft_dep_free(d: *mut Dep) {
447    if !d.is_null() {
448        unsafe { drop(Box::from_raw(d)) };
449    }
450}