mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -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:
parent
09b6dbc0a6
commit
1054723a4b
11 changed files with 152 additions and 45 deletions
|
@ -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()) {
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue