1use std::cell::RefCell;
2use std::ffi::{c_char, CString};
3use std::{fmt, ptr};
4
5use crate::macros::*;
6
7#[derive(Debug, Clone)]
8#[repr(C)]
9pub enum ErrorKind {
10 Generic,
11 Pkgcraft,
12 Config,
13 Repo,
14 Pkg,
15}
16
17#[derive(Debug, Clone)]
18pub struct Error {
19 message: String,
20 kind: ErrorKind,
21}
22
23impl Error {
24 pub fn new<S: ToString>(s: S) -> Self {
25 Error {
26 message: s.to_string(),
27 kind: ErrorKind::Generic,
28 }
29 }
30}
31
32impl fmt::Display for Error {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 write!(f, "{}", self.message)
35 }
36}
37
38impl std::error::Error for Error {}
39
40impl From<pkgcraft::Error> for Error {
41 fn from(e: pkgcraft::Error) -> Self {
42 use pkgcraft::Error::*;
43 let kind = match &e {
44 Config(_) => ErrorKind::Config,
45 InvalidPkg { .. } => ErrorKind::Pkg,
46 InvalidRepo { .. } => ErrorKind::Repo,
47 RepoInit(_) => ErrorKind::Repo,
48 _ => ErrorKind::Pkgcraft,
49 };
50
51 Error { message: e.to_string(), kind }
52 }
53}
54
55impl From<std::str::Utf8Error> for Error {
56 fn from(e: std::str::Utf8Error) -> Self {
57 Error::new(e)
58 }
59}
60
61impl From<std::ffi::NulError> for Error {
62 fn from(e: std::ffi::NulError) -> Self {
63 Error::new(e)
64 }
65}
66
67impl From<&str> for Error {
68 fn from(e: &str) -> Self {
69 Error::new(e)
70 }
71}
72
73#[repr(C)]
74pub struct PkgcraftError {
75 message: *mut c_char,
76 kind: ErrorKind,
77}
78
79impl From<Error> for PkgcraftError {
80 fn from(e: Error) -> Self {
81 PkgcraftError {
82 message: try_ptr_from_str!(e.message),
83 kind: e.kind,
84 }
85 }
86}
87
88impl Drop for PkgcraftError {
89 fn drop(&mut self) {
90 unsafe {
91 drop(CString::from_raw(self.message));
92 }
93 }
94}
95
96thread_local! {
97 static LAST_ERROR: RefCell<Option<Error>> = const { RefCell::new(None) };
98}
99
100pub(crate) fn update_last_error<E: Into<Error> + fmt::Debug>(err: E) {
102 LAST_ERROR.with(|prev| *prev.borrow_mut() = Some(err.into()));
103}
104
105#[no_mangle]
107pub extern "C" fn pkgcraft_error_last() -> *mut PkgcraftError {
108 match LAST_ERROR.with(|prev| prev.borrow_mut().take()) {
109 Some(e) => Box::into_raw(Box::new(e.into())),
110 None => ptr::null_mut(),
111 }
112}
113
114#[no_mangle]
119pub unsafe extern "C" fn pkgcraft_error_free(e: *mut PkgcraftError) {
120 if !e.is_null() {
121 unsafe { drop(Box::from_raw(e)) };
122 }
123}