pkgcraft/pkg/ebuild/
keyword.rs

1use std::cmp::Ordering;
2use std::ffi::{c_char, c_int, CString};
3use std::ops::Deref;
4
5use pkgcraft::pkg::ebuild::keyword;
6use pkgcraft::utils::hash;
7
8use crate::macros::*;
9use crate::panic::ffi_catch_panic;
10use crate::utils::boxed;
11
12/// Opaque wrapper for pkgcraft::pkg::ebuild::keyword::Keyword.
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct KeywordWrapper(keyword::Keyword);
15
16/// C-compatible wrapper for pkgcraft::pkg::ebuild::keyword::Keyword.
17#[derive(Debug, Clone)]
18#[repr(C)]
19pub struct Keyword {
20    status: keyword::KeywordStatus,
21    arch: *mut c_char,
22    keyword: *mut KeywordWrapper,
23}
24
25impl From<keyword::Keyword> for Keyword {
26    fn from(value: keyword::Keyword) -> Self {
27        Keyword {
28            status: value.status(),
29            arch: try_ptr_from_str!(value.arch().as_ref()),
30            keyword: boxed(KeywordWrapper(value)),
31        }
32    }
33}
34
35impl Deref for Keyword {
36    type Target = keyword::Keyword;
37
38    fn deref(&self) -> &Self::Target {
39        let wrapper = try_ref_from_ptr!(self.keyword);
40        &wrapper.0
41    }
42}
43
44impl Drop for Keyword {
45    fn drop(&mut self) {
46        unsafe {
47            drop(CString::from_raw(self.arch));
48            drop(Box::from_raw(self.keyword));
49        }
50    }
51}
52
53/// Parse a string into a package keyword.
54///
55/// Returns NULL on error.
56///
57/// # Safety
58/// The argument must be a non-null string.
59#[no_mangle]
60pub unsafe extern "C" fn pkgcraft_keyword_new(s: *const c_char) -> *mut Keyword {
61    ffi_catch_panic! {
62        let s = try_str_from_ptr!(s);
63        let keyword = unwrap_or_panic!(keyword::Keyword::try_new(s));
64        Box::into_raw(Box::new(keyword.into()))
65    }
66}
67
68/// Compare two package keywords returning -1, 0, or 1 if the first is less than, equal to,
69/// or greater than the second, respectively.
70///
71/// # Safety
72/// The arguments must be non-null Keyword pointers.
73#[no_mangle]
74pub unsafe extern "C" fn pkgcraft_keyword_cmp(k1: *mut Keyword, k2: *mut Keyword) -> c_int {
75    let k1 = try_ref_from_ptr!(k1);
76    let k2 = try_ref_from_ptr!(k2);
77
78    match k1.cmp(k2) {
79        Ordering::Less => -1,
80        Ordering::Equal => 0,
81        Ordering::Greater => 1,
82    }
83}
84
85/// Return the hash value for a package keyword.
86///
87/// # Safety
88/// The argument must be a non-null Keyword pointer.
89#[no_mangle]
90pub unsafe extern "C" fn pkgcraft_keyword_hash(k: *mut Keyword) -> u64 {
91    let keyword = try_ref_from_ptr!(k);
92    hash(keyword.deref())
93}
94
95/// Return the string for a package keyword.
96///
97/// # Safety
98/// The argument must be a non-null Keyword pointer.
99#[no_mangle]
100pub unsafe extern "C" fn pkgcraft_keyword_str(k: *mut Keyword) -> *mut c_char {
101    let keyword = try_ref_from_ptr!(k);
102    try_ptr_from_str!(keyword.to_string())
103}
104
105/// Free a package keyword.
106///
107/// # Safety
108/// The argument must be a Keyword pointer or NULL.
109#[no_mangle]
110pub unsafe extern "C" fn pkgcraft_keyword_free(k: *mut Keyword) {
111    if !k.is_null() {
112        unsafe { drop(Box::from_raw(k)) };
113    }
114}