//! Internal: Declare an Error type for tor-bytes use std::borrow::Cow; use std::num::NonZeroUsize; use derive_deftly::{Deftly, define_derive_deftly}; use safelog::Sensitive; use thiserror::Error; use tor_error::{Bug, into_internal}; 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 $ != $ { 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, }, /// 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), /// Using for reader.rs::take_until_with_limit /// If we reach the limit before finding the terminator, we return this error. #[error("Reached limit of {limit} bytes while searching for terminator 0x{terminator:02x}")] LimitExceeded { /// Maximum number of bytes that were allowed to read limit: usize, /// The terminator byte we were looking for terminator: u8, }, } 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` 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 for Bug { fn from(error: EncodeError) -> Bug { match error { EncodeError::Bug(bug) => bug, EncodeError::BadLengthValue => into_internal!("EncodingError")(error), } } }