| 1 | use serde::{de, ser}; |
| 2 | use static_assertions::assert_impl_all; |
| 3 | use 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)] |
| 7 | pub 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 | |
| 16 | impl 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 ] |
| 38 | pub 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 | |
| 65 | assert_impl_all!(Error: Send, Sync, Unpin); |
| 66 | |
| 67 | impl 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 | |
| 82 | impl 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 | |
| 92 | impl 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 | |
| 122 | impl 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 | |
| 144 | impl From<Infallible> for Error { |
| 145 | fn from(i: Infallible) -> Self { |
| 146 | match i {} |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | impl 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 | |
| 161 | impl 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 | |
| 170 | impl 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`. |
| 177 | pub type Result<T> = result::Result<T, Error>; |
| 178 | |