Skip to main content

podman_sequoia/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2
3#![allow(clippy::missing_safety_doc)]
4use libc::c_char;
5use std::ffi::CString;
6use std::io;
7
8#[derive(Eq, PartialEq, Debug)]
9#[repr(C)]
10/// cbindgen:rename-all=ScreamingSnakeCase
11/// cbindgen:prefix-with-name
12pub enum SequoiaErrorKind {
13    Unknown,
14    InvalidArgument,
15    IoError,
16}
17
18#[derive(Debug)]
19#[repr(C)]
20pub struct SequoiaError {
21    pub kind: SequoiaErrorKind,
22    pub message: *mut c_char,
23}
24
25impl Drop for SequoiaError {
26    fn drop(&mut self) {
27        unsafe {
28            let _ = CString::from_raw(self.message);
29        }
30    }
31}
32
33#[no_mangle]
34pub unsafe extern "C" fn sequoia_error_free(err_ptr: *mut SequoiaError) {
35    drop(Box::from_raw(err_ptr))
36}
37
38pub unsafe fn set_error_from(err_ptr: *mut *mut SequoiaError, err: anyhow::Error) {
39    if !err_ptr.is_null() {
40        let kind = if err.is::<io::Error>() {
41            SequoiaErrorKind::IoError
42        } else {
43            SequoiaErrorKind::Unknown
44        };
45
46        *err_ptr = Box::into_raw(Box::new(SequoiaError {
47            kind,
48            message: CString::from_vec_unchecked(err.to_string().into()).into_raw(),
49        }));
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn basic_usage() {
59        let error_text = "test error";
60        let result = Result::<(), anyhow::Error>::Err(anyhow::anyhow!(error_text));
61        let mut err_ptr: *mut SequoiaError = std::ptr::null_mut();
62        unsafe { set_error_from(&mut err_ptr, result.unwrap_err()) }
63        assert!(!err_ptr.is_null());
64        unsafe {
65            assert_eq!((*err_ptr).kind, SequoiaErrorKind::Unknown);
66            assert_eq!(
67                std::ffi::CStr::from_ptr((*err_ptr).message).to_str(),
68                Ok(error_text)
69            );
70        }
71        unsafe { sequoia_error_free(err_ptr) }
72    }
73
74    #[test]
75    fn nil_destination() {
76        let result = Result::<(), anyhow::Error>::Err(anyhow::anyhow!("test error"));
77        unsafe { set_error_from(std::ptr::null_mut(), result.unwrap_err()) }
78    }
79
80    #[test]
81    fn io_error() {
82        let error_text = "test error";
83        let result = Result::<(), anyhow::Error>::Err(
84            io::Error::new(io::ErrorKind::Other, error_text).into(),
85        );
86        let mut err_ptr: *mut SequoiaError = std::ptr::null_mut();
87        unsafe { set_error_from(&mut err_ptr, result.unwrap_err()) }
88        assert!(!err_ptr.is_null());
89        unsafe {
90            assert_eq!((*err_ptr).kind, SequoiaErrorKind::IoError);
91            assert_eq!(
92                std::ffi::CStr::from_ptr((*err_ptr).message).to_str(),
93                Ok(error_text)
94            );
95        }
96        unsafe { sequoia_error_free(err_ptr) }
97    }
98}