1use core::fmt;
2
3use crate::WasmFeatures;
4use crate::prelude::*;
5
6#[derive(Debug, Clone)]
8pub struct Error {
9 pub(crate) inner: Box<ErrorInner>,
13}
14
15#[derive(Debug, Clone)]
16pub(crate) struct ErrorInner {
17 message: String,
18 kind: ErrorKind,
19 offset: u64,
20 needed_hint: Option<usize>,
21}
22
23#[derive(Debug, Clone, Copy)]
24pub(crate) enum ErrorKind {
25 Uncategorized,
26 InvalidHeapType,
27 WasmFeature(WasmFeatures),
28}
29
30pub type Result<T, E = Error> = core::result::Result<T, E>;
32
33impl core::error::Error for Error {}
34
35impl fmt::Display for Error {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 write!(
38 f,
39 "{} (at offset 0x{:x})",
40 self.inner.message, self.inner.offset
41 )
42 }
43}
44
45impl Error {
46 #[cold]
47 pub(crate) fn _new(kind: ErrorKind, message: String, offset: u64) -> Self {
48 Error {
49 inner: Box::new(ErrorInner {
50 kind,
51 message,
52 offset,
53 needed_hint: None,
54 }),
55 }
56 }
57
58 #[cold]
59 pub(crate) fn new(message: impl Into<String>, offset: u64) -> Self {
60 Self::_new(ErrorKind::Uncategorized, message.into(), offset)
61 }
62
63 #[cold]
64 pub(crate) fn invalid_heap_type(msg: &'static str, offset: u64) -> Self {
65 Self::_new(ErrorKind::InvalidHeapType, msg.into(), offset)
66 }
67
68 #[cold]
69 pub(crate) fn wasm_feature(
70 feature: crate::WasmFeatures,
71 msg: impl fmt::Display,
72 offset: u64,
73 ) -> Self {
74 Self::_new(ErrorKind::WasmFeature(feature), msg.to_string(), offset)
75 }
76
77 #[cold]
78 pub(crate) fn fmt(args: fmt::Arguments<'_>, offset: u64) -> Self {
79 Error::new(args.to_string(), offset)
80 }
81
82 #[cold]
83 pub(crate) fn eof(offset: u64, needed_hint: usize) -> Self {
84 let mut err = Error::new("unexpected end-of-file", offset);
85 err.inner.needed_hint = Some(needed_hint);
86 err
87 }
88
89 pub(crate) fn kind(&self) -> ErrorKind {
90 self.inner.kind
91 }
92
93 pub fn message(&self) -> &str {
95 &self.inner.message
96 }
97
98 pub fn offset(&self) -> u64 {
100 self.inner.offset
101 }
102
103 pub fn missing_wasm_feature(&self) -> Option<WasmFeatures> {
111 match self.inner.kind {
112 ErrorKind::WasmFeature(features) => Some(features),
113 _ => None,
114 }
115 }
116
117 #[cfg(all(feature = "validate", feature = "component-model"))]
118 pub(crate) fn add_context(&mut self, context: String) {
119 self.inner.message = format!("{context}\n{}", self.inner.message);
120 }
121
122 pub(crate) fn set_message(&mut self, message: impl Into<String>) {
123 self.inner.message = message.into();
124 }
125
126 pub(crate) fn needed_hint(&self) -> Option<usize> {
127 self.inner.needed_hint
128 }
129
130 pub(crate) fn without_needed_hint(mut self) -> Self {
131 self.inner.needed_hint = None;
132 self
133 }
134}