utf8_rune/
errors.rs

1#[derive(Clone, PartialEq, Eq)]
2pub enum Error<'g> {
3    InvalidIndex(usize, &'g [u8]),
4    UnexpectedContinuationByte(u8, usize, Option<usize>, Option<usize>, &'g [u8]),
5    Utf8Error(usize, &'g [u8], String),
6}
7impl<'g> Error<'g> {
8    pub fn previous_valid_cutoff(&self) -> Option<usize> {
9        match self {
10            Error::InvalidIndex(_, _) => None,
11            Error::UnexpectedContinuationByte(_, _, previous, _, _) => previous.clone(),
12            Error::Utf8Error(_, _, _) => None,
13        }
14    }
15
16    pub fn next_valid_cutoff(&self) -> Option<usize> {
17        match self {
18            Error::InvalidIndex(_, _) => None,
19            Error::UnexpectedContinuationByte(_, _, _, next, _) => next.clone(),
20            Error::Utf8Error(_, _, _) => None,
21        }
22    }
23}
24impl<'g> std::fmt::Display for Error<'g> {
25    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
26        fn format_slice(slice: &[u8], index: usize) -> String {
27            format!(
28                "[{}]",
29                slice
30                    .into_iter()
31                    .enumerate()
32                    .map(|(i,byte)| if i == index {
33                        format!("\x1b[1;38;5;220m0x{byte:02x}\x1b[0m")
34                    } else {
35                        format!("0x{byte:02x}")
36
37                    })
38                    .collect::<Vec<String>>()
39                    .join(", ")
40            )
41        }
42        write!(
43            f,
44            "{}",
45            match self {
46                Error::InvalidIndex(index, slice) => {
47                    let length = slice.len();
48                    format!(
49                        "invalid index {index}: {index} > {length} in {}",
50                        format_slice(slice, *index)
51                    )
52                },
53                Error::Utf8Error(index, slice, error) => {
54                    format!(
55                        "Utf8Error in index {index} of {}: {error}",
56                        format_slice(slice, *index)
57                    )
58                },
59                Error::UnexpectedContinuationByte(
60                    byte,
61                    index,
62                    previous_valid_cutoff,
63                    next_valid_cutoff,
64                    slice,
65                ) => {
66                    [
67                        Some(format!(
68                        "unexpected continuation byte 0x{byte:02x}(0b{byte:08b}) at index {index} of {}",format_slice(slice, *index)
69                        )),
70                        previous_valid_cutoff.map(|previous|format!("previous valid cutoff index: {previous}")),
71                        next_valid_cutoff.map(|next|format!("next valid cutoff index: {next}")),
72                    ].into_iter().filter(|c|c.is_some()).map(|c|c.unwrap().to_string()).collect::<Vec<String>>().join("\n")
73                },
74            }
75        )
76    }
77}
78impl<'g> std::fmt::Debug for Error<'g> {
79    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
80        write!(f, "{self}")
81    }
82}
83impl<'g> std::error::Error for Error<'g> {}
84pub type Result<T> = std::result::Result<T, Error<'static>>;