diff --git a/Cargo.lock b/Cargo.lock index 087328c888c..e5c566e5cc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,7 +379,7 @@ dependencies = [ "float-cmp", "futures-lite 2.5.0", "hashbrown 0.15.2", - "icu_calendar", + "icu_calendar 1.5.2", "icu_casemap", "icu_collator", "icu_datetime", @@ -389,7 +389,7 @@ dependencies = [ "icu_locid_transform", "icu_normalizer", "icu_plurals", - "icu_provider", + "icu_provider 1.5.0", "icu_segmenter", "indexmap", "indoc", @@ -419,9 +419,9 @@ dependencies = [ "thin-vec", "thiserror", "time", - "tinystr", + "tinystr 0.7.6", "web-time", - "writeable", + "writeable 0.5.5", "yoke", "zerofrom", ] @@ -466,7 +466,7 @@ dependencies = [ "icu_locid_transform", "icu_normalizer", "icu_plurals", - "icu_provider", + "icu_provider 1.5.0", "icu_provider_adapters", "icu_provider_blob", "icu_segmenter", @@ -1297,7 +1297,7 @@ dependencies = [ "displaydoc", "ryu", "smallvec", - "writeable", + "writeable 0.5.5", ] [[package]] @@ -1543,10 +1543,10 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff5e3018d703f168b00dcefa540a65f1bbc50754ae32f3f5f0e43fe5ee51502" dependencies = [ - "icu_calendar", + "icu_calendar 1.5.2", "icu_casemap", "icu_collator", - "icu_collections", + "icu_collections 1.5.0", "icu_datetime", "icu_decimal", "icu_experimental", @@ -1556,7 +1556,7 @@ dependencies = [ "icu_normalizer", "icu_plurals", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "icu_segmenter", "icu_timezone", ] @@ -1570,21 +1570,39 @@ dependencies = [ "calendrical_calculations", "databake", "displaydoc", - "icu_calendar_data", "icu_locid", - "icu_locid_transform", - "icu_provider", + "icu_provider 1.5.0", "serde", - "tinystr", - "writeable", - "zerovec", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_calendar" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3689f3f720936703584298dce9711d8c68b7aecef258d0e1e2677ec3d9567ff6" +dependencies = [ + "calendrical_calculations", + "displaydoc", + "icu_calendar_data", + "icu_locale_core", + "icu_provider 2.0.0-beta1", + "tinystr 0.8.0", + "writeable 0.6.0", + "zerovec 0.11.0", ] [[package]] name = "icu_calendar_data" -version = "1.5.0" +version = "2.0.0-beta1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e009b7f0151ee6fb28c40b1283594397e0b7183820793e9ace3dcd13db126d0" +checksum = "a113bfe4a5f0a4f9ab2f4ec5baac9f5cfab7c5ada910abf4b9ed4cfd066881cd" +dependencies = [ + "icu_locale", + "icu_provider_baked", +] [[package]] name = "icu_casemap" @@ -1594,13 +1612,13 @@ checksum = "9ff0c8ae9f8d31b12e27fc385ff9ab1f3cd9b17417c665c49e4ec958c37da75f" dependencies = [ "databake", "displaydoc", - "icu_collections", + "icu_collections 1.5.0", "icu_locid", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "serde", - "writeable", - "zerovec", + "writeable 0.5.5", + "zerovec 0.10.4", ] [[package]] @@ -1609,10 +1627,10 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41aa8d27817174c88860a3227fa5cc50cf2d915367f626d56f5711dd8a2e22a" dependencies = [ - "icu_collections", + "icu_collections 1.5.0", "toml 0.5.11", "wasmi", - "zerovec", + "zerovec 0.10.4", ] [[package]] @@ -1623,15 +1641,15 @@ checksum = "d370371887d31d56f361c3eaa15743e54f13bc677059c9191c77e099ed6966b2" dependencies = [ "databake", "displaydoc", - "icu_collections", + "icu_collections 1.5.0", "icu_normalizer", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "serde", "smallvec", "utf16_iter", "utf8_iter", - "zerovec", + "zerovec 0.10.4", ] [[package]] @@ -1645,7 +1663,20 @@ dependencies = [ "serde", "yoke", "zerofrom", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_collections" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "547ceba155a760830b848d9ae28183bc6bddf1b714ffc27bee1c7144f07229db" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec 0.11.0", ] [[package]] @@ -1659,11 +1690,11 @@ dependencies = [ "either", "elsa", "icu", - "icu_calendar", + "icu_calendar 1.5.2", "icu_casemap", "icu_codepointtrie_builder", "icu_collator", - "icu_collections", + "icu_collections 1.5.0", "icu_datetime", "icu_decimal", "icu_experimental", @@ -1674,7 +1705,7 @@ dependencies = [ "icu_pattern", "icu_plurals", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "icu_provider_adapters", "icu_provider_blob", "icu_segmenter", @@ -1692,13 +1723,13 @@ dependencies = [ "serde", "serde-aux", "serde_json", - "tinystr", + "tinystr 0.7.6", "toml 0.5.11", "twox-hash", "ureq", - "writeable", - "zerotrie", - "zerovec", + "writeable 0.5.5", + "zerotrie 0.1.3", + "zerovec 0.10.4", "zip", ] @@ -1712,18 +1743,18 @@ dependencies = [ "displaydoc", "either", "fixed_decimal", - "icu_calendar", + "icu_calendar 1.5.2", "icu_decimal", "icu_locid", "icu_plurals", - "icu_provider", + "icu_provider 1.5.0", "icu_timezone", "litemap", "serde", "smallvec", - "tinystr", - "writeable", - "zerovec", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", ] [[package]] @@ -1735,9 +1766,9 @@ dependencies = [ "databake", "displaydoc", "fixed_decimal", - "icu_provider", + "icu_provider 1.5.0", "serde", - "writeable", + "writeable 0.5.5", ] [[package]] @@ -1749,7 +1780,7 @@ dependencies = [ "databake", "displaydoc", "fixed_decimal", - "icu_collections", + "icu_collections 1.5.0", "icu_decimal", "icu_locid", "icu_locid_transform", @@ -1757,7 +1788,7 @@ dependencies = [ "icu_pattern", "icu_plurals", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "litemap", "log", "num-bigint", @@ -1765,11 +1796,11 @@ dependencies = [ "num-traits", "serde", "smallvec", - "tinystr", - "writeable", + "tinystr 0.7.6", + "writeable 0.5.5", "zerofrom", - "zerotrie", - "zerovec", + "zerotrie 0.1.3", + "zerovec 0.10.4", ] [[package]] @@ -1781,10 +1812,48 @@ dependencies = [ "databake", "deduplicating_array", "displaydoc", - "icu_provider", + "icu_provider 1.5.0", "regex-automata 0.2.0", "serde", - "writeable", + "writeable 0.5.5", +] + +[[package]] +name = "icu_locale" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d3c7f2dae0cd50d8b681a258e761eb714c9924f8222b7042118c0fb410649" +dependencies = [ + "displaydoc", + "icu_collections 2.0.0-beta1", + "icu_locale_core", + "icu_locale_data", + "icu_provider 2.0.0-beta1", + "potential_utf", + "tinystr 0.8.0", + "zerovec 0.11.0", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36332a8c93574b07598351bb479425282022341528ff521238fd4a48d143162" +dependencies = [ + "displaydoc", + "litemap", + "tinystr 0.8.0", + "writeable 0.6.0", + "zerovec 0.11.0", +] + +[[package]] +name = "icu_locale_data" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222f29513408cc4572fce10bcadd05505c61ca1e30412416661e2fd464821c80" +dependencies = [ + "icu_provider_baked", ] [[package]] @@ -1797,9 +1866,9 @@ dependencies = [ "displaydoc", "litemap", "serde", - "tinystr", - "writeable", - "zerovec", + "tinystr 0.7.6", + "writeable 0.5.5", + "zerovec 0.10.4", ] [[package]] @@ -1812,10 +1881,10 @@ dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", - "icu_provider", + "icu_provider 1.5.0", "serde", - "tinystr", - "zerovec", + "tinystr 0.7.6", + "zerovec 0.10.4", ] [[package]] @@ -1832,16 +1901,16 @@ checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "databake", "displaydoc", - "icu_collections", + "icu_collections 1.5.0", "icu_normalizer_data", "icu_properties", - "icu_provider", + "icu_provider 1.5.0", "serde", "smallvec", "utf16_iter", "utf8_iter", "write16", - "zerovec", + "zerovec 0.10.4", ] [[package]] @@ -1860,7 +1929,7 @@ dependencies = [ "displaydoc", "either", "serde", - "writeable", + "writeable 0.5.5", "yoke", "zerofrom", ] @@ -1874,9 +1943,9 @@ dependencies = [ "databake", "displaydoc", "fixed_decimal", - "icu_provider", + "icu_provider 1.5.0", "serde", - "zerovec", + "zerovec 0.10.4", ] [[package]] @@ -1887,13 +1956,13 @@ checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "databake", "displaydoc", - "icu_collections", + "icu_collections 1.5.0", "icu_locid_transform", "icu_properties_data", - "icu_provider", + "icu_provider 1.5.0", "serde", - "tinystr", - "zerovec", + "tinystr 0.7.6", + "zerovec 0.10.4", ] [[package]] @@ -1912,16 +1981,33 @@ dependencies = [ "displaydoc", "erased-serde", "icu_locid", - "icu_provider_macros", + "icu_provider_macros 1.5.0", "log", "postcard", "serde", "stable_deref_trait", - "tinystr", - "writeable", + "tinystr 0.7.6", + "writeable 0.5.5", "yoke", "zerofrom", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201d2b3bc0bd9a7ad78a00af62374365dd53ee6916942c645cd9e28778c238a5" +dependencies = [ + "displaydoc", + "icu_locale_core", + "icu_provider_macros 2.0.0-beta1", + "stable_deref_trait", + "tinystr 0.8.0", + "writeable 0.6.0", + "yoke", + "zerofrom", + "zerovec 0.11.0", ] [[package]] @@ -1932,10 +2018,21 @@ checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" dependencies = [ "icu_locid", "icu_locid_transform", - "icu_provider", + "icu_provider 1.5.0", "serde", - "tinystr", - "zerovec", + "tinystr 0.7.6", + "zerovec 0.10.4", +] + +[[package]] +name = "icu_provider_baked" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c6494d25b75593ad56dcd9bde1040ef7e22e9c70b24c1de8920d9a919118893" +dependencies = [ + "icu_provider 2.0.0-beta1", + "writeable 0.6.0", + "zerotrie 0.2.0", ] [[package]] @@ -1944,13 +2041,13 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c24b98d1365f55d78186c205817631a4acf08d7a45bdf5dc9dcf9c5d54dccf51" dependencies = [ - "icu_provider", + "icu_provider 1.5.0", "log", "postcard", "serde", - "writeable", - "zerotrie", - "zerovec", + "writeable 0.5.5", + "zerotrie 0.1.3", + "zerovec 0.10.4", ] [[package]] @@ -1964,6 +2061,17 @@ dependencies = [ "syn", ] +[[package]] +name = "icu_provider_macros" +version = "2.0.0-beta1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0c1a4c9cca68c00053013b9ad7dc7d2e69aefed59dd9e38cb63347c28299b0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "icu_segmenter" version = "1.5.0" @@ -1973,12 +2081,12 @@ dependencies = [ "core_maths", "databake", "displaydoc", - "icu_collections", + "icu_collections 1.5.0", "icu_locid", - "icu_provider", + "icu_provider 1.5.0", "serde", "utf8_iter", - "zerovec", + "zerovec 0.10.4", ] [[package]] @@ -1989,12 +2097,12 @@ checksum = "aa91ba6a585939a020c787235daa8aee856d9bceebd6355e283c0c310bc6de96" dependencies = [ "databake", "displaydoc", - "icu_calendar", - "icu_provider", + "icu_calendar 1.5.2", + "icu_provider 1.5.0", "serde", - "tinystr", - "zerotrie", - "zerovec", + "tinystr 0.7.6", + "zerotrie 0.1.3", + "zerovec 0.10.4", ] [[package]] @@ -2134,11 +2242,12 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "ixdtf" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2123305f927452a9502fc05c33800280d90127c95c50eb45ec6b3c50346afbf3" +checksum = "fb6cd1080e64f68b07c577e3c687f4a894b3d1bd6093cb36b55c7bd07675aa3a" dependencies = [ "displaydoc", + "utf8_iter", ] [[package]] @@ -2730,6 +2839,16 @@ dependencies = [ "serde", ] +[[package]] +name = "potential_utf" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a1d6d1132e166768a82805efecd7c326eb8dc70ad4a586da697836b44eb970" +dependencies = [ + "serde", + "zerovec 0.11.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3348,17 +3467,17 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "temporal_rs" version = "0.0.4" -source = "git+https://github.com/boa-dev/temporal.git?rev=016bc31d2ce5484973b71ccdb0faeb33c00a9ae6#016bc31d2ce5484973b71ccdb0faeb33c00a9ae6" +source = "git+https://github.com/boa-dev/temporal.git?rev=4498edf4efa52f0cdec0bbed8bf49cae7e543e74#4498edf4efa52f0cdec0bbed8bf49cae7e543e74" dependencies = [ "bitflags 2.6.0", "combine", "iana-time-zone", - "icu_calendar", + "icu_calendar 2.0.0-beta1", "ixdtf", "jiff-tzdb", "num-traits", "rustc-hash 2.1.0", - "tinystr", + "tinystr 0.8.0", "tzif", "web-time", ] @@ -3501,7 +3620,17 @@ dependencies = [ "databake", "displaydoc", "serde", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "tinystr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b56a820bb70060f096338fcc02edb78cb3f8fb21c5078503f48588cfcaf494" +dependencies = [ + "displaydoc", + "zerovec 0.11.0", ] [[package]] @@ -3649,9 +3778,9 @@ dependencies = [ [[package]] name = "tzif" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b8eb18929606c6f3eea7ef096a91dd5c26dbbde2a20a343c4a409b851666fd" +checksum = "5cecffbab91858408738280e7bb6aac788f59a522dda961cd6b15542f0c08559" dependencies = [ "combine", ] @@ -4158,6 +4287,12 @@ dependencies = [ "either", ] +[[package]] +name = "writeable" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b3b5b7c6114bf7253093603034e102d479ecc8501deca33b6c1c816418b6d2" + [[package]] name = "yoke" version = "0.7.5" @@ -4242,7 +4377,16 @@ dependencies = [ "serde", "yoke", "zerofrom", - "zerovec", + "zerovec 0.10.4", +] + +[[package]] +name = "zerotrie" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa766b97d68da210d29cc0bc8d072d87de9359cb998e4bc30ab4982a1c795d47" +dependencies = [ + "displaydoc", ] [[package]] @@ -4255,7 +4399,18 @@ dependencies = [ "serde", "yoke", "zerofrom", - "zerovec-derive", + "zerovec-derive 0.10.3", +] + +[[package]] +name = "zerovec" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b622856b789971a6fe0442b69f3a2d7ac949005c4c8586b2c4ef09cc5182f2b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive 0.11.0", ] [[package]] @@ -4269,6 +4424,17 @@ dependencies = [ "syn", ] +[[package]] +name = "zerovec-derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "996c67268f00e216986ac140d8de9f47968c330b96aeefcae9ed296f23934448" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zip" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index fc619a70f4d..0b8b5119508 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -112,7 +112,7 @@ intrusive-collections = "0.9.7" cfg-if = "1.0.0" either = "1.13.0" sys-locale = "0.3.2" -temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "016bc31d2ce5484973b71ccdb0faeb33c00a9ae6", features = ["tzdb", "now"] } +temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "4498edf4efa52f0cdec0bbed8bf49cae7e543e74", features = ["tzdb", "now"] } web-time = "1.1.0" criterion = "0.5.1" float-cmp = "0.10.0" diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index f71c28391b3..0fd300cf6e1 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -2,7 +2,7 @@ use super::{ options::{get_temporal_unit, TemporalUnitGroup}, - to_integer_if_integral, DateTimeValues, + DateTimeValues, }; use crate::value::JsVariant; use crate::{ @@ -16,14 +16,14 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ options::{RelativeTo, RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit}, partial::PartialDuration, - primitive::FiniteF64, Duration as InnerDuration, }; @@ -222,66 +222,96 @@ impl BuiltInConstructor for Duration { } // 2. If years is undefined, let y be 0; else let y be ? ToIntegerIfIntegral(years). - let years = args - .get_or_undefined(0) - .map_or(Ok(0), |y| to_integer_if_integral(y, context))?; + let years = args.get_or_undefined(0).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 3. If months is undefined, let mo be 0; else let mo be ? ToIntegerIfIntegral(months). - let months = args - .get_or_undefined(1) - .map_or(Ok(0), |mo| to_integer_if_integral(mo, context))?; + let months = args.get_or_undefined(1).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 4. If weeks is undefined, let w be 0; else let w be ? ToIntegerIfIntegral(weeks). - let weeks = args - .get_or_undefined(2) - .map_or(Ok(0), |wk| to_integer_if_integral(wk, context))?; + let weeks = args.get_or_undefined(2).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 5. If days is undefined, let d be 0; else let d be ? ToIntegerIfIntegral(days). - let days = args - .get_or_undefined(3) - .map_or(Ok(0), |d| to_integer_if_integral(d, context))?; + let days = args.get_or_undefined(3).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 6. If hours is undefined, let h be 0; else let h be ? ToIntegerIfIntegral(hours). - let hours = args - .get_or_undefined(4) - .map_or(Ok(0), |h| to_integer_if_integral(h, context))?; + let hours = args.get_or_undefined(4).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 7. If minutes is undefined, let m be 0; else let m be ? ToIntegerIfIntegral(minutes). - let minutes = args - .get_or_undefined(5) - .map_or(Ok(0), |m| to_integer_if_integral(m, context))?; + let minutes = args.get_or_undefined(5).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 8. If seconds is undefined, let s be 0; else let s be ? ToIntegerIfIntegral(seconds). - let seconds = args - .get_or_undefined(6) - .map_or(Ok(0), |s| to_integer_if_integral(s, context))?; + let seconds = args.get_or_undefined(6).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 9. If milliseconds is undefined, let ms be 0; else let ms be ? ToIntegerIfIntegral(milliseconds). - let milliseconds = args - .get_or_undefined(7) - .map_or(Ok(0), |ms| to_integer_if_integral(ms, context))?; + let milliseconds = args.get_or_undefined(7).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 10. If microseconds is undefined, let mis be 0; else let mis be ? ToIntegerIfIntegral(microseconds). - let microseconds = args - .get_or_undefined(8) - .map_or(Ok(0), |mis| to_integer_if_integral(mis, context))?; + let microseconds = args.get_or_undefined(8).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 11. If nanoseconds is undefined, let ns be 0; else let ns be ? ToIntegerIfIntegral(nanoseconds). - let nanoseconds = args - .get_or_undefined(9) - .map_or(Ok(0), |ns| to_integer_if_integral(ns, context))?; + let nanoseconds = args.get_or_undefined(9).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; let record = InnerDuration::new( - years.into(), - months.into(), - weeks.into(), - days.into(), - hours.into(), - minutes.into(), - seconds.into(), - milliseconds.into(), - microseconds.into(), - nanoseconds.into(), + years.try_into()?, + months.try_into()?, + weeks.try_into()?, + days.try_into()?, + hours.try_into()?, + minutes.try_into()?, + seconds.try_into()?, + milliseconds.try_into()?, + microseconds.try_into()?, + nanoseconds.try_into()?, )?; // 12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns, NewTarget). @@ -929,119 +959,160 @@ pub(crate) fn to_temporal_partial_duration( }; // 2. Let result be a new partial Duration Record with each field set to undefined. - let mut result = PartialDuration::default(); - // 3. NOTE: The following steps read properties and perform independent validation in alphabetical order. // 4. Let days be ? Get(temporalDurationLike, "days"). - let days = unknown_object.get(js_string!("days"), context)?; - if !days.is_undefined() { - // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days). - let _ = result - .days - .insert(FiniteF64::from(to_integer_if_integral(&days, context)?)); - } + // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days). + let days = unknown_object + .get(js_string!("days"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 6. Let hours be ? Get(temporalDurationLike, "hours"). - let hours = unknown_object.get(js_string!("hours"), context)?; // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours). - if !hours.is_undefined() { - let _ = result - .hours - .insert(FiniteF64::from(to_integer_if_integral(&hours, context)?)); - } + let hours = unknown_object + .get(js_string!("hours"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds"). - let microseconds = unknown_object.get(js_string!("microseconds"), context)?; // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds). - if !microseconds.is_undefined() { - let _ = result - .microseconds - .insert(FiniteF64::from(to_integer_if_integral( - µseconds, - context, - )?)); - } + let microseconds = unknown_object + .get(js_string!("microseconds"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds"). - let milliseconds = unknown_object.get(js_string!("milliseconds"), context)?; // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds). - if !milliseconds.is_undefined() { - let _ = result - .milliseconds - .insert(FiniteF64::from(to_integer_if_integral( - &milliseconds, - context, - )?)); - } + let milliseconds = unknown_object + .get(js_string!("milliseconds"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 12. Let minutes be ? Get(temporalDurationLike, "minutes"). - let minutes = unknown_object.get(js_string!("minutes"), context)?; // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes). - if !minutes.is_undefined() { - let _ = result - .minutes - .insert(FiniteF64::from(to_integer_if_integral(&minutes, context)?)); - } + let minutes = unknown_object + .get(js_string!("minutes"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 14. Let months be ? Get(temporalDurationLike, "months"). - let months = unknown_object.get(js_string!("months"), context)?; // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months). - if !months.is_undefined() { - let _ = result - .months - .insert(FiniteF64::from(to_integer_if_integral(&months, context)?)); - } + let months = unknown_object + .get(js_string!("months"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds"). - let nanoseconds = unknown_object.get(js_string!("nanoseconds"), context)?; // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds). - if !nanoseconds.is_undefined() { - let _ = result - .nanoseconds - .insert(FiniteF64::from(to_integer_if_integral( - &nanoseconds, - context, - )?)); - } + let nanoseconds = unknown_object + .get(js_string!("nanoseconds"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 18. Let seconds be ? Get(temporalDurationLike, "seconds"). - let seconds = unknown_object.get(js_string!("seconds"), context)?; // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds). - if !seconds.is_undefined() { - let _ = result - .seconds - .insert(FiniteF64::from(to_integer_if_integral(&seconds, context)?)); - } + let seconds = unknown_object + .get(js_string!("seconds"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 20. Let weeks be ? Get(temporalDurationLike, "weeks"). - let weeks = unknown_object.get(js_string!("weeks"), context)?; // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks). - if !weeks.is_undefined() { - let _ = result - .weeks - .insert(FiniteF64::from(to_integer_if_integral(&weeks, context)?)); - } + let weeks = unknown_object + .get(js_string!("weeks"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 22. Let years be ? Get(temporalDurationLike, "years"). - let years = unknown_object.get(js_string!("years"), context)?; // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years). - if !years.is_undefined() { - let _ = result - .years - .insert(FiniteF64::from(to_integer_if_integral(&years, context)?)); - } + let years = unknown_object + .get(js_string!("years"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; + + let partial = PartialDuration { + years, + months, + weeks, + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + nanoseconds, + }; - // TODO: Implement this functionality better in `temporal_rs`. // 24. If years is undefined, and months is undefined, and weeks is undefined, and days // is undefined, and hours is undefined, and minutes is undefined, and seconds is // undefined, and milliseconds is undefined, and microseconds is undefined, and // nanoseconds is undefined, throw a TypeError exception. - if result.is_empty() { + if partial.is_empty() { return Err(JsNativeError::typ() .with_message("PartialDurationRecord must have a defined field.") .into()); } // 25. Return result. - Ok(result) + Ok(partial) } diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index 182491fbc79..5fe1f9d16d3 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -31,7 +31,7 @@ use temporal_rs::{ }; /// The `Temporal.Instant` object. -#[derive(Debug, Clone, Trace, Finalize, JsData)] +#[derive(Debug, Clone, Copy, Trace, Finalize, JsData)] // SAFETY: Instant does not contain any traceable values. #[boa_gc(unsafe_empty_trace)] pub struct Instant { @@ -530,7 +530,7 @@ fn to_temporal_instant(item: &JsValue, context: &mut Context) -> JsResult() { - return Ok(instant.inner.clone()); + return Ok(instant.inner); } else if let Some(_zdt) = obj.downcast_ref::() { return Err(JsNativeError::error() .with_message("Not yet implemented.") diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index 0769ef4af23..bb814a0a6e1 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -1,5 +1,8 @@ //! The ECMAScript `Temporal` stage 3 built-in implementation. //! +//! Boa's Temporal implementation uses the `temporal_rs` crate +//! for the core functionality of the implementation. +//! //! More information: //! //! [spec]: https://tc39.es/proposal-temporal/ @@ -38,7 +41,10 @@ use crate::{ Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use temporal_rs::{PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime, NS_PER_DAY}; +use temporal_rs::{ + primitive::FiniteF64, PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime, + NS_PER_DAY, +}; // TODO: Remove in favor of `temporal_rs` pub(crate) fn ns_max_instant() -> JsBigInt { @@ -209,33 +215,6 @@ pub(crate) fn _iterator_to_list_of_types( Ok(values) } -// Abstract Operation 13.3 `EpochDaysToEpochMs` -// Migrated to `temporal_rs` - -// 13.4 Date Equations -// implemented in temporal/date_equations.rs - -// Abstract Operation 13.5 `GetOptionsObject ( options )` -// Implemented in builtin/options.rs - -// 13.6 `GetOption ( options, property, type, values, default )` -// Implemented in builtin/options.rs - -// 13.7 `ToTemporalOverflow (options)` -// Now implemented in temporal/options.rs - -// 13.10 `ToTemporalRoundingMode ( normalizedOptions, fallback )` -// Now implemented in builtin/options.rs - -// 13.11 `NegateTemporalRoundingMode ( roundingMode )` -// Now implemented in builtin/options.rs - -// 13.16 `ToTemporalRoundingIncrement ( normalizedOptions )` -// Now implemented in temporal/options.rs - -// 13.17 `ValidateTemporalRoundingIncrement ( increment, dividend, inclusive )` -// Moved to temporal_rs - type RelativeTemporalObjectResult = JsResult<(Option, Option)>; /// 13.21 `ToRelativeTemporalObject ( options )` @@ -260,15 +239,6 @@ pub(crate) fn to_relative_temporal_object( Ok((Some(plain_date), None)) } -// 13.22 `LargerOfTwoTemporalUnits ( u1, u2 )` -// use core::cmp::max - -// 13.23 `MaximumTemporalDurationRoundingIncrement ( unit )` -// Implemented on TemporalUnit in temporal/options.rs - -// 13.26 `GetUnsignedRoundingMode ( roundingMode, isNegative )` -// Implemented on RoundingMode in builtins/options.rs - // 13.26 IsPartialTemporalObject ( object ) pub(crate) fn is_partial_temporal_object<'value>( value: &'value JsValue, @@ -309,79 +279,14 @@ pub(crate) fn is_partial_temporal_object<'value>( Ok(Some(obj)) } -// 13.27 `ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode )` -// Migrated to `temporal_rs` - -// 13.28 `RoundNumberToIncrement ( x, increment, roundingMode )` -// Migrated to `temporal_rs` - -// 13.29 `RoundNumberToIncrementAsIfPositive ( x, increment, roundingMode )` -// Migrated to `temporal_rs` - -/// 13.43 `ToPositiveIntegerWithTruncation ( argument )` -#[inline] -#[allow(unused)] -pub(crate) fn to_positive_integer_with_trunc( - value: &JsValue, - context: &mut Context, -) -> JsResult { - // 1. Let integer be ? ToIntegerWithTruncation(argument). - let int = to_integer_with_truncation(value, context)?; - // 2. If integer ≤ 0, throw a RangeError exception. - if int <= 0 { - return Err(JsNativeError::range() - .with_message("value is not a positive integer") - .into()); - } - // 3. Return integer. - Ok(int) -} - -/// 13.44 `ToIntegerWithTruncation ( argument )` -#[inline] -pub(crate) fn to_integer_with_truncation(value: &JsValue, context: &mut Context) -> JsResult { - // 1. Let number be ? ToNumber(argument). - let number = value.to_number(context)?; - // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception. - if number.is_nan() || number.is_infinite() { - return Err(JsNativeError::range() - .with_message("truncation target must be an integer.") - .into()); +impl JsValue { + pub(crate) fn to_finitef64(&self, context: &mut Context) -> JsResult { + let number = self.to_number(context)?; + let result = FiniteF64::try_from(number)?; + Ok(result) } - // 3. Return truncate(ℝ(number)). - Ok(number.trunc() as i32) } -/// Abstract operation 13.45 `ToIntegerIfIntegral( argument )` -#[inline] -pub(crate) fn to_integer_if_integral(arg: &JsValue, _context: &mut Context) -> JsResult { - // 1. Let number be ? ToNumber(argument). - // 2. If IsIntegralNumber(number) is false, throw a RangeError exception. - // 3. Return ℝ(number). - let Some(arg) = arg.as_i32() else { - return Err(JsNativeError::range() - .with_message("value to convert is not an integral number.") - .into()); - }; - - Ok(arg) -} - -// 13.46 `PrepareTemporalFields ( fields, fieldNames, requiredFields [ , duplicateBehaviour ] )` -// See fields.rs - -// NOTE: op -> true == until | false == since -// 13.47 `GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, fallbackSmallestUnit, smallestLargestDefaultUnit )` -// Migrated to `temporal_rs` - -// NOTE: used for MergeFields methods. Potentially can be omitted in favor of `TemporalFields`. -// 14.6 `CopyDataProperties ( target, source, excludedKeys [ , excludedValues ] )` -// Migrated or repurposed to `temporal_rs`/`fields.rs` - -// Note: Deviates from Proposal spec -> proto appears to be always null across the specification. -// 14.7 `SnapshotOwnProperties ( source, proto [ , excludedKeys [ , excludedValues ] ] )` -// Migrated or repurposed to `temporal_rs`/`fields.rs` - fn extract_from_temporal_type( object: &JsObject, date_f: DF, diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index f58411ecab1..8b914b4e85f 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -21,8 +21,7 @@ use crate::{ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - options::ArithmeticOverflow, partial::PartialDate, Calendar, PlainDate as InnerDate, - TinyAsciiStr, + options::ArithmeticOverflow, partial::PartialDate, PlainDate as InnerDate, TinyAsciiStr, }; use super::{ @@ -244,20 +243,23 @@ impl BuiltInConstructor for PlainDate { .into()); }; - let iso_year = super::to_integer_with_truncation(args.get_or_undefined(0), context)?; - let iso_month = super::to_integer_with_truncation(args.get_or_undefined(1), context)?; - let iso_day = super::to_integer_with_truncation(args.get_or_undefined(2), context)?; + let year = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); + let month = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); + let day = args + .get_or_undefined(2) + .to_finitef64(context)? + .as_integer_with_truncation::(); let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(3))?; - Ok(create_temporal_date( - iso_year, - iso_month, - iso_day, - calendar_slot, - Some(new_target), - context, - )? - .into()) + let inner = InnerDate::try_new(year, month.into(), day.into(), calendar_slot)?; + + Ok(create_temporal_date(inner, Some(new_target), context)?.into()) } } @@ -491,27 +493,11 @@ impl PlainDate { if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::) { let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?; let _ = get_option::(&options, js_string!("overflow"), context)?; - return create_temporal_date( - date.inner.iso_year(), - date.inner.iso_month().into(), - date.inner.iso_day().into(), - date.inner.calendar().clone(), - None, - context, - ) - .map(Into::into); + return create_temporal_date(date.inner.clone(), None, context).map(Into::into); } let resolved_date = to_temporal_date(item, options.cloned(), context)?; - create_temporal_date( - resolved_date.iso_year(), - resolved_date.iso_month().into(), - resolved_date.iso_day().into(), - resolved_date.calendar().clone(), - None, - context, - ) - .map(Into::into) + create_temporal_date(resolved_date, None, context).map(Into::into) } /// 3.2.3 Temporal.PlainDate.compare ( one, two ) @@ -600,15 +586,7 @@ impl PlainDate { // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options). let resolved_date = date.inner.add(&duration, overflow)?; - create_temporal_date( - resolved_date.iso_year(), - resolved_date.iso_month().into(), - resolved_date.iso_day().into(), - resolved_date.calendar().clone(), - None, - context, - ) - .map(Into::into) + create_temporal_date(resolved_date, None, context).map(Into::into) } fn subtract(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { @@ -632,15 +610,7 @@ impl PlainDate { // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 7. Return ? AddDate(calendarRec, temporalDate, negatedDuration, options). let resolved_date = date.inner.subtract(&duration, overflow)?; - create_temporal_date( - resolved_date.iso_year(), - resolved_date.iso_month().into(), - resolved_date.iso_day().into(), - resolved_date.calendar().clone(), - None, - context, - ) - .map(Into::into) + create_temporal_date(resolved_date, None, context).map(Into::into) } // 3.3.24 Temporal.PlainDate.prototype.with ( temporalDateLike [ , options ] ) @@ -677,15 +647,7 @@ impl PlainDate { // 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions). let resolved_date = date.inner.with(partial, overflow)?; - create_temporal_date( - resolved_date.iso_year(), - resolved_date.iso_month().into(), - resolved_date.iso_day().into(), - resolved_date.calendar().clone(), - None, - context, - ) - .map(Into::into) + create_temporal_date(resolved_date, None, context).map(Into::into) } /// 3.3.26 Temporal.PlainDate.prototype.withCalendar ( calendarLike ) @@ -699,15 +661,7 @@ impl PlainDate { let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(0))?; let resolved_date = date.inner.with_calendar(calendar)?; - create_temporal_date( - resolved_date.iso_year(), - resolved_date.iso_month().into(), - resolved_date.iso_day().into(), - resolved_date.calendar().clone(), - None, - context, - ) - .map(Into::into) + create_temporal_date(resolved_date, None, context).map(Into::into) } fn until(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { @@ -797,14 +751,7 @@ impl PlainDate { impl PlainDate { /// Utitily function for translating a `Temporal.PlainDate` into a `JsObject`. pub(crate) fn as_object(&self, context: &mut Context) -> JsResult { - create_temporal_date( - self.inner.iso_year(), - self.inner.iso_month().into(), - self.inner.iso_day().into(), - self.inner.calendar().clone(), - None, - context, - ) + create_temporal_date(self.inner.clone(), None, context) } } @@ -813,16 +760,12 @@ impl PlainDate { /// 3.5.3 `CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] )` pub(crate) fn create_temporal_date( - iso_year: i32, - iso_month: i32, - iso_day: i32, - calendar_slot: Calendar, + inner: InnerDate, new_target: Option<&JsValue>, context: &mut Context, ) -> JsResult { // 1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception. // 2. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception. - let inner = InnerDate::try_new(iso_year, iso_month, iso_day, calendar_slot)?; // 3. If newTarget is not present, set newTarget to %Temporal.PlainDate%. let new_target = if let Some(new_target) = new_target { @@ -958,11 +901,21 @@ pub(crate) fn to_partial_date_record( // TODO: Most likely need to use an iterator to handle. let day = partial_object .get(js_string!("day"), context)? - .map(|v| super::to_positive_integer_with_trunc(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + finite + .as_positive_integer_with_truncation() + .map_err(JsError::from) + }) .transpose()?; let month = partial_object .get(js_string!("month"), context)? - .map(|v| super::to_positive_integer_with_trunc(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + finite + .as_positive_integer_with_truncation() + .map_err(JsError::from) + }) .transpose()?; let month_code = partial_object .get(js_string!("monthCode"), context)? @@ -973,17 +926,23 @@ pub(crate) fn to_partial_date_record( .with_message("The monthCode field value must be a string.") .into()); }; - TinyAsciiStr::<4>::from_str(&month_code.to_std_string_escaped()) + TinyAsciiStr::<4>::try_from_str(&month_code.to_std_string_escaped()) .map_err(|e| JsError::from(JsNativeError::typ().with_message(e.to_string()))) }) .transpose()?; let year = partial_object .get(js_string!("year"), context)? - .map(|v| super::to_integer_if_integral(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()?; let era_year = partial_object .get(js_string!("eraYear"), context)? - .map(|v| super::to_integer_if_integral(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()?; let era = partial_object .get(js_string!("era"), context)? @@ -996,7 +955,7 @@ pub(crate) fn to_partial_date_record( )); }; // TODO: double check if an invalid monthCode is a range or type error. - TinyAsciiStr::<19>::from_str(&era.to_std_string_escaped()) + TinyAsciiStr::<19>::try_from_str(&era.to_std_string_escaped()) .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string()))) }) .transpose()?; diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index 73811ecc439..d7ab63c04dc 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -4,7 +4,7 @@ use crate::{ builtins::{ options::{get_option, get_options_object}, - temporal::{to_integer_with_truncation, to_partial_date_record, to_partial_time_record}, + temporal::{to_partial_date_record, to_partial_time_record}, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, @@ -14,7 +14,8 @@ use crate::{ realm::Realm, string::StaticJsStrings, value::IntoOrUndefined, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -22,6 +23,12 @@ use boa_profiler::Profiler; #[cfg(test)] mod tests; +use temporal_rs::{ + options::{ArithmeticOverflow, RoundingIncrement, RoundingOptions, TemporalRoundingMode}, + partial::PartialDateTime, + PlainDateTime as InnerDateTime, PlainTime, +}; + use super::{ calendar::{get_temporal_calendar_slot_value_with_default, to_temporal_calendar_slot_value}, create_temporal_duration, @@ -29,11 +36,6 @@ use super::{ to_temporal_duration_record, to_temporal_time, PlainDate, ZonedDateTime, }; use crate::value::JsVariant; -use temporal_rs::{ - options::{ArithmeticOverflow, RoundingIncrement, RoundingOptions, TemporalRoundingMode}, - partial::PartialDateTime, - PlainDateTime as InnerDateTime, PlainTime, -}; /// The `Temporal.PlainDateTime` object. #[derive(Debug, Clone, Trace, Finalize, JsData)] @@ -308,48 +310,73 @@ impl BuiltInConstructor for PlainDateTime { }; // 2. Set isoYear to ? ToIntegerWithTruncation(isoYear). - let iso_year = to_integer_with_truncation(args.get_or_undefined(0), context)?; + let iso_year = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 3. Set isoMonth to ? ToIntegerWithTruncation(isoMonth). - let iso_month = to_integer_with_truncation(args.get_or_undefined(1), context)?; + let iso_month = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 4. Set isoDay to ? ToIntegerWithTruncation(isoDay). - let iso_day = to_integer_with_truncation(args.get_or_undefined(2), context)?; + let iso_day = args + .get_or_undefined(2) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour). - let hour = args - .get_or_undefined(3) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let hour = args.get_or_undefined(3).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute). - let minute = args - .get_or_undefined(4) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let minute = args.get_or_undefined(4).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second). - let second = args - .get_or_undefined(5) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let second = args.get_or_undefined(5).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond). let millisecond = args .get_or_undefined(6) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond). let microsecond = args .get_or_undefined(7) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond). let nanosecond = args .get_or_undefined(8) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; - // 11. Let calendar be ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(9))?; let dt = InnerDateTime::new( iso_year, - iso_month, - iso_day, - hour, - minute, - second, - millisecond, - microsecond, - nanosecond, + iso_month.into(), + iso_day.into(), + hour.into(), + minute.into(), + second.into(), + millisecond.into(), + microsecond.into(), + nanosecond.into(), calendar_slot, )?; diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index 1713cc005fc..c665d775126 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -25,10 +25,7 @@ use temporal_rs::{ PlainDateTime, PlainMonthDay as InnerMonthDay, TinyAsciiStr, }; -use super::{ - calendar::to_temporal_calendar_slot_value, to_integer_if_integral, - to_positive_integer_with_trunc, DateTimeValues, -}; +use super::{calendar::to_temporal_calendar_slot_value, DateTimeValues}; /// The `Temporal.PlainMonthDay` object. #[derive(Debug, Clone, Trace, Finalize, JsData)] @@ -201,20 +198,29 @@ impl BuiltInConstructor for PlainMonthDay { .into()); } - let year = args.get_or_undefined(3); - let ref_year = if year.is_undefined() { - None - } else { - Some(super::to_integer_with_truncation(year, context)?) - }; + let ref_year = args + .get_or_undefined(3) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; // We can ignore 2 as the underlying temporal library handles the reference year - let m = super::to_integer_with_truncation(args.get_or_undefined(0), context)?; - let d = super::to_integer_with_truncation(args.get_or_undefined(1), context)?; + let m = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); + + let d = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); + let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; let inner = InnerMonthDay::new_with_overflow( - m, - d, + m.into(), + d.into(), calendar, ArithmeticOverflow::Constrain, ref_year, @@ -326,12 +332,24 @@ fn to_temporal_month_day( } else if item.is_object() { let day = item .get_v(js_string!("day"), context)? - .map(|v| to_positive_integer_with_trunc(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + // TODO: Update to the below to u8 after temporal_rs change + finite + .as_positive_integer_with_truncation::() + .map_err(JsError::from) + }) .transpose()?; let month = item .get_v(js_string!("month"), context)? - .map(|v| to_positive_integer_with_trunc(v, context)) + .map(|v| { + let finite = v.to_finitef64(context)?; + // TODO: Update to the below to u8 after temporal_rs change + finite + .as_positive_integer_with_truncation::() + .map_err(JsError::from) + }) .transpose()?; let month_code = item @@ -348,11 +366,12 @@ fn to_temporal_month_day( }) .transpose()?; - let year = item - .get_v(js_string!("year"), context)? - .map(|v| to_integer_if_integral(v, context)) - .transpose()? - .unwrap_or(1972); + let year = + item.get_v(js_string!("year"), context)? + .map_or(Ok::(1972), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; let partial_date = &PartialDate { month, diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index fd9679b91ec..e6b015f0b15 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -3,7 +3,7 @@ use super::{ create_temporal_duration, options::{get_difference_settings, get_temporal_unit, TemporalUnitGroup}, - to_integer_with_truncation, to_temporal_duration_record, PlainDateTime, ZonedDateTime, + to_temporal_duration_record, PlainDateTime, ZonedDateTime, }; use crate::value::JsVariant; use crate::{ @@ -17,7 +17,8 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -149,32 +150,53 @@ impl BuiltInConstructor for PlainTime { } // 2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour). - let hour = args - .get_or_undefined(0) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let hour = args.get_or_undefined(0).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute). - let minute = args - .get_or_undefined(1) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let minute = args.get_or_undefined(1).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second). - let second = args - .get_or_undefined(2) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + let second = args.get_or_undefined(2).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond). let millisecond = args .get_or_undefined(3) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond). let microsecond = args .get_or_undefined(4) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; + // 7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond). let nanosecond = args .get_or_undefined(5) - .map_or(Ok(0), |v| to_integer_with_truncation(v, context))?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; - let inner = - PlainTimeInner::new(hour, minute, second, millisecond, microsecond, nanosecond)?; + let inner = PlainTimeInner::new( + hour.into(), + minute.into(), + second.into(), + millisecond.into(), + microsecond.into(), + nanosecond.into(), + )?; // 8. Return ? CreateTemporalTime(hour, minute, second, millisecond, microsecond, nanosecond, NewTarget). create_temporal_time(inner, Some(new_target), context).map(Into::into) @@ -701,33 +723,57 @@ pub(crate) fn to_partial_time_record( ) -> JsResult { let hour = partial_object .get(js_string!("hour"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); let minute = partial_object .get(js_string!("minute"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); let second = partial_object .get(js_string!("second"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); let millisecond = partial_object .get(js_string!("millisecond"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); let microsecond = partial_object .get(js_string!("microsecond"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); let nanosecond = partial_object .get(js_string!("nanosecond"), context)? - .map(|v| super::to_integer_if_integral(v, context)) - .transpose()?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .map(Into::into); Ok(PartialTime { hour, diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index 7f6349cec40..4a075a21c5a 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -13,7 +13,8 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -170,26 +171,40 @@ impl BuiltInConstructor for PlainYearMonth { .into()); } - let day = args.get_or_undefined(3); // 2. If referenceISODay is undefined, then - let ref_day = if day.is_undefined() { - // a. Set referenceISODay to 1𝔽. - None - } else { - // 6. Let ref be ? ToIntegerWithTruncation(referenceISODay). - Some(super::to_integer_with_truncation(day, context)?) - }; - + // a. Set referenceISODay to 1𝔽. // 3. Let y be ? ToIntegerWithTruncation(isoYear). - let y = super::to_integer_with_truncation(args.get_or_undefined(0), context)?; + let y = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); + // 4. Let m be ? ToIntegerWithTruncation(isoMonth). - let m = super::to_integer_with_truncation(args.get_or_undefined(1), context)?; + let m = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); + // 5. Let calendar be ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; + // 6. Let ref be ? ToIntegerWithTruncation(referenceISODay). + let ref_day = args + .get_or_undefined(3) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; + // 7. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget). - let inner = - InnerYearMonth::new_with_overflow(y, m, ref_day, calendar, ArithmeticOverflow::Reject)?; + let inner = InnerYearMonth::new_with_overflow( + y, + m, + ref_day.map(Into::into), + calendar, + ArithmeticOverflow::Reject, + )?; create_temporal_year_month(inner, Some(new_target), context) } @@ -219,22 +234,38 @@ impl PlainYearMonth { let overflow = get_option(&options, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); + let year = item + .get_v(js_string!("year"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .unwrap_or_default(); + + let month = item + .get_v(js_string!("month"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .unwrap_or_default(); + + let ref_day = item + .get_v(js_string!("day"), context)? + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; + // a. Let calendar be ? ToTemporalCalendar(item). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(1))?; InnerYearMonth::new_with_overflow( - super::to_integer_with_truncation( - &item.get_v(js_string!("year"), context)?, - context, - )?, - super::to_integer_with_truncation( - &item.get_v(js_string!("month"), context)?, - context, - )?, - super::to_integer_with_truncation( - &item.get_v(js_string!("day"), context)?, - context, - ) - .ok(), + year, + month, + ref_day.map(Into::into), calendar, overflow, )?