zvariant/
error.rs

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