1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

feat(serde_v8): better error output (#18815)

The type that was received is now printed as part of a message.
This commit is contained in:
Bartek Iwańczuk 2023-04-27 02:12:39 +02:00 committed by GitHub
parent 09b6dbc0a6
commit 1054723a4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 152 additions and 45 deletions

View file

@ -4385,7 +4385,7 @@ Deno.core.opAsync("op_async_serialize_object_with_numbers_as_keys", {
let sum = Deno.core.ops.op_sum_take(w32.subarray(0, 2));
return false;
} catch(e) {
return e.message.includes('invalid type, expected: detachable');
return e.message.includes('invalid type; expected: detachable');
}
});
if (!assertWasmThrow()) {

View file

@ -4,6 +4,7 @@ use serde::de::Visitor;
use serde::de::{self};
use serde::Deserialize;
use crate::error::value_to_type_str;
use crate::error::Error;
use crate::error::Result;
use crate::keys::v8_struct_key;
@ -84,7 +85,7 @@ macro_rules! deserialize_signed {
} else if let Some(x) = self.input.to_big_int(self.scope) {
x.i64_value().0 as $t
} else {
return Err(Error::ExpectedInteger);
return Err(Error::ExpectedInteger(value_to_type_str(self.input)));
},
)
}
@ -107,7 +108,7 @@ macro_rules! deserialize_unsigned {
} else if let Some(x) = self.input.to_big_int(self.scope) {
x.u64_value().0 as $t
} else {
return Err(Error::ExpectedInteger);
return Err(Error::ExpectedInteger(value_to_type_str(self.input)));
},
)
}
@ -188,7 +189,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
} else if let Some(x) = self.input.to_big_int(self.scope) {
bigint_to_f64(x)
} else {
return Err(Error::ExpectedNumber);
return Err(Error::ExpectedNumber(value_to_type_str(self.input)));
},
)
}
@ -216,7 +217,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
let string = to_utf8(v8_string, self.scope);
visitor.visit_string(string)
} else {
Err(Error::ExpectedString)
Err(Error::ExpectedString(value_to_type_str(self.input)))
}
}
@ -268,7 +269,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
V: Visitor<'de>,
{
let arr = v8::Local::<v8::Array>::try_from(self.input)
.map_err(|_| Error::ExpectedArray)?;
.map_err(|_| Error::ExpectedArray(value_to_type_str(self.input)))?;
visitor.visit_seq(SeqAccess::new(arr.into(), self.scope, 0..arr.length()))
}
@ -308,7 +309,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
{
// Assume object, then get_own_property_names
let obj = v8::Local::<v8::Object>::try_from(self.input)
.map_err(|_| Error::ExpectedObject)?;
.map_err(|_| Error::ExpectedObject(value_to_type_str(self.input)))?;
if v8::Local::<v8::Map>::try_from(self.input).is_ok() {
let pairs_array = v8::Local::<v8::Map>::try_from(self.input)
@ -363,7 +364,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
_ => {
// Regular struct
let obj = v8::Local::<v8::Object>::try_from(self.input)
.or(Err(Error::ExpectedObject))?;
.map_err(|_| Error::ExpectedObject(value_to_type_str(self.input)))?;
// Fields names are a hint and must be inferred when not provided
if fields.is_empty() {
@ -409,7 +410,8 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
let tag = {
let prop_names =
obj.get_own_property_names(self.scope, Default::default());
let prop_names = prop_names.ok_or(Error::ExpectedEnum)?;
let prop_names = prop_names
.ok_or_else(|| Error::ExpectedEnum(value_to_type_str(self.input)))?;
let prop_names_len = prop_names.length();
if prop_names_len != 1 {
return Err(Error::LengthMismatch(prop_names_len as usize, 1));
@ -424,8 +426,7 @@ impl<'de, 'a, 'b, 's, 'x> de::Deserializer<'de>
payload,
})
} else {
// TODO: improve error
Err(Error::ExpectedEnum)
Err(Error::ExpectedEnum(value_to_type_str(self.input)))
}
}

View file

@ -9,30 +9,41 @@ pub enum Error {
#[error("{0}")]
Message(String),
#[error("serde_v8 error: invalid type, expected: boolean")]
ExpectedBoolean,
#[error("serde_v8 error: invalid type, expected: integer")]
ExpectedInteger,
#[error("serde_v8 error: invalid type, expected: number")]
ExpectedNumber,
#[error("serde_v8 error: invalid type, expected: string")]
ExpectedString,
#[error("serde_v8 error: invalid type, expected: array")]
ExpectedArray,
#[error("serde_v8 error: invalid type, expected: map")]
ExpectedMap,
#[error("serde_v8 error: invalid type, expected: enum")]
ExpectedEnum,
#[error("serde_v8 error: invalid type, expected: object")]
ExpectedObject,
#[error("serde_v8 error: invalid type, expected: buffer")]
ExpectedBuffer,
#[error("serde_v8 error: invalid type, expected: detachable")]
ExpectedDetachable,
#[error("serde_v8 error: invalid type, expected: external")]
ExpectedExternal,
#[error("serde_v8 error: invalid type, expected: bigint")]
ExpectedBigInt,
#[error("serde_v8 error: invalid type; expected: boolean, got: {0}")]
ExpectedBoolean(&'static str),
#[error("serde_v8 error: invalid type; expected: integer, got: {0}")]
ExpectedInteger(&'static str),
#[error("serde_v8 error: invalid type; expected: number, got: {0}")]
ExpectedNumber(&'static str),
#[error("serde_v8 error: invalid type; expected: string, got: {0}")]
ExpectedString(&'static str),
#[error("serde_v8 error: invalid type; expected: array, got: {0}")]
ExpectedArray(&'static str),
#[error("serde_v8 error: invalid type; expected: map, got: {0}")]
ExpectedMap(&'static str),
#[error("serde_v8 error: invalid type; expected: enum, got: {0}")]
ExpectedEnum(&'static str),
#[error("serde_v8 error: invalid type; expected: object, got: {0}")]
ExpectedObject(&'static str),
#[error("serde_v8 error: invalid type; expected: buffer, got: {0}")]
ExpectedBuffer(&'static str),
#[error("serde_v8 error: invalid type; expected: detachable, got: {0}")]
ExpectedDetachable(&'static str),
#[error("serde_v8 error: invalid type; expected: external, got: {0}")]
ExpectedExternal(&'static str),
#[error("serde_v8 error: invalid type; expected: bigint, got: {0}")]
ExpectedBigInt(&'static str),
#[error("serde_v8 error: invalid type, expected: utf8")]
ExpectedUtf8,
@ -57,3 +68,89 @@ impl serde::de::Error for Error {
Error::Message(msg.to_string())
}
}
pub(crate) fn value_to_type_str(value: v8::Local<v8::Value>) -> &'static str {
if value.is_module_namespace_object() {
"Module"
} else if value.is_wasm_module_object() {
"WASM module"
} else if value.is_wasm_memory_object() {
"WASM memory object"
} else if value.is_proxy() {
"Proxy"
} else if value.is_shared_array_buffer() {
"SharedArrayBuffer"
} else if value.is_data_view() {
"DataView"
} else if value.is_big_uint64_array() {
"BigUint64Array"
} else if value.is_big_int64_array() {
"BigInt64Array"
} else if value.is_float64_array() {
"Float64Array"
} else if value.is_float32_array() {
"Float32Array"
} else if value.is_int32_array() {
"Int32Array"
} else if value.is_uint32_array() {
"Uint32Array"
} else if value.is_int16_array() {
"Int16Array"
} else if value.is_uint16_array() {
"Uint16Array"
} else if value.is_int8_array() {
"Int8Array"
} else if value.is_uint8_clamped_array() {
"Uint8ClampedArray"
} else if value.is_uint8_array() {
"Uint8Array"
} else if value.is_typed_array() {
"TypedArray"
} else if value.is_array_buffer_view() {
"ArrayBufferView"
} else if value.is_array_buffer() {
"ArrayBuffer"
} else if value.is_weak_set() {
"WeakSet"
} else if value.is_weak_map() {
"WeakMap"
} else if value.is_set_iterator() {
"Set Iterator"
} else if value.is_map_iterator() {
"Map Iterator"
} else if value.is_set() {
"Set"
} else if value.is_map() {
"Map"
} else if value.is_promise() {
"Promise"
} else if value.is_generator_function() {
"Generator function"
} else if value.is_async_function() {
"Async function"
} else if value.is_reg_exp() {
"RegExp"
} else if value.is_date() {
"Date"
} else if value.is_number() {
"Number"
} else if value.is_boolean() {
"Boolean"
} else if value.is_big_int() {
"bigint"
} else if value.is_array() {
"array"
} else if value.is_function() {
"function"
} else if value.is_symbol() {
"symbol"
} else if value.is_string() {
"string"
} else if value.is_null() {
"null"
} else if value.is_undefined() {
"undefined"
} else {
"unknown"
}
}

View file

@ -5,6 +5,7 @@ use smallvec::SmallVec;
use super::transl8::FromV8;
use super::transl8::ToV8;
use crate::error::value_to_type_str;
use crate::magic::transl8::impl_magic;
use crate::Error;
@ -42,7 +43,7 @@ impl FromV8 for BigInt {
value: v8::Local<v8::Value>,
) -> Result<Self, crate::Error> {
let v8bigint = v8::Local::<v8::BigInt>::try_from(value)
.map_err(|_| Error::ExpectedBigInt)?;
.map_err(|_| Error::ExpectedBigInt(value_to_type_str(value)))?;
let word_count = v8bigint.word_count();
let mut words: SmallVec<[u64; 1]> = smallvec![0u64; word_count];
let (sign_bit, _words) = v8bigint.to_words_array(&mut words);

View file

@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use super::transl8::FromV8;
use super::transl8::ToV8;
use crate::error::value_to_type_str;
use crate::magic::transl8::impl_magic;
use crate::Error;
use smallvec::SmallVec;
@ -49,7 +50,7 @@ impl FromV8 for ByteString {
value: v8::Local<v8::Value>,
) -> Result<Self, crate::Error> {
let v8str = v8::Local::<v8::String>::try_from(value)
.map_err(|_| Error::ExpectedString)?;
.map_err(|_| Error::ExpectedString(value_to_type_str(value)))?;
if !v8str.contains_only_onebyte() {
return Err(Error::ExpectedLatin1);
}

View file

@ -8,6 +8,7 @@ use super::transl8::FromV8;
use super::transl8::ToV8;
use super::v8slice::to_ranged_buffer;
use super::v8slice::V8Slice;
use crate::error::value_to_type_str;
use crate::magic::transl8::impl_magic;
// A buffer that detaches when deserialized from JS
@ -57,10 +58,10 @@ impl FromV8 for DetachedBuffer {
scope: &mut v8::HandleScope,
value: v8::Local<v8::Value>,
) -> Result<Self, crate::Error> {
let (b, range) =
to_ranged_buffer(scope, value).or(Err(crate::Error::ExpectedBuffer))?;
let (b, range) = to_ranged_buffer(scope, value)
.map_err(|_| crate::Error::ExpectedBuffer(value_to_type_str(value)))?;
if !b.is_detachable() {
return Err(crate::Error::ExpectedDetachable);
return Err(crate::Error::ExpectedDetachable(value_to_type_str(value)));
}
let store = b.get_backing_store();
b.detach(None); // Detach

View file

@ -2,6 +2,8 @@
use std::ffi::c_void;
use crate::error::value_to_type_str;
use super::transl8::impl_magic;
use super::transl8::FromV8;
use super::transl8::ToV8;
@ -38,7 +40,7 @@ impl FromV8 for ExternalPointer {
} else if let Ok(external) = v8::Local::<v8::External>::try_from(value) {
Ok(ExternalPointer(external.value()))
} else {
Err(crate::Error::ExpectedExternal)
Err(crate::Error::ExpectedExternal(value_to_type_str(value)))
}
}
}

View file

@ -2,6 +2,7 @@
use super::buffer::ZeroCopyBuf;
use super::transl8::FromV8;
use super::transl8::ToV8;
use crate::error::value_to_type_str;
use crate::magic::transl8::impl_magic;
use crate::Error;
use std::ops::Deref;
@ -73,7 +74,7 @@ impl FromV8 for StringOrBuffer {
} else if let Ok(s) = crate::from_v8(scope, value) {
return Ok(Self::String(s));
}
Err(Error::ExpectedBuffer)
Err(Error::ExpectedBuffer(value_to_type_str(value)))
}
}

View file

@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use crate::error::value_to_type_str;
use crate::Error;
use super::transl8::impl_magic;
@ -37,7 +38,7 @@ impl FromV8 for U16String {
value: v8::Local<v8::Value>,
) -> Result<Self, crate::Error> {
let v8str = v8::Local::<v8::String>::try_from(value)
.map_err(|_| Error::ExpectedString)?;
.map_err(|_| Error::ExpectedString(value_to_type_str(value)))?;
let len = v8str.length();
let mut buffer = Vec::with_capacity(len);
#[allow(clippy::uninit_vec)]

View file

@ -5,6 +5,8 @@ use std::ops::DerefMut;
use std::ops::Range;
use std::rc::Rc;
use crate::error::value_to_type_str;
use super::rawbytes;
use super::transl8::FromV8;
@ -91,7 +93,7 @@ impl FromV8 for V8Slice {
) -> Result<Self, crate::Error> {
to_ranged_buffer(scope, value)
.and_then(|(b, r)| Self::from_buffer(b, r))
.map_err(|_| crate::Error::ExpectedBuffer)
.map_err(|_| crate::Error::ExpectedBuffer(value_to_type_str(value)))
}
}

View file

@ -408,7 +408,7 @@ detest!(
);
defail!(defail_struct, MathOp, "123", |e| e
== Err(Error::ExpectedObject));
== Err(Error::ExpectedObject("Number")));
#[derive(Eq, PartialEq, Debug, Deserialize)]
pub struct SomeThing {