1use pyo3::PyErr;
2use pyo3::{exceptions::*, DowncastError, DowncastIntoError};
3use serde::{de, ser};
4use std::convert::Infallible;
5use std::error;
6use std::fmt::{self, Debug, Display};
7use std::result;
8
9pub type Result<T> = result::Result<T, PythonizeError>;
11
12pub struct PythonizeError {
14 pub(crate) inner: Box<ErrorImpl>,
15}
16
17impl PythonizeError {
18 pub(crate) fn msg<T>(text: T) -> Self
19 where
20 T: ToString,
21 {
22 Self {
23 inner: Box::new(ErrorImpl::Message(text.to_string())),
24 }
25 }
26
27 pub(crate) fn unsupported_type<T>(t: T) -> Self
28 where
29 T: ToString,
30 {
31 Self {
32 inner: Box::new(ErrorImpl::UnsupportedType(t.to_string())),
33 }
34 }
35
36 pub(crate) fn dict_key_not_string() -> Self {
37 Self {
38 inner: Box::new(ErrorImpl::DictKeyNotString),
39 }
40 }
41
42 pub(crate) fn incorrect_sequence_length(expected: usize, got: usize) -> Self {
43 Self {
44 inner: Box::new(ErrorImpl::IncorrectSequenceLength { expected, got }),
45 }
46 }
47
48 pub(crate) fn invalid_enum_type() -> Self {
49 Self {
50 inner: Box::new(ErrorImpl::InvalidEnumType),
51 }
52 }
53
54 pub(crate) fn invalid_length_enum() -> Self {
55 Self {
56 inner: Box::new(ErrorImpl::InvalidLengthEnum),
57 }
58 }
59
60 pub(crate) fn invalid_length_char() -> Self {
61 Self {
62 inner: Box::new(ErrorImpl::InvalidLengthChar),
63 }
64 }
65}
66
67#[derive(Debug)]
69pub enum ErrorImpl {
70 PyErr(PyErr),
72 Message(String),
74 UnsupportedType(String),
76 UnexpectedType(String),
78 DictKeyNotString,
80 IncorrectSequenceLength { expected: usize, got: usize },
82 InvalidEnumType,
84 InvalidLengthEnum,
86 InvalidLengthChar,
88}
89
90impl error::Error for PythonizeError {}
91
92impl Display for PythonizeError {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 match self.inner.as_ref() {
95 ErrorImpl::PyErr(e) => Display::fmt(e, f),
96 ErrorImpl::Message(s) => Display::fmt(s, f),
97 ErrorImpl::UnsupportedType(s) => write!(f, "unsupported type {}", s),
98 ErrorImpl::UnexpectedType(s) => write!(f, "unexpected type: {}", s),
99 ErrorImpl::DictKeyNotString => f.write_str("dict keys must have type str"),
100 ErrorImpl::IncorrectSequenceLength { expected, got } => {
101 write!(f, "expected sequence of length {}, got {}", expected, got)
102 }
103 ErrorImpl::InvalidEnumType => f.write_str("expected either a str or dict for enum"),
104 ErrorImpl::InvalidLengthEnum => {
105 f.write_str("expected tagged enum dict to have exactly 1 key")
106 }
107 ErrorImpl::InvalidLengthChar => f.write_str("expected a str of length 1 for char"),
108 }
109 }
110}
111
112impl Debug for PythonizeError {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 self.inner.as_ref().fmt(f)
115 }
116}
117
118impl ser::Error for PythonizeError {
119 fn custom<T>(msg: T) -> Self
120 where
121 T: Display,
122 {
123 Self {
124 inner: Box::new(ErrorImpl::Message(msg.to_string())),
125 }
126 }
127}
128
129impl de::Error for PythonizeError {
130 fn custom<T>(msg: T) -> Self
131 where
132 T: Display,
133 {
134 Self {
135 inner: Box::new(ErrorImpl::Message(msg.to_string())),
136 }
137 }
138}
139
140impl From<Infallible> for PythonizeError {
142 fn from(other: Infallible) -> Self {
143 match other {}
144 }
145}
146
147impl From<PyErr> for PythonizeError {
149 fn from(other: PyErr) -> Self {
150 Self {
151 inner: Box::new(ErrorImpl::PyErr(other)),
152 }
153 }
154}
155
156impl<'a, 'py> From<DowncastError<'a, 'py>> for PythonizeError {
158 fn from(other: DowncastError<'a, 'py>) -> Self {
159 Self {
160 inner: Box::new(ErrorImpl::UnexpectedType(other.to_string())),
161 }
162 }
163}
164
165impl<'py> From<DowncastIntoError<'py>> for PythonizeError {
167 fn from(other: DowncastIntoError<'py>) -> Self {
168 Self {
169 inner: Box::new(ErrorImpl::UnexpectedType(other.to_string())),
170 }
171 }
172}
173
174impl From<PythonizeError> for PyErr {
176 fn from(other: PythonizeError) -> Self {
177 match *other.inner {
178 ErrorImpl::PyErr(e) => e,
179 ErrorImpl::Message(e) => PyException::new_err(e),
180 ErrorImpl::UnsupportedType(_)
181 | ErrorImpl::UnexpectedType(_)
182 | ErrorImpl::DictKeyNotString
183 | ErrorImpl::InvalidEnumType => PyTypeError::new_err(other.to_string()),
184 ErrorImpl::IncorrectSequenceLength { .. }
185 | ErrorImpl::InvalidLengthEnum
186 | ErrorImpl::InvalidLengthChar => PyValueError::new_err(other.to_string()),
187 }
188 }
189}