feat(webidl): derive wrapping signed long long conversion

Extracted from wpt-misc-fix.

Source-commit: 4fb35a340e
This commit is contained in:
ldm0
2026-10-12 01:03:50 +08:00
committed by Donough Liu
parent 60c0a7ffcb
commit 8ca9986eec
5 changed files with 92 additions and 2 deletions
+8
View File
@@ -14,6 +14,7 @@ pub(crate) enum ConverterKind {
CallbackFunction,
CallbackInterface,
Long,
LongLong,
EnforceRangeLong,
Short,
UnsignedShort,
@@ -49,6 +50,7 @@ impl ConverterKind {
"callback_function" => Ok(Self::CallbackFunction),
"callback_interface" => Ok(Self::CallbackInterface),
"long" => Ok(Self::Long),
"long_long" => Ok(Self::LongLong),
"enforce_range_long" => Ok(Self::EnforceRangeLong),
"short" => Ok(Self::Short),
"unsigned_short" => Ok(Self::UnsignedShort),
@@ -81,6 +83,7 @@ impl ConverterKind {
Self::CallbackFunction => quote!(::moli_webidl::WebIdlCallbackFunction),
Self::CallbackInterface => quote!(::moli_webidl::WebIdlCallbackInterface),
Self::Long => quote!(::moli_webidl::Long),
Self::LongLong => quote!(::moli_webidl::LongLong),
Self::EnforceRangeLong => quote!(::moli_webidl::EnforceRangeLong),
Self::Short => quote!(::moli_webidl::Short),
Self::UnsignedShort => quote!(::moli_webidl::UnsignedShort),
@@ -122,6 +125,7 @@ impl ConverterKind {
Self::BufferSource => quote!(::moli_webidl::BufferSource::from(#expr)),
Self::CallbackFunction | Self::CallbackInterface => quote!(#expr),
Self::Long => quote!(::moli_webidl::Long(#expr)),
Self::LongLong => quote!(::moli_webidl::LongLong(#expr)),
Self::EnforceRangeLong => quote!(::moli_webidl::EnforceRangeLong(#expr)),
Self::Short => quote!(::moli_webidl::Short(#expr)),
Self::UnsignedShort => quote!(::moli_webidl::UnsignedShort(#expr)),
@@ -158,6 +162,7 @@ impl ConverterKind {
Self::DomString
| Self::UsvString
| Self::Long
| Self::LongLong
| Self::EnforceRangeLong
| Self::Short
| Self::UnsignedShort
@@ -372,6 +377,9 @@ fn infer_converter_kind(ty: &Type) -> Option<ConverterKind> {
if is_type_ident(ty, "i16") {
return Some(ConverterKind::Short);
}
if is_type_ident(ty, "i64") {
return Some(ConverterKind::LongLong);
}
if is_type_ident(ty, "u64") {
return Some(ConverterKind::UnsignedLongLong);
}
+13
View File
@@ -331,6 +331,19 @@ impl<'s> WebIdlConverter<'s> for UnsignedLongLong {
}
}
impl<'s> WebIdlConverter<'s> for crate::LongLong {
type Options = ();
fn convert(
scope: &mut v8::PinScope<'s, '_>,
value: v8::Local<'s, v8::Value>,
context: Context,
_: &(),
) -> Result<Self, WebIdlError> {
number_value(scope, value, context, "long long")
.map(|value| Self(unsigned_long_long(value) as i64))
}
}
impl<'s> WebIdlConverter<'s> for EnforceRangeLongLong {
type Options = ();
+2 -2
View File
@@ -95,8 +95,8 @@ pub use traits::{ParseOutcome, WebIdlArguments, WebIdlConverter, WebIdlDictionar
pub use types::{
Boolean, BufferSource, ByteString, ClampedUnsignedShort, Dictionary, DomString, DomString16,
Double, EnforceRangeLong, EnforceRangeUnsignedLong, EnforceRangeUnsignedLongLong, EnumValue,
EventListenerOptions, InterfaceObject, InterfaceOptions, Long, Record, Sequence, Short,
StringOptions, UnrestrictedDouble, UnrestrictedFloat, UnsignedLong, UnsignedLongLong,
EventListenerOptions, InterfaceObject, InterfaceOptions, Long, LongLong, Record, Sequence,
Short, StringOptions, UnrestrictedDouble, UnrestrictedFloat, UnsignedLong, UnsignedLongLong,
UnsignedShort, UsvString,
};
+9
View File
@@ -298,6 +298,15 @@ impl From<ClampedUnsignedShort> for u16 {
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct LongLong(pub i64);
impl From<LongLong> for i64 {
fn from(value: LongLong) -> Self {
value.0
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct UnsignedLongLong(pub u64);
+60
View File
@@ -0,0 +1,60 @@
use moli_webidl::{Context, WebIdlDictionary};
#[derive(WebIdlDictionary)]
#[webidl(prefix = "LongLongInit")]
struct Init {
#[webidl(default = 0)]
value: i64,
#[webidl(converter = "long_long", default = 0)]
explicit: i64,
}
#[test]
fn long_long_derive_wraps_and_preserves_conversion_errors() {
moli_v8_test_util::ensure_v8();
let mut isolate = v8::Isolate::new(v8::CreateParams::default());
v8::scope!(let scope, &mut isolate);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
for (expression, expected) in [
("-17.9", -17),
("NaN", 0),
("Infinity", 0),
("undefined", 0),
("2**63", i64::MIN),
("2**64", 0),
("-(2**63)-2048", i64::MAX - 2047),
] {
let source = v8::String::new(
scope,
&format!("({{value:{expression},explicit:{expression}}})"),
)
.unwrap();
let value = v8::Script::compile(scope, source, None)
.unwrap()
.run(scope)
.unwrap();
let init =
moli_webidl::parse_dictionary::<Init>(scope, value, Context::argument("Test", 1))
.unwrap()
.unwrap();
assert_eq!(init.value, expected, "{expression}");
assert_eq!(init.explicit, expected, "{expression}");
}
for source in [
"({value:Symbol(),explicit:0})",
"({value:0,explicit:1n})",
"({get explicit(){throw 42},value:0})",
] {
v8::tc_scope!(let scope, scope);
let source = v8::String::new(scope, source).unwrap();
let value = v8::Script::compile(scope, source, None)
.unwrap()
.run(scope)
.unwrap();
assert!(
moli_webidl::parse_dictionary::<Init>(scope, value, Context::argument("Test", 1))
.is_err()
);
}
}