|
2 | 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this
|
3 | 3 | // file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
4 | 4 |
|
| 5 | +use std::time::SystemTime; |
| 6 | + |
5 | 7 | use crate::{
|
6 |
| - ecmascript::types::OrdinaryObject, |
| 8 | + SmallInteger, |
| 9 | + ecmascript::types::{IntoValue, OrdinaryObject, Value}, |
7 | 10 | heap::{CompactionLists, HeapMarkAndSweep, WorkQueues},
|
8 | 11 | };
|
9 |
| -use std::time::SystemTime; |
| 12 | + |
| 13 | +/// ### [21.4.1.1 Time Values and Time Range](https://tc39.es/ecma262/#sec-time-values-and-time-range) |
| 14 | +/// |
| 15 | +/// A Number can exactly represent all integers from -9,007,199,254,740,992 |
| 16 | +/// to 9,007,199,254,740,992 (21.1.2.8 and 21.1.2.6). A time value supports |
| 17 | +/// a slightly smaller range of -8,640,000,000,000,000 to 8,640,000,000,000,000 milliseconds. |
| 18 | +/// This yields a supported time value range of exactly -100,000,000 days |
| 19 | +/// to 100,000,000 days relative to midnight at the beginning of 1 January 1970 UTC. |
| 20 | +/// |
| 21 | +/// In that case, the time value can be either: |
| 22 | +/// |
| 23 | +/// - Invalid, which is presented as `i64::MAX` |
| 24 | +/// - An integer in the range of -8,640,000,000,000,000 to 8,640,000,000,000,000, |
| 25 | +/// which is represented as a non-max `i64`, and can also fit in `SmallInteger` |
| 26 | +#[derive(Debug, Clone, Copy)] |
| 27 | +#[repr(transparent)] |
| 28 | +pub(crate) struct DateValue(i64); |
| 29 | + |
| 30 | +impl DateValue { |
| 31 | + pub const NAN: Self = Self(i64::MAX); |
| 32 | + |
| 33 | + pub fn get_i64(self) -> Option<i64> { |
| 34 | + if self.0 == i64::MAX { |
| 35 | + None |
| 36 | + } else { |
| 37 | + Some(self.0) |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + pub fn get_f64(self) -> Option<f64> { |
| 42 | + self.get_i64().map(|v| v as f64) |
| 43 | + } |
| 44 | + |
| 45 | + pub fn now() -> Self { |
| 46 | + let now = SystemTime::now(); |
| 47 | + let now = now |
| 48 | + .duration_since(SystemTime::UNIX_EPOCH) |
| 49 | + .expect("Time went backwards") |
| 50 | + .as_millis(); |
| 51 | + Self(now as i64) |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +/// ### [21.4.1.31 TimeClip ( time )](https://tc39.es/ecma262/#sec-timeclip) |
| 56 | +/// |
| 57 | +/// The abstract operation TimeClip takes argument time (a Number) and returns |
| 58 | +/// a Number. It calculates a number of milliseconds. |
| 59 | +pub(crate) fn time_clip(time: f64) -> DateValue { |
| 60 | + // 1. If time is not finite, return NaN. |
| 61 | + if !time.is_finite() { |
| 62 | + return DateValue::NAN; |
| 63 | + } |
| 64 | + |
| 65 | + // 2. If abs(ℝ(time)) > 8.64 × 10**15, return NaN. |
| 66 | + if time.abs() > 8.64e15 { |
| 67 | + return DateValue::NAN; |
| 68 | + } |
| 69 | + |
| 70 | + // 3. Return 𝔽(! ToIntegerOrInfinity(time)). |
| 71 | + DateValue(time.trunc() as i64) |
| 72 | +} |
| 73 | + |
| 74 | +impl<'a> IntoValue<'a> for DateValue { |
| 75 | + fn into_value(self) -> Value<'a> { |
| 76 | + if let Some(value) = self.get_f64() { |
| 77 | + // SAFETY: `value` is guaranteed to be in the range of `SmallInteger`. |
| 78 | + Value::Integer(SmallInteger::try_from(value).unwrap()) |
| 79 | + } else { |
| 80 | + Value::nan() |
| 81 | + } |
| 82 | + } |
| 83 | +} |
10 | 84 |
|
11 | 85 | #[derive(Debug, Clone, Copy)]
|
12 | 86 | pub struct DateHeapData {
|
13 | 87 | pub(crate) object_index: Option<OrdinaryObject<'static>>,
|
14 |
| - pub(crate) date: Option<SystemTime>, |
| 88 | + pub(crate) date: DateValue, |
15 | 89 | }
|
16 | 90 |
|
17 | 91 | impl DateHeapData {
|
18 | 92 | pub(crate) fn new_invalid() -> Self {
|
19 | 93 | Self {
|
20 | 94 | object_index: None,
|
21 |
| - date: None, |
| 95 | + date: DateValue::NAN, |
22 | 96 | }
|
23 | 97 | }
|
24 | 98 | }
|
|
0 commit comments