1use serde::{de, ser};
2use static_assertions::assert_impl_all;
3use std::{convert::Infallible, error, fmt, io, result, sync::Arc};
4
5/// Enum representing the max depth exceeded error.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum MaxDepthExceeded {
8 /// The maximum allowed depth for structures in encoding was exceeded.
9 Structure,
10 /// The maximum allowed depth for arrays in encoding was exceeded.
11 Array,
12 /// The maximum allowed depth for containers in encoding was exceeded.
13 Container,
14}
15
16impl fmt::Display for MaxDepthExceeded {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 match self {
19 Self::Structure => write!(
20 f,
21 "Maximum allowed depth for structures in encoding was exceeded"
22 ),
23 Self::Array => write!(
24 f,
25 "Maximum allowed depth for arrays in encoding was exceeded"
26 ),
27 Self::Container => write!(
28 f,
29 "Maximum allowed depth for containers in encoding was exceeded"
30 ),
31 }
32 }
33}
34
35/// Error type used by zvariant API.
36#[derive(Debug)]
37#[non_exhaustive]
38pub enum Error {
39 /// Generic error. All serde errors gets transformed into this variant.
40 Message(String),
41
42 /// Wrapper for [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)
43 InputOutput(Arc<io::Error>),
44 /// Type conversions errors.
45 IncorrectType,
46 /// Wrapper for [`std::str::Utf8Error`](https://doc.rust-lang.org/std/str/struct.Utf8Error.html)
47 Utf8(std::str::Utf8Error),
48 /// Non-0 padding byte(s) encountered.
49 PaddingNot0(u8),
50 /// The deserialized file descriptor is not in the given FD index.
51 UnknownFd,
52 /// Missing framing offset at the end of a GVariant-encoded container,
53 MissingFramingOffset,
54 /// The type (signature as first argument) being (de)serialized is not supported by the format.
55 IncompatibleFormat(crate::Signature<'static>, crate::serialized::Format),
56 /// The provided signature (first argument) was not valid for reading as the requested type.
57 /// Details on the expected signatures are in the second argument.
58 SignatureMismatch(crate::Signature<'static>, String),
59 /// Out of bounds range specified.
60 OutOfBounds,
61 /// The maximum allowed depth for containers in encoding was exceeded.
62 MaxDepthExceeded(MaxDepthExceeded),
63}
64
65assert_impl_all!(Error: Send, Sync, Unpin);
66
67impl PartialEq for Error {
68 fn eq(&self, other: &Self) -> bool {
69 match (self, other) {
70 (Error::Message(msg: &String), Error::Message(other: &String)) => msg == other,
71 // Io is false
72 (Error::IncorrectType, Error::IncorrectType) => true,
73 (Error::Utf8(msg: &Utf8Error), Error::Utf8(other: &Utf8Error)) => msg == other,
74 (Error::PaddingNot0(p: &u8), Error::PaddingNot0(other: &u8)) => p == other,
75 (Error::UnknownFd, Error::UnknownFd) => true,
76 (Error::MaxDepthExceeded(max1: &MaxDepthExceeded), Error::MaxDepthExceeded(max2: &MaxDepthExceeded)) => max1 == max2,
77 (_, _) => false,
78 }
79 }
80}
81
82impl error::Error for Error {
83 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
84 match self {
85 Error::InputOutput(e: &Arc) => Some(e),
86 Error::Utf8(e: &Utf8Error) => Some(e),
87 _ => None,
88 }
89 }
90}
91
92impl fmt::Display for Error {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 match self {
95 Error::Message(s) => write!(f, "{s}"),
96 Error::InputOutput(e) => e.fmt(f),
97 Error::IncorrectType => write!(f, "incorrect type"),
98 Error::Utf8(e) => write!(f, "{e}"),
99 Error::PaddingNot0(b) => write!(f, "Unexpected non-0 padding byte `{b}`"),
100 Error::UnknownFd => write!(f, "File descriptor not in the given FD index"),
101 Error::MissingFramingOffset => write!(
102 f,
103 "Missing framing offset at the end of GVariant-encoded container"
104 ),
105 Error::IncompatibleFormat(sig, format) => {
106 write!(f, "Type `{sig}` is not compatible with `{format}` format",)
107 }
108 Error::SignatureMismatch(provided, expected) => write!(
109 f,
110 "Signature mismatch: got `{provided}`, expected {expected}",
111 ),
112 Error::OutOfBounds => write!(
113 f,
114 // FIXME: using the `Debug` impl of `Range` because it doesn't impl `Display`.
115 "Out of bounds range specified",
116 ),
117 Error::MaxDepthExceeded(max) => write!(f, "{max}"),
118 }
119 }
120}
121
122impl Clone for Error {
123 fn clone(&self) -> Self {
124 match self {
125 Error::Message(s: &String) => Error::Message(s.clone()),
126 Error::InputOutput(e: &Arc) => Error::InputOutput(e.clone()),
127 Error::IncorrectType => Error::IncorrectType,
128 Error::Utf8(e: &Utf8Error) => Error::Utf8(*e),
129 Error::PaddingNot0(b: &u8) => Error::PaddingNot0(*b),
130 Error::UnknownFd => Error::UnknownFd,
131 Error::MissingFramingOffset => Error::MissingFramingOffset,
132 Error::IncompatibleFormat(sig: &Signature<'static>, format: &Format) => {
133 Error::IncompatibleFormat(sig.clone(), *format)
134 }
135 Error::SignatureMismatch(provided: &Signature<'static>, expected: &String) => {
136 Error::SignatureMismatch(provided.clone(), expected.clone())
137 }
138 Error::OutOfBounds => Error::OutOfBounds,
139 Error::MaxDepthExceeded(max: &MaxDepthExceeded) => Error::MaxDepthExceeded(*max),
140 }
141 }
142}
143
144impl From<Infallible> for Error {
145 fn from(i: Infallible) -> Self {
146 match i {}
147 }
148}
149
150impl de::Error for Error {
151 // TODO: Add more specific error variants to Error enum above so we can implement other methods
152 // here too.
153 fn custom<T>(msg: T) -> Error
154 where
155 T: fmt::Display,
156 {
157 Error::Message(msg.to_string())
158 }
159}
160
161impl ser::Error for Error {
162 fn custom<T>(msg: T) -> Error
163 where
164 T: fmt::Display,
165 {
166 Error::Message(msg.to_string())
167 }
168}
169
170impl From<io::Error> for Error {
171 fn from(val: io::Error) -> Self {
172 Error::InputOutput(Arc::new(data:val))
173 }
174}
175
176/// Alias for a `Result` with the error type `zvariant::Error`.
177pub type Result<T> = result::Result<T, Error>;
178