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>>;