tor_bytes/
err.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! Internal: Declare an Error type for tor-bytes

use std::borrow::Cow;
use std::num::NonZeroUsize;

use derive_deftly::{define_derive_deftly, Deftly};
use safelog::Sensitive;
use thiserror::Error;
use tor_error::{into_internal, Bug};

define_derive_deftly! {
    /// `impl PartialEq for Error`
    PartialEqForError expect items:

    impl PartialEq for $ttype {
        fn eq(&self, other: &Self) -> bool {
            match (self, other) {
              $(
                ${when not(vmeta(never_eq))}
                #[allow(deprecated)]
                (${vpat fprefix=a_}, ${vpat fprefix=b_}) => {
                  $(
                    if $<a_ $fname> != $<b_ $fname> { return false; }
                  )
                    return true;
                },
              )
                (_, _) => false,
            }
        }
    }
}

/// Error type for decoding Tor objects from bytes.
//
// TODO(nickm): This error type could use a redesign: it doesn't do a good job
// of preserving context.  At the least it should say what kind of object it
// found any given problem in.
#[derive(Error, Debug, Clone, Deftly)]
#[derive_deftly(PartialEqForError)]
#[non_exhaustive]
pub enum Error {
    /// Something was truncated
    ///
    /// It might be an inner data structure, or the outer message being parsed.
    #[deprecated(since = "0.22.0", note = "Use Reader::incomplete_error instead.")]
    #[error("something was truncated (maybe inner structure, maybe outer message)")]
    Truncated,
    /// Tried to read something, but we didn't find enough bytes.
    ///
    /// This can means that the outer object is truncated.
    /// Possibly we need to read more and try again,
    ///
    /// This error is only returned by [`Reader`](crate::Reader)s created with
    /// [`from_possibly_incomplete_slice`](crate::Reader::from_possibly_incomplete_slice).
    ///
    /// # Do not directly construct this variant
    ///
    /// It is usually a bug to explicitly construct this variant.
    /// Use [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
    ///
    /// In tests using
    /// [`Reader::from_slice_for_test`](crate::Reader::from_slice_for_test),
    /// use [`Error::new_incomplete_for_test`].
    #[error("Object truncated (or not fully present), at least {deficit} more bytes needed")]
    Incomplete {
        /// Lower bound on number of additional bytes needed
        deficit: Sensitive<NonZeroUsize>,
    },
    /// Called Reader::should_be_exhausted(), but found bytes anyway.
    #[error("Extra bytes at end of object")]
    ExtraneousBytes,
    /// Invalid length value
    #[error("Object length too large to represent as usize")]
    BadLengthValue,
    /// An attempt to parse an object failed for some reason related to its
    /// contents.
    #[deprecated(since = "0.6.2", note = "Use InvalidMessage instead.")]
    #[error("Bad object: {0}")]
    BadMessage(&'static str),
    /// An attempt to parse an object failed for some reason related to its
    /// contents.
    ///
    /// # General case, more specific variants also exist
    ///
    /// This variant is used when encountering parsing trouble
    /// for which there is no more specific variant.
    ///
    /// Other variants can occur when deserialising malformed messages.
    /// for example (but not necessarily only):
    /// [`ExtraneousBytes`](Error::ExtraneousBytes),
    /// [`MissingData`](Error::MissingData), and
    /// [`BadLengthValue`](Error::BadLengthValue).
    #[error("Bad object: {0}")]
    InvalidMessage(Cow<'static, str>),
    /// The message contains data which is too short (perhaps in an inner counted section)
    ///
    /// # Usually, do not directly construct this variant
    ///
    /// It is often a bug to explicitly construct this variant.
    /// Consider [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
    ///
    /// (It can be appropriate in test cases,
    /// or during bespoke parsing of an inner substructure.)
    #[error("message (or inner portion) too short")]
    MissingData,
    /// A parsing error that should never happen.
    ///
    /// We use this one in lieu of calling assert() and expect() and
    /// unwrap() from within parsing code.
    #[error("Internal error")]
    #[deftly(never_eq)] // an internal error is equal to nothing, not even itself.
    Bug(#[from] tor_error::Bug),
}

impl Error {
    /// Make an [`Error::Incomplete`] with a specified deficit
    ///
    /// Suitable for use in tests.
    ///
    /// # Panics
    ///
    /// Panics if the specified `deficit` is zero.
    pub fn new_incomplete_for_test(deficit: usize) -> Self {
        let deficit = NonZeroUsize::new(deficit)
            .expect("zero deficit in assert!")
            .into();
        Error::Incomplete { deficit }
    }
}

/// Error type for encoding Tor objects to bytes.
#[derive(Error, Debug, Clone)]
#[non_exhaustive]
pub enum EncodeError {
    /// We tried to encode an object with an attached length, but the length was
    /// too large to encode in the available space.
    #[error("Object length too large to encode")]
    BadLengthValue,
    /// A parsing error that should never happen.
    ///
    /// We use this variant instead of calling assert() and expect() and
    /// unwrap() from within encoding implementations.
    #[error("Internal error")]
    Bug(#[from] Bug),
}

impl EncodeError {
    /// Converts this error into a [`Bug`]
    ///
    /// Use when any encoding error is a bug.
    //
    // TODO: should this be a `From` impl or would that be too error-prone?
    #[deprecated(note = "please use the `From<EncodeError>` trait for `Bug` instead")]
    pub fn always_bug(self) -> Bug {
        match self {
            EncodeError::Bug(bug) => bug,
            EncodeError::BadLengthValue => into_internal!("EncodingError")(self),
        }
    }
}

// This trait is used to convert any encoding error into a bug
impl From<EncodeError> for Bug {
    fn from(error: EncodeError) -> Bug {
        match error {
            EncodeError::Bug(bug) => bug,
            EncodeError::BadLengthValue => into_internal!("EncodingError")(error),
        }
    }
}