pkgcraft/repo/
set.rs

1use std::cmp::Ordering;
2use std::ffi::{c_char, c_int};
3use std::{ptr, slice};
4
5use pkgcraft::dep::Version;
6use pkgcraft::pkg::Pkg;
7use pkgcraft::repo::set::RepoSet;
8use pkgcraft::repo::{PkgRepository, Repo};
9use pkgcraft::restrict::Restrict;
10use pkgcraft::utils::hash;
11
12use crate::macros::*;
13use crate::types::{RepoSetIter, SetOp};
14use crate::utils::{boxed, str_to_raw};
15
16/// Create a repo set.
17///
18/// # Safety
19/// The argument must be an array of Repo pointers.
20#[no_mangle]
21pub unsafe extern "C" fn pkgcraft_repo_set_new(repos: *mut *mut Repo, len: usize) -> *mut RepoSet {
22    let repos = unsafe { slice::from_raw_parts(repos, len) };
23    let repos = repos.iter().map(|r| try_ref_from_ptr!(r));
24    Box::into_raw(Box::new(repos.collect()))
25}
26
27/// Return a repo set's categories.
28///
29/// # Safety
30/// The argument must be a non-null RepoSet pointer.
31#[no_mangle]
32pub unsafe extern "C" fn pkgcraft_repo_set_categories(
33    s: *mut RepoSet,
34    len: *mut usize,
35) -> *mut *mut c_char {
36    let s = try_ref_from_ptr!(s);
37    iter_to_array!(s.categories().iter(), len, str_to_raw)
38}
39
40/// Return a repo set's packages for a category.
41///
42/// # Safety
43/// The arguments must be a non-null RepoSet pointer and category.
44#[no_mangle]
45pub unsafe extern "C" fn pkgcraft_repo_set_packages(
46    s: *mut RepoSet,
47    cat: *const c_char,
48    len: *mut usize,
49) -> *mut *mut c_char {
50    let s = try_ref_from_ptr!(s);
51    let cat = try_str_from_ptr!(cat);
52    iter_to_array!(s.packages(cat).iter(), len, str_to_raw)
53}
54
55/// Return a repo set's versions for a package.
56///
57/// # Safety
58/// The arguments must be a non-null RepoSet pointer, category, and package.
59#[no_mangle]
60pub unsafe extern "C" fn pkgcraft_repo_set_versions(
61    s: *mut RepoSet,
62    cat: *const c_char,
63    pkg: *const c_char,
64    len: *mut usize,
65) -> *mut *mut Version {
66    let s = try_ref_from_ptr!(s);
67    let cat = try_str_from_ptr!(cat);
68    let pkg = try_str_from_ptr!(pkg);
69    iter_to_array!(s.versions(cat, pkg).into_iter(), len, boxed)
70}
71
72/// Return a repo set's length.
73///
74/// # Safety
75/// The argument must be a non-null RepoSet pointer.
76#[no_mangle]
77pub unsafe extern "C" fn pkgcraft_repo_set_len(s: *mut RepoSet) -> usize {
78    let s = try_ref_from_ptr!(s);
79    s.len()
80}
81
82/// Determine if a repo set is empty.
83///
84/// # Safety
85/// The argument must be a non-null RepoSet pointer.
86#[no_mangle]
87pub unsafe extern "C" fn pkgcraft_repo_set_is_empty(s: *mut RepoSet) -> bool {
88    let s = try_ref_from_ptr!(s);
89    s.is_empty()
90}
91
92/// Return the ordered array of repos for a repo set.
93///
94/// # Safety
95/// The argument must be a non-null RepoSet pointer.
96#[no_mangle]
97pub unsafe extern "C" fn pkgcraft_repo_set_repos(
98    s: *mut RepoSet,
99    len: *mut usize,
100) -> *mut *const Repo {
101    let s = try_ref_from_ptr!(s);
102    iter_to_array!(s.repos.iter(), len, |r| { r as *const _ })
103}
104
105/// Compare two repo sets returning -1, 0, or 1 if the first set is less than, equal to, or greater
106/// than the second set, respectively.
107///
108/// # Safety
109/// The arguments must be non-null RepoSet pointers.
110#[no_mangle]
111pub unsafe extern "C" fn pkgcraft_repo_set_cmp(s1: *mut RepoSet, s2: *mut RepoSet) -> c_int {
112    let s1 = try_ref_from_ptr!(s1);
113    let s2 = try_ref_from_ptr!(s2);
114
115    match s1.cmp(s2) {
116        Ordering::Less => -1,
117        Ordering::Equal => 0,
118        Ordering::Greater => 1,
119    }
120}
121
122/// Return the hash value for a repo set.
123///
124/// # Safety
125/// The argument must be a non-null RepoSet pointer.
126#[no_mangle]
127pub unsafe extern "C" fn pkgcraft_repo_set_hash(s: *mut RepoSet) -> u64 {
128    let s = try_ref_from_ptr!(s);
129    hash(s)
130}
131
132/// Free a repo set.
133///
134/// # Safety
135/// The argument must be a RepoSet pointer or NULL.
136#[no_mangle]
137pub unsafe extern "C" fn pkgcraft_repo_set_free(r: *mut RepoSet) {
138    if !r.is_null() {
139        unsafe { drop(Box::from_raw(r)) };
140    }
141}
142
143/// Return a package iterator for a repo set.
144///
145/// # Safety
146/// The repo argument must be a non-null Repo pointer and the restrict argument can be a
147/// Restrict pointer or NULL to iterate over all packages.
148#[no_mangle]
149pub unsafe extern "C" fn pkgcraft_repo_set_iter<'a>(
150    s: *mut RepoSet,
151    restrict: *mut Restrict,
152) -> *mut RepoSetIter<'a> {
153    let s = try_ref_from_ptr!(s);
154    let iter = match unsafe { restrict.as_ref() } {
155        Some(r) => s.iter_restrict(r.clone()),
156        None => s.iter(),
157    };
158    Box::into_raw(Box::new(iter))
159}
160
161/// Return the next package from a repo set package iterator.
162///
163/// Returns NULL when the iterator is empty.
164///
165/// # Safety
166/// The argument must be a non-null RepoSetIter pointer.
167#[no_mangle]
168pub unsafe extern "C" fn pkgcraft_repo_set_iter_next(i: *mut RepoSetIter) -> *mut Pkg {
169    let iter = try_mut_from_ptr!(i);
170    iter.next().map(boxed).unwrap_or(ptr::null_mut())
171}
172
173/// Free a repo set iterator.
174///
175/// # Safety
176/// The argument must be a non-null RepoSetIter pointer or NULL.
177#[no_mangle]
178pub unsafe extern "C" fn pkgcraft_repo_set_iter_free(i: *mut RepoSetIter) {
179    if !i.is_null() {
180        unsafe { drop(Box::from_raw(i)) };
181    }
182}
183
184/// Perform a set operation on two repo sets, assigning to the first set.
185///
186/// # Safety
187/// The arguments must be non-null RepoSet pointers.
188#[no_mangle]
189pub unsafe extern "C" fn pkgcraft_repo_set_assign_op_set(
190    op: SetOp,
191    s1: *mut RepoSet,
192    s2: *mut RepoSet,
193) {
194    use SetOp::*;
195    let s1 = try_mut_from_ptr!(s1);
196    let s2 = try_ref_from_ptr!(s2);
197    match op {
198        And => *s1 &= s2,
199        Or => *s1 |= s2,
200        Xor => *s1 ^= s2,
201        Sub => *s1 -= s2,
202    }
203}
204
205/// Perform a set operation on a repo set and repo, assigning to the set.
206///
207/// # Safety
208/// The arguments must be non-null RepoSet and Repo pointers.
209#[no_mangle]
210pub unsafe extern "C" fn pkgcraft_repo_set_assign_op_repo(
211    op: SetOp,
212    s: *mut RepoSet,
213    r: *mut Repo,
214) {
215    use SetOp::*;
216    let s = try_mut_from_ptr!(s);
217    let r = try_ref_from_ptr!(r);
218    match op {
219        And => *s &= r,
220        Or => *s |= r,
221        Xor => *s ^= r,
222        Sub => *s -= r,
223    }
224}
225
226/// Perform a set operation on two repo sets, creating a new set.
227///
228/// # Safety
229/// The arguments must be non-null RepoSet pointers.
230#[no_mangle]
231pub unsafe extern "C" fn pkgcraft_repo_set_op_set(
232    op: SetOp,
233    s1: *mut RepoSet,
234    s2: *mut RepoSet,
235) -> *mut RepoSet {
236    use SetOp::*;
237    let s1 = try_mut_from_ptr!(s1);
238    let s2 = try_ref_from_ptr!(s2);
239    let set = match op {
240        And => s1.clone() & s2,
241        Or => s1.clone() | s2,
242        Xor => s1.clone() ^ s2,
243        Sub => s1.clone() - s2,
244    };
245    Box::into_raw(Box::new(set))
246}
247
248/// Perform a set operation on a repo set and repo, creating a new set.
249///
250/// # Safety
251/// The arguments must be non-null RepoSet and Repo pointers.
252#[no_mangle]
253pub unsafe extern "C" fn pkgcraft_repo_set_op_repo(
254    op: SetOp,
255    s: *mut RepoSet,
256    r: *mut Repo,
257) -> *mut RepoSet {
258    use SetOp::*;
259    let s = try_mut_from_ptr!(s);
260    let r = try_ref_from_ptr!(r);
261    let set = match op {
262        And => s.clone() & r,
263        Or => s.clone() | r,
264        Xor => s.clone() ^ r,
265        Sub => s.clone() - r,
266    };
267    Box::into_raw(Box::new(set))
268}