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: &binread::Error) -> Vec<Label> {
41 use binread::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 err = err
53 .downcast_ref::<&str>()
54 .unwrap_or(&"unknown error (there's a bug in error reporting)");
55 vec![Label {
56 pos,
57 message: (*err).to_string(),
58 }]
59 }
60 EnumErrors {
61 pos,
62 variant_errors,
63 } => {
64 let pos = (pos * 2) as usize;
65 let variant = variant_errors
66 .iter()
67 .find(|(_, e)| !matches!(e, BadMagic { .. }));
68 match variant {
70 None => vec![Label {
71 pos,
72 message: "Unknown opcode".to_string(),
73 }],
74 Some((id, e)) => {
75 let mut labels = get_binread_labels(e);
76 labels.push(Label {
77 pos,
78 message: (*id).to_string(),
79 });
80 labels
81 }
82 }
83 }
84 NoVariantMatch { pos } => {
85 let pos = (pos * 2) as usize;
86 vec![Label {
87 pos,
88 message: "No variant match".to_string(),
89 }]
90 }
91 AssertFail { pos, message } => {
92 let pos = (pos * 2) as usize;
93 vec![Label {
94 pos,
95 message: message.to_string(),
96 }]
97 }
98 Io(_) => vec![],
99 _ => unreachable!(),
100 }
101}
102
103impl ser::Error for Error {
104 fn custom<T: std::fmt::Display>(msg: T) -> Self {
105 Error::msg(format!("Serialize error: {msg}"))
106 }
107}
108
109impl de::Error for Error {
110 fn custom<T: std::fmt::Display>(msg: T) -> Self {
111 let msg = msg.to_string();
112 if let Some(msg) = msg.strip_prefix("Subtyping error: ") {
113 Error::Subtype(msg.to_string())
114 } else {
115 Error::msg(format!("Deserialize error: {msg}"))
116 }
117 }
118 fn invalid_type(_: de::Unexpected<'_>, exp: &dyn de::Expected) -> Self {
119 Error::Subtype(format!("{exp}"))
120 }
121}
122
123impl From<io::Error> for Error {
124 fn from(e: io::Error) -> Error {
125 Error::msg(format!("io error: {e}"))
126 }
127}
128
129impl From<binread::Error> for Error {
130 fn from(e: binread::Error) -> Error {
131 Error::Binread(get_binread_labels(&e))
132 }
133}
134
135impl From<ParseIntError> for Error {
136 fn from(e: ParseIntError) -> Error {
137 Error::msg(format!("ParseIntError: {e}"))
138 }
139}