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),
}
}
}