Skip to main content

graphannis_capi/
cerror.rs

1use super::cast_const;
2use super::data::{vec_get, vec_size};
3use graphannis::errors;
4use libc::{c_char, size_t};
5use std::error::Error as StdError;
6use std::ffi::CString;
7
8/// An representation of an internal error.
9pub struct Error {
10    /// The message for the user.
11    pub msg: CString,
12    // The general kind or type of error.
13    pub kind: CString,
14}
15
16/// A list of multiple errors.
17pub type ErrorList = Vec<Error>;
18
19struct CauseIterator<'a> {
20    current: Option<&'a dyn StdError>,
21}
22
23impl std::iter::Iterator for CauseIterator<'_> {
24    type Item = Error;
25
26    fn next(&mut self) -> std::option::Option<Error> {
27        let std_error = self.current?;
28        let result = Error {
29            msg: CString::new(std_error.to_string()).unwrap_or_default(),
30            kind: CString::new("Cause").unwrap_or_default(),
31        };
32        self.current = std_error.source();
33        Some(result)
34    }
35}
36
37#[allow(clippy::borrowed_box)]
38fn error_kind(e: &Box<dyn StdError>) -> &'static str {
39    if let Some(annis_err) = e.downcast_ref::<errors::GraphAnnisError>() {
40        annis_err.into()
41    } else {
42        // Check for several known types
43        if e.is::<std::io::Error>() {
44            "IO"
45        } else if e.is::<log::SetLoggerError>() {
46            "SetLoggerError"
47        } else {
48            "Unknown"
49        }
50    }
51}
52
53pub fn create_error_list(e: Box<dyn StdError>) -> ErrorList {
54    let mut result = vec![Error {
55        msg: CString::new(e.to_string()).unwrap_or_default(),
56        kind: CString::new(error_kind(&e)).unwrap_or_default(),
57    }];
58    let cause_it = CauseIterator {
59        current: e.source(),
60    };
61    for e in cause_it {
62        result.push(e)
63    }
64    result
65}
66
67impl From<log::SetLoggerError> for Error {
68    fn from(e: log::SetLoggerError) -> Error {
69        if let Ok(error_msg) = CString::new(e.to_string()) {
70            Error {
71                msg: error_msg,
72                kind: CString::new("SetLoggerError").unwrap(),
73            }
74        } else {
75            // meta-error
76            Error {
77                msg: CString::new(String::from("Some error occurred")).unwrap(),
78                kind: CString::new("SetLoggerError").unwrap(),
79            }
80        }
81    }
82}
83
84impl From<std::io::Error> for Error {
85    fn from(e: std::io::Error) -> Error {
86        if let Ok(error_msg) = CString::new(e.to_string()) {
87            Error {
88                msg: error_msg,
89                kind: CString::new("std::io::Error").unwrap(),
90            }
91        } else {
92            // meta-error
93            Error {
94                msg: CString::new(String::from("Some error occurred")).unwrap(),
95                kind: CString::new("std::io::Error").unwrap(),
96            }
97        }
98    }
99}
100/// Creates a new error from the internal type
101pub fn new(err: Box<dyn StdError>) -> *mut ErrorList {
102    Box::into_raw(Box::new(create_error_list(err)))
103}
104
105/// Returns the number of errors in the list.
106#[unsafe(no_mangle)]
107pub extern "C" fn annis_error_size(ptr: *const ErrorList) -> size_t {
108    vec_size(ptr)
109}
110
111/// Get the message for the error at position `i` in the list.
112#[unsafe(no_mangle)]
113pub extern "C" fn annis_error_get_msg(ptr: *const ErrorList, i: size_t) -> *const c_char {
114    let item = vec_get(ptr, i);
115    if item.is_null() {
116        return std::ptr::null();
117    }
118    let err: &Error = cast_const(item);
119    err.msg.as_ptr()
120}
121
122/// Get the kind or type for the error at position `i` in the list.
123#[unsafe(no_mangle)]
124pub extern "C" fn annis_error_get_kind(ptr: *const ErrorList, i: size_t) -> *const c_char {
125    let item = vec_get(ptr, i);
126    if item.is_null() {
127        return std::ptr::null();
128    }
129    let err: &Error = cast_const(item);
130    err.kind.as_ptr()
131}