1use serde::{de, ser};
4use std::collections::TryReserveError;
5use std::{io, num::ParseIntError};
6use thiserror::Error;
7
8pub type Result<T = ()> = std::result::Result<T, Error>;
9
10#[derive(Debug)]
11pub struct Label {
12 pos: usize,
13 message: String,
14}
15
16#[derive(Debug, Error)]
17pub enum Error {
18 #[error("binary parser error: {}", .0.first().map_or_else(|| "io error".to_string(), |f| format!("{} at byte offset {}", f.message, f.pos/2)))]
19 Binread(Vec<Label>),
20
21 #[error(transparent)]
22 Reserve(#[from] TryReserveError),
23
24 #[error("Subtyping error: {0}")]
25 Subtype(String),
26
27 #[error(transparent)]
28 Custom(#[from] anyhow::Error),
29}
30
31impl Error {
32 pub fn msg<T: ToString>(msg: T) -> Self {
33 Error::Custom(anyhow::anyhow!(msg.to_string()))
34 }
35 pub fn subtype<T: ToString>(msg: T) -> Self {
36 Error::Subtype(msg.to_string())
37 }
38}
39
40fn get_binread_labels(e: &binrw::Error) -> Vec<Label> {
41 use binrw::Error::*;
42 match e {
43 BadMagic { pos, .. } => {
44 let pos = (*pos * 2) as usize;
45 vec![Label {
46 pos,
47 message: "Unexpected bytes".to_string(),
48 }]
49 }
50 Custom { pos, err } => {
51 let pos = (*pos * 2) as usize;
52 let message = err
56 .downcast_ref::<&str>()
57 .map(|s| (*s).to_string())
58 .or_else(|| {
59 err.downcast_ref::<crate::binary_parser::Truncated>()
60 .map(|t| t.0.to_string())
61 })
62 .unwrap_or_else(|| "unknown error (there's a bug in error reporting)".to_string());
63 vec![Label { pos, message }]
64 }
65 EnumErrors {
66 pos,
67 variant_errors,
68 } => {
69 let pos = (*pos * 2) as usize;
70 let variant = variant_errors
71 .iter()
72 .find(|(_, e)| !matches!(e, BadMagic { .. }));
73 match variant {
75 None => vec![Label {
76 pos,
77 message: "Unknown opcode".to_string(),
78 }],
79 Some((id, e)) => {
80 let mut labels = get_binread_labels(e);
81 labels.push(Label {
82 pos,
83 message: (*id).to_string(),
84 });
85 labels
86 }
87 }
88 }
89 NoVariantMatch { pos } => {
90 let pos = (*pos * 2) as usize;
91 vec![Label {
92 pos,
93 message: "No variant match".to_string(),
94 }]
95 }
96 AssertFail { pos, message } => {
97 let pos = (*pos * 2) as usize;
98 vec![Label {
99 pos,
100 message: message.to_string(),
101 }]
102 }
103 Io(_) => vec![],
104 Backtrace(backtrace) => get_binread_labels(&backtrace.error),
105 _ => vec![],
109 }
110}
111
112impl ser::Error for Error {
113 fn custom<T: std::fmt::Display>(msg: T) -> Self {
114 Error::msg(format!("Serialize error: {msg}"))
115 }
116}
117
118impl de::Error for Error {
119 fn custom<T: std::fmt::Display>(msg: T) -> Self {
120 let msg = msg.to_string();
121 if let Some(msg) = msg.strip_prefix("Subtyping error: ") {
122 Error::Subtype(msg.to_string())
123 } else {
124 Error::msg(format!("Deserialize error: {msg}"))
125 }
126 }
127 fn invalid_type(_: de::Unexpected<'_>, exp: &dyn de::Expected) -> Self {
128 Error::Subtype(format!("{exp}"))
129 }
130}
131
132impl From<io::Error> for Error {
133 fn from(e: io::Error) -> Error {
134 Error::msg(format!("io error: {e}"))
135 }
136}
137
138impl From<binrw::Error> for Error {
139 fn from(e: binrw::Error) -> Error {
140 Error::Binread(get_binread_labels(&e))
141 }
142}
143
144impl From<ParseIntError> for Error {
145 fn from(e: ParseIntError) -> Error {
146 Error::msg(format!("ParseIntError: {e}"))
147 }
148}