nvim_types/
error.rs

1use std::error::Error as StdError;
2use std::ffi::{c_char, CStr, CString};
3use std::fmt;
4
5use thiserror::Error as ThisError;
6
7// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L64
8//
9/// Binding to the error type used by Neovim.
10#[derive(Clone, ThisError, Eq, PartialEq, Hash)]
11#[repr(C)]
12pub struct Error {
13    r#type: ErrorType,
14    msg: *mut c_char,
15}
16
17unsafe impl Send for Error {}
18unsafe impl Sync for Error {}
19
20// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L27
21#[derive(Copy, Clone, Eq, PartialEq, Hash)]
22#[repr(C)]
23enum ErrorType {
24    None = -1,
25    Exception,
26    #[allow(dead_code)]
27    Validation,
28}
29
30impl Error {
31    pub const fn new() -> Self {
32        Self { r#type: ErrorType::None, msg: std::ptr::null_mut() }
33    }
34}
35
36impl Default for Error {
37    #[inline]
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl fmt::Debug for Error {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        fmt::Display::fmt(self, f)
46    }
47}
48
49impl fmt::Display for Error {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        if !self.msg.is_null() {
52            fmt::Debug::fmt(unsafe { CStr::from_ptr(self.msg) }, f)
53        } else {
54            use ErrorType::*;
55            let msg = match self.r#type {
56                None => return Ok(()),
57                Exception => "exception",
58                Validation => "validation",
59            };
60            write!(f, "{}", msg)
61        }
62    }
63}
64
65impl Error {
66    pub(crate) fn from_str<S: Into<String>>(s: S) -> Self {
67        let c_string = CString::new(s.into()).unwrap_or_default();
68        let ptr = c_string.into_raw() /* TODO: memory leak */;
69        Self { r#type: ErrorType::Exception, msg: ptr }
70    }
71
72    pub fn from_err<E: StdError>(err: E) -> Self {
73        Self::from_str(err.to_string())
74    }
75
76    pub fn is_err(&self) -> bool {
77        !matches!(self.r#type, ErrorType::None)
78    }
79}