tor_bytes/err.rs
1//! Internal: Declare an Error type for tor-bytes
2
3use std::borrow::Cow;
4use std::num::NonZeroUsize;
5
6use derive_deftly::{define_derive_deftly, Deftly};
7use safelog::Sensitive;
8use thiserror::Error;
9use tor_error::{into_internal, Bug};
10
11define_derive_deftly! {
12 /// `impl PartialEq for Error`
13 PartialEqForError expect items:
14
15 impl PartialEq for $ttype {
16 fn eq(&self, other: &Self) -> bool {
17 match (self, other) {
18 $(
19 ${when not(vmeta(never_eq))}
20 #[allow(deprecated)]
21 (${vpat fprefix=a_}, ${vpat fprefix=b_}) => {
22 $(
23 if $<a_ $fname> != $<b_ $fname> { return false; }
24 )
25 return true;
26 },
27 )
28 (_, _) => false,
29 }
30 }
31 }
32}
33
34/// Error type for decoding Tor objects from bytes.
35//
36// TODO(nickm): This error type could use a redesign: it doesn't do a good job
37// of preserving context. At the least it should say what kind of object it
38// found any given problem in.
39#[derive(Error, Debug, Clone, Deftly)]
40#[derive_deftly(PartialEqForError)]
41#[non_exhaustive]
42pub enum Error {
43 /// Something was truncated
44 ///
45 /// It might be an inner data structure, or the outer message being parsed.
46 #[deprecated(since = "0.22.0", note = "Use Reader::incomplete_error instead.")]
47 #[error("something was truncated (maybe inner structure, maybe outer message)")]
48 Truncated,
49 /// Tried to read something, but we didn't find enough bytes.
50 ///
51 /// This can means that the outer object is truncated.
52 /// Possibly we need to read more and try again,
53 ///
54 /// This error is only returned by [`Reader`](crate::Reader)s created with
55 /// [`from_possibly_incomplete_slice`](crate::Reader::from_possibly_incomplete_slice).
56 ///
57 /// # Do not directly construct this variant
58 ///
59 /// It is usually a bug to explicitly construct this variant.
60 /// Use [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
61 ///
62 /// In tests using
63 /// [`Reader::from_slice_for_test`](crate::Reader::from_slice_for_test),
64 /// use [`Error::new_incomplete_for_test`].
65 #[error("Object truncated (or not fully present), at least {deficit} more bytes needed")]
66 Incomplete {
67 /// Lower bound on number of additional bytes needed
68 deficit: Sensitive<NonZeroUsize>,
69 },
70 /// Called Reader::should_be_exhausted(), but found bytes anyway.
71 #[error("Extra bytes at end of object")]
72 ExtraneousBytes,
73 /// Invalid length value
74 #[error("Object length too large to represent as usize")]
75 BadLengthValue,
76 /// An attempt to parse an object failed for some reason related to its
77 /// contents.
78 #[deprecated(since = "0.6.2", note = "Use InvalidMessage instead.")]
79 #[error("Bad object: {0}")]
80 BadMessage(&'static str),
81 /// An attempt to parse an object failed for some reason related to its
82 /// contents.
83 ///
84 /// # General case, more specific variants also exist
85 ///
86 /// This variant is used when encountering parsing trouble
87 /// for which there is no more specific variant.
88 ///
89 /// Other variants can occur when deserialising malformed messages.
90 /// for example (but not necessarily only):
91 /// [`ExtraneousBytes`](Error::ExtraneousBytes),
92 /// [`MissingData`](Error::MissingData), and
93 /// [`BadLengthValue`](Error::BadLengthValue).
94 #[error("Bad object: {0}")]
95 InvalidMessage(Cow<'static, str>),
96 /// The message contains data which is too short (perhaps in an inner counted section)
97 ///
98 /// # Usually, do not directly construct this variant
99 ///
100 /// It is often a bug to explicitly construct this variant.
101 /// Consider [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
102 ///
103 /// (It can be appropriate in test cases,
104 /// or during bespoke parsing of an inner substructure.)
105 #[error("message (or inner portion) too short")]
106 MissingData,
107 /// A parsing error that should never happen.
108 ///
109 /// We use this one in lieu of calling assert() and expect() and
110 /// unwrap() from within parsing code.
111 #[error("Internal error")]
112 #[deftly(never_eq)] // an internal error is equal to nothing, not even itself.
113 Bug(#[from] tor_error::Bug),
114}
115
116impl Error {
117 /// Make an [`Error::Incomplete`] with a specified deficit
118 ///
119 /// Suitable for use in tests.
120 ///
121 /// # Panics
122 ///
123 /// Panics if the specified `deficit` is zero.
124 pub fn new_incomplete_for_test(deficit: usize) -> Self {
125 let deficit = NonZeroUsize::new(deficit)
126 .expect("zero deficit in assert!")
127 .into();
128 Error::Incomplete { deficit }
129 }
130}
131
132/// Error type for encoding Tor objects to bytes.
133#[derive(Error, Debug, Clone)]
134#[non_exhaustive]
135pub enum EncodeError {
136 /// We tried to encode an object with an attached length, but the length was
137 /// too large to encode in the available space.
138 #[error("Object length too large to encode")]
139 BadLengthValue,
140 /// A parsing error that should never happen.
141 ///
142 /// We use this variant instead of calling assert() and expect() and
143 /// unwrap() from within encoding implementations.
144 #[error("Internal error")]
145 Bug(#[from] Bug),
146}
147
148impl EncodeError {
149 /// Converts this error into a [`Bug`]
150 ///
151 /// Use when any encoding error is a bug.
152 //
153 // TODO: should this be a `From` impl or would that be too error-prone?
154 #[deprecated(note = "please use the `From<EncodeError>` trait for `Bug` instead")]
155 pub fn always_bug(self) -> Bug {
156 match self {
157 EncodeError::Bug(bug) => bug,
158 EncodeError::BadLengthValue => into_internal!("EncodingError")(self),
159 }
160 }
161}
162
163// This trait is used to convert any encoding error into a bug
164impl From<EncodeError> for Bug {
165 fn from(error: EncodeError) -> Bug {
166 match error {
167 EncodeError::Bug(bug) => bug,
168 EncodeError::BadLengthValue => into_internal!("EncodingError")(error),
169 }
170 }
171}