1use std::{string::FromUtf8Error, str::Utf8Error};
2
3use rain_metaboard_subgraph::metaboard_client::MetaboardSubgraphClientError;
4
5use crate::meta::KnownMagic;
6
7#[derive(Debug)]
9pub enum Error {
10 CorruptMeta,
11 NotRainMetaDocument,
12 InvalidHash,
13 UnknownMeta,
14 UnknownMagic,
15 NoRecordFound,
16 UnsupportedMeta,
17 BiggerThan32Bytes,
18 NulByteInInput,
19 InflateError(String),
20 InvalidInput(String),
21 InvalidUrl(String),
22 CorruptRecord(String),
23 SubgraphError(String),
24 Utf8Error(Utf8Error),
25 FromUtf8Error(FromUtf8Error),
26 ReqwestError(reqwest::Error),
27 SerdeCborError(serde_cbor::Error),
28 SerdeJsonError(serde_json::Error),
29 AbiCoderError(alloy::sol_types::Error),
30 ValidationErrors(validator::ValidationErrors),
31 DecodeHexStringError(alloy::primitives::hex::FromHexError),
32 InvalidMetaMagic(KnownMagic, KnownMagic),
33 MetaboardSubgraphClientError(MetaboardSubgraphClientError),
34}
35
36impl std::fmt::Display for Error {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 Error::CorruptMeta => f.write_str("corrupt meta"),
40 Error::NotRainMetaDocument => f.write_str(
41 "not a rain meta document: the bytes do not begin with the rain meta magic number",
42 ),
43 Error::UnknownMeta => f.write_str("unknown meta"),
44 Error::UnknownMagic => f.write_str("unknown magic"),
45 Error::UnsupportedMeta => f.write_str("unsupported meta"),
46 Error::InvalidHash => f.write_str("invalid keccak256 hash"),
47 Error::NoRecordFound => f.write_str("found no matching record"),
48 Error::BiggerThan32Bytes => {
49 f.write_str("unexpected input size, must be 32 bytes or less")
50 }
51 Error::NulByteInInput => f.write_str("unexpected nul byte in input"),
52 Error::InvalidInput(v) => write!(f, "invalid input: {}", v),
53 Error::InvalidUrl(v) => write!(f, "invalid URL: {}", v),
54 Error::CorruptRecord(v) => write!(f, "corrupt record: {}", v),
55 Error::SubgraphError(v) => write!(f, "subgraph error: {}", v),
56 Error::ReqwestError(v) => write!(f, "{}", v),
57 Error::InflateError(v) => write!(f, "{}", v),
58 Error::Utf8Error(v) => write!(f, "{}", v),
59 Error::AbiCoderError(v) => write!(f, "{}", v),
60 Error::SerdeCborError(v) => write!(f, "{}", v),
61 Error::SerdeJsonError(v) => write!(f, "{}", v),
62 Error::FromUtf8Error(v) => write!(f, "{}", v),
63 Error::DecodeHexStringError(v) => write!(f, "{}", v),
64 Error::ValidationErrors(v) => write!(f, "{}", v),
65 Error::InvalidMetaMagic(expected, actual) => {
66 write!(
67 f,
68 "invalid meta magic: expected {:?}, got {:?}",
69 expected, actual
70 )
71 }
72 Error::MetaboardSubgraphClientError(v) => write!(f, "{}", v),
73 }
74 }
75}
76
77impl std::error::Error for Error {}
78
79impl From<serde_json::Error> for Error {
80 fn from(value: serde_json::Error) -> Self {
81 Error::SerdeJsonError(value)
82 }
83}
84
85impl From<serde_cbor::Error> for Error {
86 fn from(value: serde_cbor::Error) -> Self {
87 Error::SerdeCborError(value)
88 }
89}
90
91impl From<FromUtf8Error> for Error {
92 fn from(value: FromUtf8Error) -> Self {
93 Error::FromUtf8Error(value)
94 }
95}
96
97impl From<Utf8Error> for Error {
98 fn from(value: Utf8Error) -> Self {
99 Error::Utf8Error(value)
100 }
101}
102
103impl From<validator::ValidationErrors> for Error {
104 fn from(value: validator::ValidationErrors) -> Self {
105 Error::ValidationErrors(value)
106 }
107}
108
109impl From<alloy::sol_types::Error> for Error {
110 fn from(value: alloy::sol_types::Error) -> Self {
111 Error::AbiCoderError(value)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
122 fn test_display_fixed_strings() {
123 assert_eq!(Error::CorruptMeta.to_string(), "corrupt meta");
124 assert_eq!(
125 Error::NotRainMetaDocument.to_string(),
126 "not a rain meta document: the bytes do not begin with the rain meta magic number"
127 );
128 assert_eq!(Error::UnknownMeta.to_string(), "unknown meta");
129 assert_eq!(Error::UnknownMagic.to_string(), "unknown magic");
130 assert_eq!(Error::UnsupportedMeta.to_string(), "unsupported meta");
131 assert_eq!(Error::InvalidHash.to_string(), "invalid keccak256 hash");
132 assert_eq!(Error::NoRecordFound.to_string(), "found no matching record");
133 assert_eq!(
134 Error::BiggerThan32Bytes.to_string(),
135 "unexpected input size, must be 32 bytes or less"
136 );
137 assert_eq!(
138 Error::NulByteInInput.to_string(),
139 "unexpected nul byte in input"
140 );
141 }
142
143 #[test]
145 fn test_display_formatted_wrappers() {
146 assert_eq!(
147 Error::InvalidInput("abc".to_string()).to_string(),
148 "invalid input: abc"
149 );
150 assert_eq!(
151 Error::InvalidUrl("not-a-url".to_string()).to_string(),
152 "invalid URL: not-a-url"
153 );
154 assert_eq!(Error::InflateError("boom".to_string()).to_string(), "boom");
155 assert_eq!(
156 Error::CorruptRecord("bytecode is missing".to_string()).to_string(),
157 "corrupt record: bytecode is missing"
158 );
159 assert_eq!(
160 Error::SubgraphError("boom".to_string()).to_string(),
161 "subgraph error: boom"
162 );
163 }
164
165 #[test]
167 fn test_display_invalid_meta_magic_field_order() {
168 let err = Error::InvalidMetaMagic(KnownMagic::RainMetaDocumentV1, KnownMagic::OpMetaV1);
169 assert_eq!(
170 err.to_string(),
171 "invalid meta magic: expected RainMetaDocumentV1, got OpMetaV1"
172 );
173 }
174
175 #[test]
178 fn test_from_serde_json_routes_to_serde_json_error() {
179 let src = serde_json::from_str::<serde_json::Value>("{oops").unwrap_err();
180 let msg = src.to_string();
181 let err: Error = src.into();
182 match err {
183 Error::SerdeJsonError(e) => assert_eq!(e.to_string(), msg),
184 other => panic!("wrong variant: {:?}", other),
185 }
186 }
187
188 #[test]
189 fn test_from_utf8_error_routes_to_utf8_error() {
190 #[allow(invalid_from_utf8)]
192 let src = std::str::from_utf8(&[0xff]).unwrap_err();
193 let err: Error = src.into();
194 match err {
195 Error::Utf8Error(e) => assert_eq!(e, src),
196 other => panic!("wrong variant: {:?}", other),
197 }
198 }
199
200 #[test]
201 fn test_from_from_utf8_error_routes_to_from_utf8_error() {
202 let src = String::from_utf8(vec![0xff]).unwrap_err();
203 let msg = src.to_string();
204 let err: Error = src.into();
205 match err {
206 Error::FromUtf8Error(e) => assert_eq!(e.to_string(), msg),
207 other => panic!("wrong variant: {:?}", other),
208 }
209 }
210}