Skip to content

Commit 86e919b

Browse files
committed
Refactor error handling and remove anyhow
1 parent 02a1820 commit 86e919b

File tree

7 files changed

+118
-92
lines changed

7 files changed

+118
-92
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7-
anyhow = "1"
87
rquickjs = "0.9"
98
serde = "1"
109

src/de.rs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
use anyhow::{anyhow, bail};
21
use rquickjs::{
3-
Array, Exception, Filter, Object, String as JSString, Value,
2+
Array, Exception, Filter, Function, Null, Object, String as JSString, Value,
3+
atom::PredefinedAtom,
44
function::This,
55
object::ObjectIter,
66
qjs::{JS_GetClassID, JS_GetProperty},
77
};
8-
use rquickjs::{Function, Null, atom::PredefinedAtom};
9-
use serde::de::{self, Error as SerError};
10-
use serde::forward_to_deserialize_any;
8+
use serde::{de, forward_to_deserialize_any};
119

1210
use crate::err::{Error, Result};
1311
use crate::utils::{as_key, to_string_lossy};
@@ -23,12 +21,6 @@ enum ClassId {
2321
BigInt = 33,
2422
}
2523

26-
impl SerError for Error {
27-
fn custom<T: std::fmt::Display>(e: T) -> Self {
28-
Error::Custom(anyhow!(e.to_string()))
29-
}
30-
}
31-
3224
/// `Deserializer` is a deserializer for [Value] values, implementing the `serde::Deserializer` trait.
3325
///
3426
/// This struct is responsible for converting [Value], into Rust types using the Serde deserialization framework.
@@ -72,15 +64,15 @@ impl<'js> Deserializer<'js> {
7264
return visitor.visit_i32(
7365
self.value
7466
.as_int()
75-
.ok_or_else(|| anyhow!("Failed to convert value to i32"))?,
67+
.ok_or_else(|| Error::new("Failed to convert value to i32"))?,
7668
);
7769
}
7870

