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
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

#[derive(Copy, Eq, PartialEq, Clone, Debug)]
pub struct Utf8Error {
    pub(crate) valid_up_to: usize,
    pub(crate) error_len: Option<u8>,
}

impl Utf8Error {
    #[must_use]
    #[inline]
    pub const fn valid_up_to(&self) -> usize {
        self.valid_up_to
    }

    #[must_use]
    #[inline]
    pub const fn error_len(&self) -> Option<usize> {
        // Manual implementation of Option::map since it's not const
        match self.error_len {
            Some(len) => Some(len as usize),
            None => None,
        }
    }

    #[must_use]
    #[inline]
    pub(crate) const fn from_std(value: std::str::Utf8Error) -> Self {
        Self {
            valid_up_to: value.valid_up_to(),
            // Manual implementation of Option::map since it's not const
            error_len: match value.error_len() {
                Some(error_len) => Some(error_len as u8),
                None => None,
            },
        }
    }
}

impl Display for Utf8Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if let Some(error_len) = self.error_len {
            write!(
                f,
                "invalid utf-8 sequence of {} bytes from index {}",
                error_len, self.valid_up_to
            )
        } else {
            write!(
                f,
                "incomplete utf-8 byte sequence from index {}",
                self.valid_up_to
            )
        }
    }
}

impl From<std::str::Utf8Error> for Utf8Error {
    #[inline]
    fn from(value: std::str::Utf8Error) -> Self {
        Self::from_std(value)
    }
}

impl Error for Utf8Error {}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FromUtf8Error {
    pub(crate) bytes: Vec<u8>,
    pub(crate) error: Utf8Error,
}

impl FromUtf8Error {
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }

    #[must_use]
    pub fn into_bytes(self) -> Vec<u8> {
        self.bytes
    }

    pub fn utf8_error(&self) -> Utf8Error {
        self.error
    }
}

impl Display for FromUtf8Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Display::fmt(&self.error, f)
    }
}

impl Error for FromUtf8Error {}

#[derive(Copy, Eq, PartialEq, Clone, Debug)]
pub enum ParseError<E> {
    InvalidUtf8(Utf8Error),
    Err(E),
}

impl<E> Display for ParseError<E>
where
    E: Display,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            ParseError::InvalidUtf8(err) => Display::fmt(err, f),
            ParseError::Err(err) => Display::fmt(err, f),
        }
    }
}

impl<E> Error for ParseError<E>
where
    E: Error + 'static,
{
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            ParseError::InvalidUtf8(err) => Some(err),
            ParseError::Err(err) => Some(err),
        }
    }
}