Skip to main content

perde_core/
error.rs

1use pyo3::{exceptions::PyRuntimeError, PyErr, Python};
2use serde::{de, ser};
3use std::fmt::{self, Display};
4
5pub type Result<T> = std::result::Result<T, Error>;
6
7#[derive(Debug)]
8pub struct Error {
9    pyerr: PyErr,
10    hints: Vec<String>,
11}
12
13#[macro_export]
14macro_rules! err {
15    ($($t:tt)*) => {
16        $crate::error::Error::new(format!($($t)*))
17    }
18}
19
20#[macro_export]
21macro_rules! bail {
22    ($($t:tt)*) => {
23        return Err($crate::err!($($t)*));
24    }
25}
26
27impl Error {
28    pub fn new<T>(t: T) -> Self
29    where
30        T: ToString,
31    {
32        let py = unsafe { Python::assume_gil_acquired() };
33
34        let pyerr = if PyErr::occurred(py) {
35            PyErr::fetch(py)
36        } else {
37            PyErr::new::<PyRuntimeError, _>(t.to_string())
38        };
39
40        Self {
41            pyerr,
42            hints: vec![t.to_string()],
43        }
44    }
45}
46
47impl<T> From<T> for Error
48where
49    T: std::error::Error,
50{
51    fn from(e: T) -> Self {
52        Self::new(e)
53    }
54}
55
56impl Display for Error {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        write!(f, "{}", self.pyerr)
59    }
60}
61
62pub trait Convert<T> {
63    fn de<E>(self) -> std::result::Result<T, E>
64    where
65        E: de::Error,
66        Self: Sized;
67
68    fn ser<E>(self) -> std::result::Result<T, E>
69    where
70        E: ser::Error,
71        Self: Sized;
72
73    fn restore(self) -> Option<T>
74    where
75        Self: Sized;
76
77    fn context<C>(self, context: C) -> Result<T>
78    where
79        C: Display + Send + Sync + 'static;
80
81    fn with_context<C, F>(self, f: F) -> Result<T>
82    where
83        C: Display + Send + Sync + 'static,
84        F: FnOnce() -> C;
85}
86
87impl<T> Convert<T> for Result<T> {
88    fn de<E>(self) -> std::result::Result<T, E>
89    where
90        E: de::Error,
91        Self: Sized,
92    {
93        self.map_err(|e| de::Error::custom(e.to_string()))
94    }
95
96    fn ser<E>(self) -> std::result::Result<T, E>
97    where
98        E: ser::Error,
99        Self: Sized,
100    {
101        self.map_err(|e| ser::Error::custom(e.to_string()))
102    }
103
104    fn restore(self) -> Option<T> {
105        match self {
106            Ok(t) => Some(t),
107            Err(e) => {
108                let py = unsafe { Python::assume_gil_acquired() };
109                e.pyerr.restore(py);
110                None
111            }
112        }
113    }
114
115    fn context<C>(mut self, context: C) -> Result<T>
116    where
117        C: Display + Send + Sync + 'static,
118    {
119        if let Err(e) = self.as_mut() {
120            e.hints.push(context.to_string());
121        }
122        self
123    }
124
125    fn with_context<C, F>(mut self, f: F) -> Result<T>
126    where
127        C: Display + Send + Sync + 'static,
128        F: FnOnce() -> C,
129    {
130        if let Err(e) = self.as_mut() {
131            e.hints.push(f().to_string());
132        }
133        self
134    }
135}