//! Errors related to URI templates. use core::fmt; #[cfg(feature = "std")] use std::error; /// Template construction and expansion error kind. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(super) enum ErrorKind { /// Cannot write to the backend. WriteFailed, /// Expression is not closed. ExpressionNotClosed, /// Invalid character. InvalidCharacter, /// Invalid expression. InvalidExpression, /// Invalid percent-encoded triplets. InvalidPercentEncoding, /// Invalid UTF-8 bytes. InvalidUtf8, /// Unexpected value type for the variable. UnexpectedValueType, /// Unsupported operator, including operators reserved for future. UnsupportedOperator, } impl ErrorKind { /// Returns the error message. #[must_use] fn as_str(self) -> &'static str { match self { Self::WriteFailed => "failed to write to the backend writer", Self::ExpressionNotClosed => "expression not closed", Self::InvalidCharacter => "invalid character", Self::InvalidExpression => "invalid expression", Self::InvalidPercentEncoding => "invalid percent-encoded triplets", Self::InvalidUtf8 => "invalid utf-8 byte sequence", Self::UnexpectedValueType => "unexpected value type for the variable", Self::UnsupportedOperator => "unsupported operator", } } } /// Template construction and expansion error. /// // Note that this type should implement `Copy` trait. // To return additional non-`Copy` data as an error, use wrapper type // (as `std::string::FromUtf8Error` contains `std::str::Utf8Error`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Error { /// Error kind. kind: ErrorKind, /// Location (byte position of the error). location: usize, } impl Error { /// Creates a new `Error`. /// /// For internal use. #[inline] #[must_use] pub(super) fn new(kind: ErrorKind, location: usize) -> Self { Self { kind, location } } /// Returns the byte position the error is detected. /// /// NOTE: This is not a part of the public API since the value to be /// returned (i.e., the definition of the "position" of an error) is not /// guaranteed to be stable. #[cfg(test)] pub(super) fn location(&self) -> usize { self.location } } impl fmt::Display for Error { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "invalid URI template: {} (at {}-th byte)", self.kind.as_str(), self.location ) } } #[cfg(feature = "std")] impl error::Error for Error {} /// Error on conversion into a URI template type. // TODO: Unifiable to `types::CreationError`? #[cfg(feature = "alloc")] pub struct CreationError { /// Soruce data. source: T, /// Validation error. error: Error, } #[cfg(feature = "alloc")] impl CreationError { /// Returns the source data. #[must_use] pub fn into_source(self) -> T { self.source } /// Returns the validation error. #[must_use] pub fn validation_error(&self) -> Error { self.error } /// Creates a new `CreationError`. #[must_use] pub(crate) fn new(error: Error, source: T) -> Self { Self { source, error } } } #[cfg(feature = "alloc")] impl fmt::Debug for CreationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CreationError") .field("source", &self.source) .field("error", &self.error) .finish() } } #[cfg(feature = "alloc")] impl Clone for CreationError { fn clone(&self) -> Self { Self { source: self.source.clone(), error: self.error, } } } #[cfg(feature = "alloc")] impl fmt::Display for CreationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.error.fmt(f) } } #[cfg(feature = "std")] impl error::Error for CreationError {}