zvariant/
error.rs

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