1use std::{error::Error, fmt};
2
3#[derive(Clone, Copy, Debug)]
5#[non_exhaustive]
6pub enum DecodingError {
7 InvalidHeader(&'static str),
9 MissingTag(usize),
11 InvalidCellIndex {
13 reason: &'static str,
15 source: Option<h3o::error::InvalidCellIndex>,
17 },
18 NotEnoughData,
20}
21
22impl DecodingError {
23 pub(crate) const fn bad_header(reason: &'static str) -> Self {
24 Self::InvalidHeader(reason)
25 }
26
27 pub(crate) const fn missing_tag(position: usize) -> Self {
28 Self::MissingTag(position)
29 }
30
31 pub(crate) const fn bad_index(
32 reason: &'static str,
33 source: Option<h3o::error::InvalidCellIndex>,
34 ) -> Self {
35 Self::InvalidCellIndex { reason, source }
36 }
37
38 pub(crate) const fn not_enough_data() -> Self {
39 Self::NotEnoughData
40 }
41}
42
43impl fmt::Display for DecodingError {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match *self {
46 Self::InvalidHeader(reason) => {
47 write!(f, "header error: {reason}")
48 }
49 Self::MissingTag(position) => {
50 write!(f, "missing tag bit at {position}")
51 }
52 Self::InvalidCellIndex { reason, .. } => {
53 write!(f, "invalid cell index: {reason}")
54 }
55 Self::NotEnoughData => write!(f, "truncated input"),
56 }
57 }
58}
59
60impl Error for DecodingError {
61 fn source(&self) -> Option<&(dyn Error + 'static)> {
62 if let Self::InvalidCellIndex {
63 source: Some(ref source),
64 ..
65 } = *self
66 {
67 return Some(source);
68 }
69 None
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use h3o::CellIndex;
77
78 #[test]
80 fn display() {
81 assert!(!DecodingError::bad_header("invalid header")
82 .to_string()
83 .is_empty());
84
85 assert!(!DecodingError::missing_tag(42).to_string().is_empty());
86
87 assert!(!DecodingError::bad_index("invalid cell index", None)
88 .to_string()
89 .is_empty());
90
91 assert!(!DecodingError::not_enough_data().to_string().is_empty());
92 }
93
94 #[test]
96 fn source() {
97 assert!(DecodingError::bad_header("invalid header")
98 .source()
99 .is_none());
100
101 assert!(DecodingError::missing_tag(42).source().is_none());
102
103 assert!(DecodingError::bad_index("invalid cell index", None)
104 .source()
105 .is_none());
106 assert!(DecodingError::bad_index(
107 "not a cell index",
108 CellIndex::try_from(0).err()
109 )
110 .source()
111 .is_some());
112
113 assert!(DecodingError::not_enough_data().source().is_none());
114 }
115}