7971
if self.value.is_float() {
8072
let f64_representation = self
8173
.value
8274
.as_float()
83-
.ok_or_else(|| anyhow!("Failed to convert value to f64"))?;
75+
.ok_or_else(|| Error::new("Failed to convert value to f64"))?;
8476
let is_positive = f64_representation.is_sign_positive();
8577
let safe_integer_range = (MIN_SAFE_INTEGER as f64)..=(MAX_SAFE_INTEGER as f64);
8678
let whole = f64_representation.fract() == 0.0;
@@ -104,7 +96,7 @@ impl<'js> Deserializer<'js> {
10496
let v = self
10597
.stack
10698
.pop()
107-
.ok_or_else(|| anyhow!("No entries found in the deserializer stack"))?;
99+
.ok_or_else(|| Error::new("No entries found in the deserializer stack"))?;
108100
Ok(v)
109101
}
110102

@@ -114,7 +106,7 @@ impl<'js> Deserializer<'js> {
114106
fn check_cycles(&self) -> Result<()> {
115107
for val in self.stack.iter().rev() {
116108
if self.value.eq(val) {
117-
return Err(Error::from(Exception::throw_type(
109+
return Err(Error::new(Exception::throw_type(
118110
val.ctx(),
119111
"circular dependency",
120112
)));
@@ -138,7 +130,7 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
138130
if get_class_id(&self.value) == ClassId::Number as u32 {
139131
let value_of = get_valueof(&self.value);
140132
if let Some(f) = value_of {
141-
let v = f.call((This(self.value.clone()),))?;
133+
let v = f.call((This(self.value.clone()),)).map_err(Error::new)?;
142134
self.value = v;
143135
return self.deserialize_number(visitor);
144136
}
@@ -151,7 +143,7 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
151143
if get_class_id(&self.value) == ClassId::Bool as u32 {
152144
let value_of = get_valueof(&self.value);
153145
if let Some(f) = value_of {
154-
let v = f.call((This(self.value.clone()),))?;
146+
let v = f.call((This(self.value.clone()),)).map_err(Error::new)?;
155147
return visitor.visit_bool(v);
156148
}
157149
}
@@ -163,7 +155,7 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
163155
if get_class_id(&self.value) == ClassId::String as u32 {
164156
let value_of = get_to_string(&self.value);
165157
if let Some(f) = value_of {
166-
let v = f.call(((This(self.value.clone())),))?;
158+
let v = f.call(((This(self.value.clone())),)).map_err(Error::new)?;
167159
self.value = v;
168160
}
169161
}
@@ -198,7 +190,7 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
198190
ensure_supported(&self.value)?;
199191

200192
if let Some(f) = get_to_json(&self.value) {
201-
let v: Value = f.call((This(self.value.clone()),))?;
193+
let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
202194

203195
if v.is_undefined() {
204196
self.value = Value::new_undefined(v.ctx().clone());
@@ -218,13 +210,13 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
218210
|| self.value.type_of() == rquickjs::Type::BigInt
219211
{
220212
if let Some(f) = get_to_json(&self.value) {
221-
let v: Value = f.call((This(self.value.clone()),))?;
213+
let v: Value = f.call((This(self.value.clone()),)).map_err(Error::new)?;
222214
self.value = v;
223215
return self.deserialize_any(visitor);
224216
}
225217
}
226218

227-
Err(Error::from(Exception::throw_type(
219+
Err(Error::new(Exception::throw_type(
228220
self.value.ctx(),
229221
"Unsupported type",
230222
)))
@@ -299,10 +291,12 @@ impl<'a, 'de> MapAccess<'a, 'de> {
299291

300292
/// Pops the top level value representing this sequence.
301293
/// Errors if a different value is popped.
302-
fn pop(&mut self) -> anyhow::Result<()> {
294+
fn pop(&mut self) -> Result<()> {
303295
let v = self.de.pop_visited()?;
304296
if v != self.obj.clone().into_value() {
305-
bail!("Popped a mismatched value. Expected the top level sequence value");
297+
return Err(Error::new(
298+
"Popped a mismatched value. Expected the top level sequence value",
299+
));
306300
}
307301

308302
Ok(())
@@ -318,11 +312,11 @@ impl<'de> de::MapAccess<'de> for MapAccess<'_, 'de> {
318312
{
319313
loop {
320314
if let Some(kv) = self.properties.next() {
321-
let (k, v) = kv?;
315+
let (k, v) = kv.map_err(Error::new)?;
322316

323317
let to_json = get_to_json(&v);
324318
let v = if let Some(f) = to_json {
325-
f.call((This(v.clone()), k.clone()))?
319+
f.call((This(v.clone()), k.clone())).map_err(Error::new)?
326320
} else {
327321
v
328322
};
@@ -338,13 +332,13 @@ impl<'de> de::MapAccess<'de> for MapAccess<'_, 'de> {
338332
if class_id == ClassId::Bool as u32 || class_id == ClassId::Number as u32 {
339333
let value_of = get_valueof(&v);
340334
if let Some(f) = value_of {
341-
let v = f.call((This(v.clone()),))?;
335+
let v = f.call((This(v.clone()),)).map_err(Error::new)?;
342336
self.de.current_kv = Some((k.clone(), v));
343337
}
344338
} else if class_id == ClassId::String as u32 {
345339
let to_string = get_to_string(&v);
346340
if let Some(f) = to_string {
347-
let v = f.call((This(v.clone()),))?;
341+
let v = f.call((This(v.clone()),)).map_err(Error::new)?;
348342
self.de.current_kv = Some((k.clone(), v));
349343
}
350344
} else {
@@ -393,15 +387,19 @@ impl<'a, 'de: 'a> SeqAccess<'a, 'de> {
393387
// using the bindings `Array::len` given that according to the spec
394388
// it's fine to return any value, not just a number from the
395389
// `length` property.
396-
let value: Value = seq.as_object().get(PredefinedAtom::Length)?;
390+
let value: Value = seq
391+
.as_object()
392+
.get(PredefinedAtom::Length)
393+
.map_err(Error::new)?;
397394
let length: usize = if value.is_number() {
398395
value.as_number().unwrap() as usize
399396
} else {
400397
let value_of: Function = value
401398
.as_object()
402399
.expect("length to be an object")
403-
.get(PredefinedAtom::ValueOf)?;
404-
value_of.call(())?
400+
.get(PredefinedAtom::ValueOf)
401+
.map_err(Error::new)?;
402+
value_of.call(()).map_err(Error::new)?
405403
};
406404

407405
Ok(Self {
@@ -414,10 +412,12 @@ impl<'a, 'de: 'a> SeqAccess<'a, 'de> {
414412

415413
/// Pops the top level value representing this sequence.
416414
/// Errors if a different value is popped.
417-
fn pop(&mut self) -> anyhow::Result<()> {
415+
fn pop(&mut self) -> Result<()> {
418416
let v = self.de.pop_visited()?;
419417
if v != self.seq.clone().into_value() {
420-
bail!("Popped a mismatched value. Expected the top level sequence value");
418+
return Err(Error::new(
419+
"Popped a mismatched value. Expected the top level sequence value",
420+
));
421421
}
422422

423423
Ok(())
@@ -432,12 +432,14 @@ impl<'de> de::SeqAccess<'de> for SeqAccess<'_, 'de> {
432432
T: de::DeserializeSeed<'de>,
433433
{
434434
if self.index < self.length {
435-
let el = self.seq.get(self.index)?;
435+
let el = self.seq.get(self.index).map_err(Error::new)?;
436436
let to_json = get_to_json(&el);
437437

438438
if let Some(f) = to_json {
439439
let index_value = JSString::from_str(el.ctx().clone(), &self.index.to_string());
440-
self.de.value = f.call((This(el.clone()), index_value))?;
440+
self.de.value = f
441+
.call((This(el.clone()), index_value))
442+
.map_err(Error::new)?;
441443
} else if ensure_supported(&el)? {
442444
self.de.value = el
443445
} else {
@@ -507,7 +509,7 @@ fn ensure_supported(value: &Value<'_>) -> Result<bool> {
507509
}
508510

509511
if class_id == ClassId::BigInt as u32 {
510-
return Err(Error::from(Exception::throw_type(
512+
return Err(Error::new(Exception::throw_type(
511513
value.ctx(),
512514
"BigInt not supported",
513515
)));

src/err.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,76 @@
11
use std::{error, fmt};
22

33
use rquickjs::Error as JSError;
4+
use serde::{de, ser};
45

6+
/// This type represents all possible errors that can occur when serializing or
7+
/// deserializing JS values.
8+
pub struct Error(Box<ErrorImpl>);
9+
10+
impl Error {
11+
pub(crate) fn new(msg: impl Into<ErrorImpl>) -> Self {
12+
Error(Box::new(msg.into()))
13+
}
14+
}
15+
16+
/// Alias for a `Result` with the error type `rquickjs_serde::Error`.
517
pub type Result<T> = std::result::Result<T, Error>;
618

7-
#[derive(Debug)]
8-
pub enum Error {
9-
Custom(anyhow::Error),
19+
impl fmt::Debug for Error {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
write!(f, "Error({})", self.0)
22+
}
1023
}
1124

1225
impl error::Error for Error {}
1326

1427
impl fmt::Display for Error {
15-
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
28+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29+
fmt::Display::fmt(&*self.0, f)
30+
}
31+
}
32+
33+
impl de::Error for Error {
34+
fn custom<T: fmt::Display>(msg: T) -> Self {
35+
Error(Box::new(ErrorImpl::Message(msg.to_string())))
36+
}
37+
}
38+
39+
impl ser::Error for Error {
40+
fn custom<T: fmt::Display>(msg: T) -> Self {
41+
Error(Box::new(ErrorImpl::Message(msg.to_string())))
42+
}
43+
}
44+
45+
/// The internal representation of an error.
46+
///
47+
/// This enum represents various errors that can occur during JS value serialization or deserialization,
48+
/// including UTF-8 conversion errors, and errors originating from the `rquickjs` library.
49+
#[derive(Debug)]
50+
pub enum ErrorImpl {
51+
/// A generic error message
52+
Message(String),
53+
/// An error originating from the `rquickjs` library.
54+
Rquickjs(JSError),
55+
}
56+
57+
impl fmt::Display for ErrorImpl {
58+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1659
match self {
17-
Error::Custom(e) => {
18-
if let Some(e) = e.downcast_ref::<JSError>() {
19-
formatter.write_str(&format!("JSError: {}", &e.to_string()))
20-
} else {
21-
formatter.write_str(&e.to_string())
22-
}
23-
}
60+
ErrorImpl::Message(msg) => write!(f, "{}", msg),
61+
ErrorImpl::Rquickjs(e) => write!(f, "{}", e),
2462
}
2563
}
2664
}
2765

28-
impl From<anyhow::Error> for Error {
29-
fn from(e: anyhow::Error) -> Self {
30-
Error::Custom(e)
66+
impl From<&str> for ErrorImpl {
67+
fn from(value: &str) -> Self {
68+
ErrorImpl::Message(value.to_string())
3169
}
3270
}
3371

34-
impl From<JSError> for Error {
72+
impl From<JSError> for ErrorImpl {
3573
fn from(value: JSError) -> Self {
36-
Error::Custom(anyhow::Error::new(value))
74+
ErrorImpl::Rquickjs(value)
3775
}
3876
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,12 @@ where
131131
mod tests {
132132
use std::collections::BTreeMap;
133133

134-
use anyhow::Result;
135134
use quickcheck::quickcheck;
136135
use serde::de::DeserializeOwned;
137136
use serde::{Deserialize, Serialize};
138137

139138
use crate::de::Deserializer as ValueDeserializer;
139+
use crate::err::Result;
140140
use crate::ser::Serializer as ValueSerializer;
141141
use crate::test::Runtime;
142142
use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};

0 commit comments

Comments
 (0)