1use core::error::Error;
2use core::fmt::Display;
3use crate::source::ChiselSourceError;
4
5#[derive(Debug)]
7pub enum ChiselErrorData<F, S> {
8	Format(F),
10	Source(S),
12	EndOfInput
14}
15
16#[derive(Debug)]
29pub struct ChiselError<F, S> {
30	pub offset: usize,
36	pub error: ChiselErrorData<F, S>
38}
39
40impl<F, S> ChiselError<F, S> {
41	pub fn new(offset: usize, error: ChiselErrorData<F, S>) -> Self { Self { offset, error } }
43	pub fn end_of_input(offset: usize) -> Self { Self { offset, error: ChiselErrorData::EndOfInput } }
45	pub fn source(offset: usize, error: S) -> Self { Self { offset, error: ChiselErrorData::Source(error) } }
47	pub fn format(offset: usize, error: F) -> Self { Self { offset, error: ChiselErrorData::Format(error) } }
49
50	pub fn map<M : FnOnce(F) -> N, N>(self, mapper: M) -> ChiselError<N, S> {
58		ChiselError {
59			offset: self.offset,
60			error: match self.error {
61				ChiselErrorData::EndOfInput => ChiselErrorData::EndOfInput,
62				ChiselErrorData::Format(x) => ChiselErrorData::Format(mapper(x)),
63				ChiselErrorData::Source(x) => ChiselErrorData::Source(x)
64			}
65		}
66	}
67}
68
69fn static_unreachable(proof: core::convert::Infallible) -> ! {
74	match proof {}
75}
76
77impl<S> ChiselError<core::convert::Infallible, S> {
78	pub fn from_source(offset: usize, error: ChiselSourceError<S>) -> Self {
80		match error {
81			ChiselSourceError::Underlying(x) => Self::source(offset, x),
82			ChiselSourceError::EndOfInput => Self::end_of_input(offset)
83		}
84	}
85
86	pub fn forward<F>(self) -> ChiselError<F, S> {
95		ChiselError {
96			error: match self.error {
97				ChiselErrorData::EndOfInput => ChiselErrorData::EndOfInput,
98				ChiselErrorData::Source(x) => ChiselErrorData::Source(x),
99				ChiselErrorData::Format(x) => { static_unreachable(x) }
100			},
101			offset: self.offset
102		}
103	}
104}
105
106impl<F : Display, S : Display> Display for ChiselError<F, S> {
107	fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
108		f.write_str("couldn't decode: ")?;
109		match &self.error {
110			ChiselErrorData::Format(x) => write!(f, "bad data: {x}"),
111			ChiselErrorData::Source(x) => write!(f, "input error: {x}"),
112			ChiselErrorData::EndOfInput => f.write_str("unexpected end of data")
113		}?;
114		write!(f, " near offset 0x{:08x}", self.offset)
115	}
116}
117
118impl<F : Error + 'static, S : Error + 'static> Error for ChiselError<F, S> {
119	fn cause(&self) -> Option<&(dyn Error + 'static)> {
120		match &self.error {
121			ChiselErrorData::Format(x) => Some(x),
122			ChiselErrorData::Source(x) => Some(x),
123			ChiselErrorData::EndOfInput => None
124		}
125	}
126}