extern crate core;
use core::fmt::{self,Display,Formatter};
use core::ops::RangeInclusive;
#[cfg(feature="std")]
use std::error::Error;
macro_rules! description {($err:ty, $desc:expr) => {
#[cfg(not(feature="std"))]
impl $err {
#[allow(missing_docs)]
pub fn description(&self) -> &'static str {
($desc)(self)
}
}
#[cfg(feature="std")]
impl Error for $err {
fn description(&self) -> &'static str {
($desc)(self)
}
}
impl Display for $err {
fn fmt(&self, fmtr: &mut Formatter) -> fmt::Result {
#![allow(deprecated)] write!(fmtr, "{}", self.description())
}
}
}}
macro_rules! single_cause {($(#[$doc:meta])* $err:ident => $desc:expr) => {
$(#[$doc])*
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub struct $err;
description!{$err, |_| $desc }
}}
single_cause!{
Utf16FirstUnitError => "is a trailing surrogate"
}
single_cause!{
NonAsciiError => "not an ASCII character"
}
single_cause!{
NonBmpError => "not a codepoint in the basic multilingual plane"
}
single_cause!{
EmptyStrError => "is empty"
}
macro_rules! simple {($(#[$tydoc:meta])* $err:ident {
$( $(#[$vardoc:meta])* $variant:ident => $string:expr, )+
} ) => {
$(#[$tydoc])*
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum $err {
$( $(#[$vardoc])* $variant, )*
}
description!{$err, |e: &$err| match *e {$($err::$variant => $string),*} }
}}
simple!{
CodepointError {
Utf16Reserved => "is reserved for UTF-16 surrogate pairs",
TooHigh => "is higher than the highest codepoint",
}}
use CodepointError::*;
impl CodepointError {
pub const fn error_range(self) -> RangeInclusive<u32> {match self {
Utf16Reserved => 0xd8_00..=0xdf_ff,
TooHigh => 0x00_10_ff_ff..=0xff_ff_ff_ff,
}}
}
simple!{
Utf16ArrayError {
FirstIsTrailingSurrogate => "the first element is a trailing surrogate",
SecondIsNotTrailingSurrogate => "the second element is needed but is not a trailing surrogate",
}}
simple!{
Utf16TupleError {
FirstIsTrailingSurrogate => "the first unit is a trailing surrogate",
SuperfluousSecond => "the second unit is superfluous",
MissingSecond => "the first unit requires a second unit",
SecondIsNotTrailingSurrogate => "the required second unit is not a trailing surrogate",
}}
simple!{
Utf16SliceError {
EmptySlice => "the slice is empty",
FirstIsTrailingSurrogate => "the first unit is a trailing surrogate",
MissingSecond => "the first and only unit requires a second one",
SecondIsNotTrailingSurrogate => "the required second unit is not a trailing surrogate",
}}
simple!{
Utf16PairError {
UnexpectedTrailingSurrogate => "a trailing surrogate was not preceeded by a leading surrogate",
UnmatchedLeadingSurrogate => "a leading surrogate was followed by an unit that was not a trailing surrogate",
Incomplete => "a trailing surrogate was expected when the end was reached",
}}
simple!{
FromStrError {
MultipleCodepoints => "contains more than one codepoint",
Empty => "is empty",
}
}
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub struct Utf8Error {
pub(crate) kind: Utf8ErrorKind,
}
impl Utf8Error {
pub const fn kind(&self) -> Utf8ErrorKind {
self.kind
}
#[cfg(not(feature="std"))]
#[allow(missing_docs)]
pub const fn description(&self) -> &'static str {
utf8_error_description(self.kind)
}
}
#[cfg(feature="std")]
impl Error for Utf8Error {
fn description(&self) -> &'static str {
utf8_error_description(self.kind)
}
}
impl Display for Utf8Error {
fn fmt(&self, fmtr: &mut Formatter) -> fmt::Result {
fmtr.write_str(utf8_error_description(self.kind))
}
}
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum Utf8ErrorKind {
TooFewBytes,
NonUtf8Byte,
UnexpectedContinuationByte,
InterruptedSequence,
OverlongEncoding,
Utf16ReservedCodepoint,
TooHighCodepoint,
}
const fn utf8_error_description(kind: Utf8ErrorKind) -> &'static str {
match kind {
Utf8ErrorKind::TooFewBytes => "too few bytes",
Utf8ErrorKind::NonUtf8Byte => "not UTF-8",
Utf8ErrorKind::UnexpectedContinuationByte => "not UTF-8",
Utf8ErrorKind::InterruptedSequence => "not UTF-8",
Utf8ErrorKind::OverlongEncoding => "malformed input",
Utf8ErrorKind::Utf16ReservedCodepoint => "malformed input",
Utf8ErrorKind::TooHighCodepoint => "invalid character",
}
}
impl PartialEq<Utf8ErrorKind> for Utf8Error {
fn eq(&self, kind: &Utf8ErrorKind) -> bool {
self.kind == *kind
}
}
impl PartialEq<Utf8Error> for Utf8ErrorKind {
fn eq(&self, error: &Utf8Error) -> bool {
*self == error.kind
}
}