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}