From eb2f33e74a054f73c051016ec141f9e9258ef90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Juli=C3=A1n=20Espina?= Date: Fri, 1 Dec 2023 09:44:55 -0600 Subject: [PATCH] Transition `Intl` types to `NativeObject` API (#3491) --- Cargo.lock | 1 + boa_engine/Cargo.toml | 2 +- boa_engine/src/builtins/intl/collator/mod.rs | 10 +- .../src/builtins/intl/date_time_format.rs | 6 +- .../src/builtins/intl/list_format/mod.rs | 18 +- boa_engine/src/builtins/intl/locale/mod.rs | 34 +-- boa_engine/src/builtins/intl/locale/utils.rs | 4 +- .../src/builtins/intl/plural_rules/mod.rs | 18 +- .../src/builtins/intl/segmenter/iterator.rs | 10 +- boa_engine/src/builtins/intl/segmenter/mod.rs | 16 +- .../src/builtins/intl/segmenter/segments.rs | 15 +- boa_engine/src/builtins/string/mod.rs | 2 +- boa_engine/src/object/mod.rs | 273 +----------------- boa_gc/Cargo.toml | 9 +- boa_gc/src/trace.rs | 21 ++ 15 files changed, 117 insertions(+), 322 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aac2f11d7f..5aecd5cf76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -517,6 +517,7 @@ dependencies = [ "boa_macros", "boa_profiler", "hashbrown 0.14.3", + "icu_locid", "thin-vec", ] diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index 288238c909..b8321f9881 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -57,7 +57,7 @@ js = ["dep:web-time"] [dependencies] boa_interner.workspace = true -boa_gc = { workspace = true, features = [ "thinvec" ] } +boa_gc = { workspace = true, features = [ "thin-vec", "icu" ] } boa_profiler.workspace = true boa_macros.workspace = true boa_ast.workspace = true diff --git a/boa_engine/src/builtins/intl/collator/mod.rs b/boa_engine/src/builtins/intl/collator/mod.rs index 77d55e9a6a..92bc74b830 100644 --- a/boa_engine/src/builtins/intl/collator/mod.rs +++ b/boa_engine/src/builtins/intl/collator/mod.rs @@ -42,7 +42,7 @@ mod options; pub(crate) use options::*; #[derive(Debug)] -pub struct Collator { +pub(crate) struct Collator { locale: Locale, collation: Value, numeric: bool, @@ -350,7 +350,7 @@ impl BuiltInConstructor for Collator { let collator = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::collator(Self { + ObjectData::native_object(Self { locale, collation, numeric, @@ -414,7 +414,7 @@ impl Collator { })?; let collator_obj = this.clone(); let mut collator = this.borrow_mut(); - let collator = collator.as_collator_mut().ok_or_else(|| { + let collator = collator.downcast_mut::().ok_or_else(|| { JsNativeError::typ() .with_message("`resolvedOptions` can only be called on a `Collator` object") })?; @@ -436,7 +436,7 @@ impl Collator { // 2. Assert: Type(collator) is Object and collator has an [[InitializedCollator]] internal slot. let collator = collator.borrow(); let collator = collator - .as_collator() + .downcast_ref::() .expect("checked above that the object was a collator object"); // 3. If x is not provided, let x be undefined. @@ -483,7 +483,7 @@ impl Collator { JsNativeError::typ() .with_message("`resolvedOptions` can only be called on a `Collator` object") })?; - let collator = collator.as_collator().ok_or_else(|| { + let collator = collator.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`resolvedOptions` can only be called on a `Collator` object") })?; diff --git a/boa_engine/src/builtins/intl/date_time_format.rs b/boa_engine/src/builtins/intl/date_time_format.rs index 2ae6c8b0a8..ed6a866fa7 100644 --- a/boa_engine/src/builtins/intl/date_time_format.rs +++ b/boa_engine/src/builtins/intl/date_time_format.rs @@ -40,7 +40,7 @@ impl OptionType for HourCycle { /// JavaScript `Intl.DateTimeFormat` object. #[derive(Debug, Clone, Trace, Finalize)] -pub struct DateTimeFormat { +pub(crate) struct DateTimeFormat { initialized_date_time_format: bool, locale: JsString, calendar: JsString, @@ -123,7 +123,7 @@ impl BuiltInConstructor for DateTimeFormat { let date_time_format = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::date_time_format(Box::new(Self { + ObjectData::native_object(Self { initialized_date_time_format: true, locale: js_string!("en-US"), calendar: js_string!("gregory"), @@ -143,7 +143,7 @@ impl BuiltInConstructor for DateTimeFormat { hour_cycle: js_string!("h24"), pattern: js_string!("{hour}:{minute}"), bound_format: js_string!("undefined"), - })), + }), ); // TODO 3. Perform ? InitializeDateTimeFormat(dateTimeFormat, locales, options). diff --git a/boa_engine/src/builtins/intl/list_format/mod.rs b/boa_engine/src/builtins/intl/list_format/mod.rs index e3cfe0cd7b..82c040a319 100644 --- a/boa_engine/src/builtins/intl/list_format/mod.rs +++ b/boa_engine/src/builtins/intl/list_format/mod.rs @@ -1,5 +1,6 @@ use std::fmt::Write; +use boa_gc::{empty_trace, Finalize, Trace}; use boa_profiler::Profiler; use icu_list::{provider::AndListV1Marker, ListFormatter, ListLength}; use icu_locid::Locale; @@ -29,14 +30,19 @@ use super::{ mod options; pub(crate) use options::*; -#[derive(Debug)] -pub struct ListFormat { +#[derive(Debug, Finalize)] +pub(crate) struct ListFormat { locale: Locale, typ: ListFormatType, style: ListLength, native: ListFormatter, } +// SAFETY: `ListFormat` doesn't contain traceable data. +unsafe impl Trace for ListFormat { + empty_trace!(); +} + impl Service for ListFormat { type LangMarker = AndListV1Marker; @@ -164,7 +170,7 @@ impl BuiltInConstructor for ListFormat { let list_format = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::list_format(Self { + ObjectData::native_object(Self { locale, typ, style, @@ -221,7 +227,7 @@ impl ListFormat { JsNativeError::typ() .with_message("`format` can only be called on a `ListFormat` object") })?; - let lf = lf.as_list_format().ok_or_else(|| { + let lf = lf.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`format` can only be called on a `ListFormat` object") })?; @@ -339,7 +345,7 @@ impl ListFormat { JsNativeError::typ() .with_message("`formatToParts` can only be called on a `ListFormat` object") })?; - let lf = lf.as_list_format().ok_or_else(|| { + let lf = lf.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`formatToParts` can only be called on a `ListFormat` object") })?; @@ -413,7 +419,7 @@ impl ListFormat { JsNativeError::typ() .with_message("`resolvedOptions` can only be called on a `ListFormat` object") })?; - let lf = lf.as_list_format().ok_or_else(|| { + let lf = lf.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`resolvedOptions` can only be called on a `ListFormat` object") })?; diff --git a/boa_engine/src/builtins/intl/locale/mod.rs b/boa_engine/src/builtins/intl/locale/mod.rs index 81cece4ad1..c6adeb8201 100644 --- a/boa_engine/src/builtins/intl/locale/mod.rs +++ b/boa_engine/src/builtins/intl/locale/mod.rs @@ -206,7 +206,7 @@ impl BuiltInConstructor for Locale { let mut tag = if let Some(tag) = tag .as_object() - .and_then(|obj| obj.borrow().as_locale().cloned()) + .and_then(|obj| obj.borrow().downcast_ref::().cloned()) { // a. Let tag be tag.[[Locale]]. tag @@ -371,7 +371,7 @@ impl BuiltInConstructor for Locale { let locale = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::locale(tag), + ObjectData::native_object(tag), ); // 37. Return locale. @@ -398,7 +398,7 @@ impl Locale { JsNativeError::typ().with_message("`maximize` can only be called on a `Locale` object") })?; let mut loc = loc - .as_locale() + .downcast_ref::() .ok_or_else(|| { JsNativeError::typ() .with_message("`maximize` can only be called on a `Locale` object") @@ -413,7 +413,7 @@ impl Locale { Ok(JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::locale(loc), + ObjectData::native_object(loc), ) .into()) } @@ -436,7 +436,7 @@ impl Locale { JsNativeError::typ().with_message("`minimize` can only be called on a `Locale` object") })?; let mut loc = loc - .as_locale() + .downcast_ref::() .ok_or_else(|| { JsNativeError::typ() .with_message("`minimize` can only be called on a `Locale` object") @@ -451,7 +451,7 @@ impl Locale { Ok(JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), prototype, - ObjectData::locale(loc), + ObjectData::native_object(loc), ) .into()) } @@ -469,7 +469,7 @@ impl Locale { let loc = this.as_object().map(JsObject::borrow).ok_or_else(|| { JsNativeError::typ().with_message("`toString` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ().with_message("`toString` can only be called on a `Locale` object") })?; @@ -491,7 +491,7 @@ impl Locale { JsNativeError::typ() .with_message("`get baseName` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get baseName` can only be called on a `Locale` object") })?; @@ -515,7 +515,7 @@ impl Locale { JsNativeError::typ() .with_message("`get calendar` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get calendar` can only be called on a `Locale` object") })?; @@ -544,7 +544,7 @@ impl Locale { JsNativeError::typ() .with_message("`get caseFirst` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get caseFirst` can only be called on a `Locale` object") })?; @@ -573,7 +573,7 @@ impl Locale { JsNativeError::typ() .with_message("`get collation` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get collation` can only be called on a `Locale` object") })?; @@ -602,7 +602,7 @@ impl Locale { JsNativeError::typ() .with_message("`get hourCycle` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get hourCycle` can only be called on a `Locale` object") })?; @@ -631,7 +631,7 @@ impl Locale { JsNativeError::typ() .with_message("`get numeric` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get numeric` can only be called on a `Locale` object") })?; @@ -668,7 +668,7 @@ impl Locale { JsNativeError::typ() .with_message("`get numberingSystem` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get numberingSystem` can only be called on a `Locale` object") })?; @@ -697,7 +697,7 @@ impl Locale { JsNativeError::typ() .with_message("`get language` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get language` can only be called on a `Locale` object") })?; @@ -722,7 +722,7 @@ impl Locale { JsNativeError::typ() .with_message("`get script` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get script` can only be called on a `Locale` object") })?; @@ -752,7 +752,7 @@ impl Locale { JsNativeError::typ() .with_message("`get region` can only be called on a `Locale` object") })?; - let loc = loc.as_locale().ok_or_else(|| { + let loc = loc.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`get region` can only be called on a `Locale` object") })?; diff --git a/boa_engine/src/builtins/intl/locale/utils.rs b/boa_engine/src/builtins/intl/locale/utils.rs index 1f76a9eb16..16194b07f8 100644 --- a/boa_engine/src/builtins/intl/locale/utils.rs +++ b/boa_engine/src/builtins/intl/locale/utils.rs @@ -80,7 +80,7 @@ pub(crate) fn canonicalize_locale_list( let o = if locales.is_string() || locales .as_object() - .map_or(false, |o| o.borrow().is_locale()) + .map_or(false, |o| o.borrow().is::()) { // a. Let O be CreateArrayFromList(« locales »). Array::create_array_from_list([locales.clone()], context) @@ -113,7 +113,7 @@ pub(crate) fn canonicalize_locale_list( // iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then let mut tag = if let Some(tag) = k_value .as_object() - .and_then(|obj| obj.borrow().as_locale().cloned()) + .and_then(|obj| obj.borrow().downcast_ref::().cloned()) { // 1. Let tag be kValue.[[Locale]]. tag diff --git a/boa_engine/src/builtins/intl/plural_rules/mod.rs b/boa_engine/src/builtins/intl/plural_rules/mod.rs index 4750d6245f..b79ca9a106 100644 --- a/boa_engine/src/builtins/intl/plural_rules/mod.rs +++ b/boa_engine/src/builtins/intl/plural_rules/mod.rs @@ -1,5 +1,6 @@ mod options; +use boa_gc::{empty_trace, Finalize, Trace}; use boa_macros::utf16; use boa_profiler::Profiler; use fixed_decimal::FixedDecimal; @@ -34,14 +35,19 @@ use super::{ Service, }; -#[derive(Debug)] -pub struct PluralRules { +#[derive(Debug, Finalize)] +pub(crate) struct PluralRules { locale: Locale, native: PluralRulesWithRanges, rule_type: PluralRuleType, format_options: DigitFormatOptions, } +// SAFETY: `PluralRules` doesn't contain any traceable data. +unsafe impl Trace for PluralRules { + empty_trace!(); +} + impl Service for PluralRules { type LangMarker = CardinalV1Marker; @@ -164,7 +170,7 @@ impl BuiltInConstructor for PluralRules { Ok(JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), proto, - ObjectData::plural_rules(Self { + ObjectData::native_object(Self { locale, native, rule_type, @@ -192,7 +198,7 @@ impl PluralRules { JsNativeError::typ() .with_message("`select` can only be called on an `Intl.PluralRules` object") })?; - let plural_rules = plural_rules.as_plural_rules().ok_or_else(|| { + let plural_rules = plural_rules.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`select` can only be called on an `Intl.PluralRules` object") })?; @@ -219,7 +225,7 @@ impl PluralRules { JsNativeError::typ() .with_message("`select_range` can only be called on an `Intl.PluralRules` object") })?; - let plural_rules = plural_rules.as_plural_rules().ok_or_else(|| { + let plural_rules = plural_rules.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`select_range` can only be called on an `Intl.PluralRules` object") })?; @@ -314,7 +320,7 @@ impl PluralRules { "`resolved_options` can only be called on an `Intl.PluralRules` object", ) })?; - let plural_rules = plural_rules.as_plural_rules().ok_or_else(|| { + let plural_rules = plural_rules.downcast_ref::().ok_or_else(|| { JsNativeError::typ().with_message( "`resolved_options` can only be called on an `Intl.PluralRules` object", ) diff --git a/boa_engine/src/builtins/intl/segmenter/iterator.rs b/boa_engine/src/builtins/intl/segmenter/iterator.rs index 32615e5c30..55e4753102 100644 --- a/boa_engine/src/builtins/intl/segmenter/iterator.rs +++ b/boa_engine/src/builtins/intl/segmenter/iterator.rs @@ -14,7 +14,7 @@ use crate::{ Context, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; -use super::create_segment_data_object; +use super::{create_segment_data_object, Segmenter}; pub(crate) enum NativeSegmentIterator<'l, 's> { Grapheme(GraphemeClusterBreakIteratorUtf16<'l, 's>), @@ -47,7 +47,7 @@ impl NativeSegmentIterator<'_, '_> { } #[derive(Debug, Trace, Finalize)] -pub struct SegmentIterator { +pub(crate) struct SegmentIterator { segmenter: JsObject, string: JsString, next_segment_index: usize, @@ -90,7 +90,7 @@ impl SegmentIterator { .objects() .iterator_prototypes() .segment(), - ObjectData::segment_iterator(Self { + ObjectData::native_object(Self { segmenter, string, next_segment_index: 0, @@ -107,7 +107,7 @@ impl SegmentIterator { JsNativeError::typ() .with_message("`next` can only be called on a `Segment Iterator` object") })?; - let iter = iter.as_segment_iterator_mut().ok_or_else(|| { + let iter = iter.downcast_mut::().ok_or_else(|| { JsNativeError::typ() .with_message("`next` can only be called on a `Segment Iterator` object") })?; @@ -121,7 +121,7 @@ impl SegmentIterator { // 3. Let segmenter be iterator.[[IteratingSegmenter]]. let segmenter = iter.segmenter.borrow(); let segmenter = segmenter - .as_segmenter() + .downcast_ref::() .expect("segment iterator object should contain a segmenter"); let mut segments = segmenter.native.segment(string); // the first elem is always 0. diff --git a/boa_engine/src/builtins/intl/segmenter/mod.rs b/boa_engine/src/builtins/intl/segmenter/mod.rs index 1ea1f6d2f7..547d789104 100644 --- a/boa_engine/src/builtins/intl/segmenter/mod.rs +++ b/boa_engine/src/builtins/intl/segmenter/mod.rs @@ -1,5 +1,6 @@ use std::ops::Range; +use boa_gc::{empty_trace, Finalize, Trace}; use boa_macros::utf16; use boa_profiler::Profiler; use icu_locid::Locale; @@ -36,12 +37,17 @@ use super::{ Service, }; -#[derive(Debug)] -pub struct Segmenter { +#[derive(Debug, Finalize)] +pub(crate) struct Segmenter { locale: Locale, native: NativeSegmenter, } +// SAFETY: `Segmenter` doesn't contain any traceable data. +unsafe impl Trace for Segmenter { + empty_trace!(); +} + #[derive(Debug)] pub(crate) enum NativeSegmenter { Grapheme(Box), @@ -177,7 +183,7 @@ impl BuiltInConstructor for Segmenter { let segmenter = JsObject::from_proto_and_data_with_shared_shape( context.root_shape(), proto, - ObjectData::segmenter(segmenter), + ObjectData::native_object(segmenter), ); // 14. Return segmenter. @@ -230,7 +236,7 @@ impl Segmenter { JsNativeError::typ() .with_message("`resolved_options` can only be called on an `Intl.Segmenter` object") })?; - let segmenter = segmenter.as_segmenter().ok_or_else(|| { + let segmenter = segmenter.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`resolved_options` can only be called on an `Intl.Segmenter` object") })?; @@ -268,7 +274,7 @@ impl Segmenter { // 2. Perform ? RequireInternalSlot(segmenter, [[InitializedSegmenter]]). let segmenter = this .as_object() - .filter(|o| o.borrow().is_segmenter()) + .filter(|o| o.borrow().is::()) .ok_or_else(|| { JsNativeError::typ().with_message( "`resolved_options` can only be called on an `Intl.Segmenter` object", diff --git a/boa_engine/src/builtins/intl/segmenter/segments.rs b/boa_engine/src/builtins/intl/segmenter/segments.rs index ef7d4bbc9f..680c4a8647 100644 --- a/boa_engine/src/builtins/intl/segmenter/segments.rs +++ b/boa_engine/src/builtins/intl/segmenter/segments.rs @@ -11,10 +11,10 @@ use crate::{ Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; -use super::{create_segment_data_object, SegmentIterator}; +use super::{create_segment_data_object, SegmentIterator, Segmenter}; #[derive(Debug, Trace, Finalize)] -pub struct Segments { +pub(crate) struct Segments { segmenter: JsObject, string: JsString, } @@ -44,9 +44,10 @@ impl Segments { // 3. Set segments.[[SegmentsSegmenter]] to segmenter. // 4. Set segments.[[SegmentsString]] to string. // 5. Return segments. - JsObject::from_proto_and_data( + JsObject::from_proto_and_data_with_shared_shape( + context.root_shape(), context.intrinsics().objects().segments_prototype(), - ObjectData::segments(Self { segmenter, string }), + ObjectData::native_object(Self { segmenter, string }), ) } @@ -60,7 +61,7 @@ impl Segments { JsNativeError::typ() .with_message("`containing` can only be called on a `Segments` object") })?; - let segments = segments.as_segments().ok_or_else(|| { + let segments = segments.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`containing` can only be called on a `Segments` object") })?; @@ -68,7 +69,7 @@ impl Segments { // 3. Let segmenter be segments.[[SegmentsSegmenter]]. let segmenter = segments.segmenter.borrow(); let segmenter = segmenter - .as_segmenter() + .downcast_ref::() .expect("segments object should contain a segmenter"); // 4. Let string be segments.[[SegmentsString]]. @@ -115,7 +116,7 @@ impl Segments { JsNativeError::typ() .with_message("`containing` can only be called on a `Segments` object") })?; - let segments = segments.as_segments().ok_or_else(|| { + let segments = segments.downcast_ref::().ok_or_else(|| { JsNativeError::typ() .with_message("`containing` can only be called on a `Segments` object") })?; diff --git a/boa_engine/src/builtins/string/mod.rs b/boa_engine/src/builtins/string/mod.rs index 2e8c9f0f6c..120a265924 100644 --- a/boa_engine/src/builtins/string/mod.rs +++ b/boa_engine/src/builtins/string/mod.rs @@ -1425,7 +1425,7 @@ impl String { .map(JsObject::borrow) .expect("constructor must return a JsObject"); let collator = collator - .as_collator() + .downcast_ref::() .expect("constructor must return a `Collator` object") .collator(); diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 2e98413264..699e162207 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -30,14 +30,6 @@ use self::{ }, shape::Shape, }; -#[cfg(feature = "intl")] -use crate::builtins::intl::{ - collator::Collator, - date_time_format::DateTimeFormat, - list_format::ListFormat, - plural_rules::PluralRules, - segmenter::{SegmentIterator, Segmenter, Segments}, -}; #[cfg(feature = "temporal")] use crate::builtins::temporal::{ Calendar, Duration, Instant, PlainDate, PlainDateTime, PlainMonthDay, PlainTime, @@ -128,8 +120,18 @@ pub trait NativeObject: Any + Trace { /// Convert the Rust type which implements `NativeObject` to a `&mut dyn Any`. fn as_mut_any(&mut self) -> &mut dyn Any; + + /// Gets the type name of the value. + fn type_name_of_value(&self) -> &'static str { + fn name_of_val(_val: &T) -> &'static str { + std::any::type_name::() + } + + name_of_val(self) + } } +// TODO: Use super trait casting in Rust 1.75 impl NativeObject for T { fn as_any(&self) -> &dyn Any { self @@ -140,6 +142,7 @@ impl NativeObject for T { } } +// TODO: Use super trait casting in Rust 1.75 impl dyn NativeObject { /// Returns `true` if the inner type is the same as `T`. #[inline] @@ -409,37 +412,6 @@ pub enum ObjectKind { /// The `ModuleNamespace` object kind. ModuleNamespace(ModuleNamespace), - /// The `Intl.Collator` object kind. - #[cfg(feature = "intl")] - Collator(Box), - - /// The `Intl.DateTimeFormat` object kind. - #[cfg(feature = "intl")] - DateTimeFormat(Box), - - /// The `Intl.ListFormat` object kind. - #[cfg(feature = "intl")] - ListFormat(Box), - - /// The `Intl.Locale` object kind. - #[cfg(feature = "intl")] - Locale(Box), - - /// The `Intl.Segmenter` object kind. - #[cfg(feature = "intl")] - Segmenter(Segmenter), - - /// The `Segments` object kind. - #[cfg(feature = "intl")] - Segments(Segments), - - /// The `Segment Iterator` object kind. - #[cfg(feature = "intl")] - SegmentIterator(SegmentIterator), - /// The `PluralRules` object kind. - #[cfg(feature = "intl")] - PluralRules(Box), - /// The `Temporal.Instant` object kind. #[cfg(feature = "temporal")] Instant(Instant), @@ -509,19 +481,6 @@ unsafe impl Trace for ObjectKind { Self::WeakMap(wm) => mark(wm), Self::WeakSet(ws) => mark(ws), Self::ModuleNamespace(m) => mark(m), - #[cfg(feature = "intl")] - Self::DateTimeFormat(f) => mark(f), - #[cfg(feature = "intl")] - Self::Collator(co) => mark(co), - #[cfg(feature = "intl")] - Self::Segments(seg) => mark(seg), - #[cfg(feature = "intl")] - Self::SegmentIterator(it) => mark(it), - #[cfg(feature = "intl")] - Self::ListFormat(_) - | Self::Locale(_) - | Self::Segmenter(_) - | Self::PluralRules(_) => {} Self::RegExp(_) | Self::BigInt(_) | Self::Boolean(_) @@ -907,86 +866,6 @@ impl ObjectData { } } - /// Create the `Collator` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn collator(date_time_fmt: Collator) -> Self { - Self { - kind: ObjectKind::Collator(Box::new(date_time_fmt)), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `DateTimeFormat` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn date_time_format(date_time_fmt: Box) -> Self { - Self { - kind: ObjectKind::DateTimeFormat(date_time_fmt), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `ListFormat` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn list_format(list_format: ListFormat) -> Self { - Self { - kind: ObjectKind::ListFormat(Box::new(list_format)), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `Locale` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn locale(locale: icu_locid::Locale) -> Self { - Self { - kind: ObjectKind::Locale(Box::new(locale)), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `Segmenter` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn segmenter(segmenter: Segmenter) -> Self { - Self { - kind: ObjectKind::Segmenter(segmenter), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `Segments` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn segments(segments: Segments) -> Self { - Self { - kind: ObjectKind::Segments(segments), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `SegmentIterator` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn segment_iterator(segment_iterator: SegmentIterator) -> Self { - Self { - kind: ObjectKind::SegmentIterator(segment_iterator), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - - /// Create the `PluralRules` object data - #[cfg(feature = "intl")] - #[must_use] - pub fn plural_rules(plural_rules: PluralRules) -> Self { - Self { - kind: ObjectKind::PluralRules(Box::new(plural_rules)), - internal_methods: &ORDINARY_INTERNAL_METHODS, - } - } - /// Create the `Instant` object data #[cfg(feature = "temporal")] #[must_use] @@ -1119,7 +998,6 @@ impl Debug for ObjectKind { Self::Date(_) => "Date", Self::Global => "Global", Self::Arguments(_) => "Arguments", - Self::NativeObject(_) => "NativeObject", Self::IntegerIndexed(_) => "TypedArray", Self::DataView(_) => "DataView", Self::Promise(_) => "Promise", @@ -1127,22 +1005,7 @@ impl Debug for ObjectKind { Self::WeakMap(_) => "WeakMap", Self::WeakSet(_) => "WeakSet", Self::ModuleNamespace(_) => "ModuleNamespace", - #[cfg(feature = "intl")] - Self::Collator(_) => "Collator", - #[cfg(feature = "intl")] - Self::DateTimeFormat(_) => "DateTimeFormat", - #[cfg(feature = "intl")] - Self::ListFormat(_) => "ListFormat", - #[cfg(feature = "intl")] - Self::Locale(_) => "Locale", - #[cfg(feature = "intl")] - Self::Segmenter(_) => "Segmenter", - #[cfg(feature = "intl")] - Self::Segments(_) => "Segments", - #[cfg(feature = "intl")] - Self::SegmentIterator(_) => "SegmentIterator", - #[cfg(feature = "intl")] - Self::PluralRules(_) => "PluralRules", + Self::NativeObject(obj) => (**obj).type_name_of_value(), #[cfg(feature = "temporal")] Self::Instant(_) => "Instant", #[cfg(feature = "temporal")] @@ -2045,118 +1908,6 @@ impl Object { } } - /// Gets the `Collator` data if the object is a `Collator`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_collator(&self) -> Option<&Collator> { - match self.kind { - ObjectKind::Collator(ref collator) => Some(collator), - _ => None, - } - } - - /// Gets a mutable reference to the `Collator` data if the object is a `Collator`. - #[inline] - #[cfg(feature = "intl")] - pub fn as_collator_mut(&mut self) -> Option<&mut Collator> { - match self.kind { - ObjectKind::Collator(ref mut collator) => Some(collator), - _ => None, - } - } - - /// Checks if it is a `Locale` object. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn is_locale(&self) -> bool { - matches!(self.kind, ObjectKind::Locale(_)) - } - - /// Gets the `Locale` data if the object is a `Locale`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_locale(&self) -> Option<&icu_locid::Locale> { - match self.kind { - ObjectKind::Locale(ref locale) => Some(locale), - _ => None, - } - } - - /// Gets the `ListFormat` data if the object is a `ListFormat`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_list_format(&self) -> Option<&ListFormat> { - match self.kind { - ObjectKind::ListFormat(ref lf) => Some(lf), - _ => None, - } - } - - /// Checks if it is a `Segmenter` object. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn is_segmenter(&self) -> bool { - matches!(self.kind, ObjectKind::Segmenter(_)) - } - - /// Gets the `Segmenter` data if the object is a `Segmenter`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_segmenter(&self) -> Option<&Segmenter> { - match self.kind { - ObjectKind::Segmenter(ref seg) => Some(seg), - _ => None, - } - } - - /// Gets the `Segments` data if the object is a `Segments`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_segments(&self) -> Option<&Segments> { - match self.kind { - ObjectKind::Segments(ref seg) => Some(seg), - _ => None, - } - } - - /// Gets the `SegmentIterator` data if the object is a `SegmentIterator`. - #[inline] - #[cfg(feature = "intl")] - pub fn as_segment_iterator_mut(&mut self) -> Option<&mut SegmentIterator> { - match &mut self.kind { - ObjectKind::SegmentIterator(it) => Some(it), - _ => None, - } - } - - /// Gets the `PluralRules` data if the object is a `PluralRules`. - #[inline] - #[must_use] - #[cfg(feature = "intl")] - pub const fn as_plural_rules(&self) -> Option<&PluralRules> { - match &self.kind { - ObjectKind::PluralRules(it) => Some(it), - _ => None, - } - } - - /// Gets a mutable reference to the `PluralRules` data if the object is a `PluralRules`. - #[inline] - #[cfg(feature = "intl")] - pub fn as_plural_rules_mut(&mut self) -> Option<&mut PluralRules> { - match &mut self.kind { - ObjectKind::PluralRules(plural_rules) => Some(plural_rules), - _ => None, - } - } - /// Gets the `TimeZone` data if the object is a `Temporal.TimeZone`. #[inline] #[must_use] diff --git a/boa_gc/Cargo.toml b/boa_gc/Cargo.toml index 2f682112e7..aea8b175c8 100644 --- a/boa_gc/Cargo.toml +++ b/boa_gc/Cargo.toml @@ -11,15 +11,18 @@ repository.workspace = true rust-version.workspace = true [features] -# Enable default implementatio of trace and finalize thin-vec crate -thinvec = ["thin-vec"] +# Enable default implementations of trace and finalize for the thin-vec crate +thin-vec = ["dep:thin-vec"] +# Enable default implementations of trace and finalize for some `ICU4X` types +icu = ["dep:icu_locid"] [dependencies] boa_profiler.workspace = true boa_macros.workspace = true +hashbrown = { workspace = true, features = ["ahash", "raw"] } thin-vec = { workspace = true, optional = true } -hashbrown = { workspace = true, features = ["ahash", "raw"] } +icu_locid = { workspace = true, optional = true } [lints] workspace = true diff --git a/boa_gc/src/trace.rs b/boa_gc/src/trace.rs index c1de3d44db..d384761bef 100644 --- a/boa_gc/src/trace.rs +++ b/boa_gc/src/trace.rs @@ -438,3 +438,24 @@ unsafe impl Trace for Cell> { } }); } + +#[cfg(feature = "icu")] +mod icu { + use icu_locid::{LanguageIdentifier, Locale}; + + use crate::{Finalize, Trace}; + + impl Finalize for LanguageIdentifier {} + + // SAFETY: `LanguageIdentifier` doesn't have any traceable data. + unsafe impl Trace for LanguageIdentifier { + empty_trace!(); + } + + impl Finalize for Locale {} + + // SAFETY: `LanguageIdentifier` doesn't have any traceable data. + unsafe impl Trace for Locale { + empty_trace!(); + } +}