pkgcraft/dep/
version.rs

1use std::cmp::Ordering;
2use std::ffi::{c_char, c_int};
3use std::ptr;
4
5use pkgcraft::dep::version::WithOp;
6use pkgcraft::dep::{Operator, Revision, Version};
7use pkgcraft::traits::Intersects;
8use pkgcraft::utils::hash;
9
10use crate::macros::*;
11use crate::panic::ffi_catch_panic;
12
13/// Parse a string into a revision.
14///
15/// Returns NULL on error.
16///
17/// # Safety
18/// The argument should be a valid UTF-8 string.
19#[no_mangle]
20pub unsafe extern "C" fn pkgcraft_revision_new(s: *const c_char) -> *mut Revision {
21    ffi_catch_panic! {
22        let s = try_str_from_ptr!(s);
23        let rev = unwrap_or_panic!(Revision::try_new(s));
24        Box::into_raw(Box::new(rev))
25    }
26}
27
28/// Compare two revisions returning -1, 0, or 1 if the first is less than, equal to, or greater
29/// than the second, respectively.
30///
31/// # Safety
32/// The revision arguments should be non-null Revision pointers.
33#[no_mangle]
34pub unsafe extern "C" fn pkgcraft_revision_cmp(r1: *mut Revision, r2: *mut Revision) -> c_int {
35    let r1 = try_ref_from_ptr!(r1);
36    let r2 = try_ref_from_ptr!(r2);
37
38    match r1.cmp(r2) {
39        Ordering::Less => -1,
40        Ordering::Equal => 0,
41        Ordering::Greater => 1,
42    }
43}
44
45/// Return the hash value for a revision.
46///
47/// # Safety
48/// The revision argument should be a non-null Revision pointer.
49#[no_mangle]
50pub unsafe extern "C" fn pkgcraft_revision_hash(r: *mut Revision) -> u64 {
51    let rev = try_ref_from_ptr!(r);
52    hash(rev)
53}
54
55/// Return a revision's string value.
56///
57/// # Safety
58/// The revision argument should be a non-null Revision pointer.
59#[no_mangle]
60pub unsafe extern "C" fn pkgcraft_revision_str(r: *mut Revision) -> *mut c_char {
61    let rev = try_ref_from_ptr!(r);
62    try_ptr_from_str!(rev.as_str())
63}
64
65/// Free a revision.
66///
67/// # Safety
68/// The revision argument should be a non-null Revision pointer.
69#[no_mangle]
70pub unsafe extern "C" fn pkgcraft_revision_free(r: *mut Revision) {
71    if !r.is_null() {
72        let _ = unsafe { Box::from_raw(r) };
73    }
74}
75
76/// Parse a string into a version.
77///
78/// Returns NULL on error.
79///
80/// # Safety
81/// The version argument should point to a valid string.
82#[no_mangle]
83pub unsafe extern "C" fn pkgcraft_version_new(s: *const c_char) -> *mut Version {
84    ffi_catch_panic! {
85        let s = try_str_from_ptr!(s);
86        let ver = unwrap_or_panic!(Version::try_new(s));
87        Box::into_raw(Box::new(ver))
88    }
89}
90
91/// Determine if a string is a valid package version.
92///
93/// Returns NULL on error.
94///
95/// # Safety
96/// The argument should point to a UTF-8 string.
97#[no_mangle]
98pub unsafe extern "C" fn pkgcraft_version_parse(s: *const c_char) -> *const c_char {
99    ffi_catch_panic! {
100        let val = try_str_from_ptr!(s);
101        unwrap_or_panic!(Version::try_new(val));
102        s
103    }
104}
105
106/// Return a version operator's raw value.
107///
108/// Returns a value of 0 for nonexistence.
109///
110/// # Safety
111/// The argument must be a non-null Version pointer.
112#[no_mangle]
113pub unsafe extern "C" fn pkgcraft_version_op(v: *mut Version) -> u32 {
114    let ver = try_ref_from_ptr!(v);
115    ver.op().map(|x| x as u32).unwrap_or_default()
116}
117
118/// Potentially create a new Version by applying an operator.
119///
120/// Returns NULL on error.
121///
122/// # Safety
123/// The argument must be a non-null Version pointer.
124#[no_mangle]
125pub unsafe extern "C" fn pkgcraft_version_with_op(v: *mut Version, op: Operator) -> *mut Version {
126    ffi_catch_panic! {
127        let ver = try_ref_from_ptr!(v);
128        if ver.op() == Some(op) {
129            v
130        } else {
131            let ver = unwrap_or_panic!(ver.clone().with_op(op));
132            Box::into_raw(Box::new(ver))
133        }
134    }
135}
136
137/// Return a version's base, e.g. the version "1-r2" has a base of "1".
138///
139/// # Safety
140/// The version argument should be a non-null Version pointer.
141#[no_mangle]
142pub unsafe extern "C" fn pkgcraft_version_base(v: *mut Version) -> *mut c_char {
143    let ver = try_ref_from_ptr!(v);
144    try_ptr_from_str!(ver.base())
145}
146
147/// Parse a string into an Operator's raw value.
148///
149/// Returns a value of 0 for nonexistence.
150///
151/// # Safety
152/// The argument should be a UTF-8 string.
153#[no_mangle]
154pub unsafe extern "C" fn pkgcraft_version_op_from_str(s: *const c_char) -> u32 {
155    let s = try_str_from_ptr!(s);
156    s.parse::<Operator>().map(|x| x as u32).unwrap_or_default()
157}
158
159/// Return the string for an Operator.
160#[no_mangle]
161pub extern "C" fn pkgcraft_version_op_str(op: Operator) -> *mut c_char {
162    try_ptr_from_str!(op.as_ref())
163}
164
165/// Compare two versions returning -1, 0, or 1 if the first is less than, equal to, or greater than
166/// the second, respectively.
167///
168/// # Safety
169/// The version arguments should be non-null Version pointers.
170#[no_mangle]
171pub unsafe extern "C" fn pkgcraft_version_cmp(v1: *mut Version, v2: *mut Version) -> c_int {
172    let v1 = try_ref_from_ptr!(v1);
173    let v2 = try_ref_from_ptr!(v2);
174
175    match v1.cmp(v2) {
176        Ordering::Less => -1,
177        Ordering::Equal => 0,
178        Ordering::Greater => 1,
179    }
180}
181
182/// Determine if two versions intersect.
183///
184/// # Safety
185/// The version arguments should be non-null Version pointers.
186#[no_mangle]
187pub unsafe extern "C" fn pkgcraft_version_intersects(v1: *mut Version, v2: *mut Version) -> bool {
188    let v1 = try_ref_from_ptr!(v1);
189    let v2 = try_ref_from_ptr!(v2);
190    v1.intersects(v2)
191}
192
193/// Return a version's revision, e.g. the version "1-r2" has a revision of "2".
194///
195/// Returns NULL on nonexistence.
196///
197/// # Safety
198/// The version argument should be a non-null Version pointer.
199#[no_mangle]
200pub unsafe extern "C" fn pkgcraft_version_revision(v: *mut Version) -> *mut Revision {
201    let ver = try_ref_from_ptr!(v);
202    match ver.revision() {
203        Some(rev) => Box::into_raw(Box::new(rev.clone())),
204        None => ptr::null_mut(),
205    }
206}
207
208/// Return a version's string value without operator.
209///
210/// # Safety
211/// The version argument should be a non-null Version pointer.
212#[no_mangle]
213pub unsafe extern "C" fn pkgcraft_version_str(v: *mut Version) -> *mut c_char {
214    let ver = try_ref_from_ptr!(v);
215    try_ptr_from_str!(ver.to_string())
216}
217
218/// Free a version.
219///
220/// # Safety
221/// The version argument should be a non-null Version pointer.
222#[no_mangle]
223pub unsafe extern "C" fn pkgcraft_version_free(v: *mut Version) {
224    if !v.is_null() {
225        let _ = unsafe { Box::from_raw(v) };
226    }
227}
228
229/// Return the hash value for a version.
230///
231/// # Safety
232/// The version argument should be a non-null Version pointer.
233#[no_mangle]
234pub unsafe extern "C" fn pkgcraft_version_hash(v: *mut Version) -> u64 {
235    let ver = try_ref_from_ptr!(v);
236    hash(ver)
237}