@@ -9,13 +9,13 @@ mod plain_time_prototype;
99pub ( crate ) use data:: * ;
1010pub ( crate ) use plain_time_constructor:: * ;
1111pub ( crate ) use plain_time_prototype:: * ;
12+ use temporal_rs:: options:: { Overflow , Unit , UnitGroup } ;
1213
1314use crate :: {
1415 ecmascript:: {
15- Agent , ExceptionType , Function , InternalMethods , InternalSlots , JsResult , OrdinaryObject ,
16- ProtoIntrinsics , Value , object_handle, ordinary_populate_from_constructor,
16+ Agent , BUILTIN_STRING_MEMORY , DurationRecord , ExceptionType , Function , InternalMethods , InternalSlots , JsResult , Object , OrdinaryObject , ProtoIntrinsics , String , TemporalDuration , Value , get, get_difference_settings, get_options_object, get_temporal_overflow_option, object_handle, ordinary_populate_from_constructor, temporal_err_to_js_err, to_integer_with_truncation
1717 } ,
18- engine:: { Bindable , GcScope , NoGcScope } ,
18+ engine:: { Bindable , GcScope , NoGcScope , Scopable } ,
1919 heap:: {
2020 ArenaAccess , ArenaAccessMut , BaseIndex , CompactionLists , CreateHeapData , Heap ,
2121 HeapMarkAndSweep , HeapSweepWeakReference , WorkQueues , arena_vec_access,
@@ -133,3 +133,254 @@ pub(crate) fn create_temporal_plain_time<'gc>(
133133 . unwrap ( ) ,
134134 )
135135}
136+
137+ /// ### [4.5.6 ToTemporalTime ( item [ , options ] )](https://tc39.es/proposal-temporal/#sec-temporal-totemporaltime)
138+ ///
139+ /// The abstract operation ToTemporalTime takes argument item (an ECMAScript language value) and optional argument
140+ /// options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime
141+ /// or a throw Completion. Converts item to a new Temporal.PlainTime instance if possible, and throws otherwise.
142+ pub ( crate ) fn to_temporal_time < ' gc > (
143+ agent : & mut Agent ,
144+ item : Value ,
145+ options : Option < Value > ,
146+ mut gc : GcScope < ' gc , ' _ > ,
147+ ) -> JsResult < ' gc , temporal_rs:: PlainTime > {
148+ let item = item. bind ( gc. nogc ( ) ) ;
149+
150+ // 1. If options is not present, set options to undefined.
151+ let options = options. unwrap_or ( Value :: Undefined ) ;
152+ // 2. If item is an Object, then
153+ // a. If item has an [[InitializedTemporalTime]] internal slot, then
154+ if let Value :: PlainTime ( time) = item {
155+ // i. Let resolvedOptions be ? GetOptionsObject(options).
156+ // let resolved_options = get_options_object(agent, options, gc.nogc()).unbind()?;
157+ // ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
158+ // get_temporal_overflow_option(agent, resolved_options, gc.reborrow()).unbind()?;
159+ // iii. Return ! CreateTemporalTime(item.[[Time]]).
160+ return Ok ( * time. inner_plain_time ( agent) ) ;
161+ } else if let Value :: Object ( item) = item {
162+ // b. If item has an [[InitializedTemporalDateTime]] internal slot, then
163+ // i. Let resolvedOptions be ? GetOptionsObject(options).
164+ // ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
165+ // iii. Return ! CreateTemporalTime(item.[[ISODateTime]].[[Time]]).
166+
167+ // c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
168+ // i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
169+ // ii. Let resolvedOptions be ? GetOptionsObject(options).
170+ // iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
171+ // iv. Return ! CreateTemporalTime(isoDateTime.[[Time]]).
172+
173+ // d. Let result be ? ToTemporalTimeRecord(item).
174+ let result = to_temporal_time_record ( agent, item. unbind ( ) . into ( ) , gc. reborrow ( ) )
175+ . unbind ( ) ?
176+ . bind ( gc. nogc ( ) ) ;
177+ // e. Let resolvedOptions be ? GetOptionsObject(options).
178+ let resolved_options = get_options_object ( agent, options, gc. nogc ( ) )
179+ . unbind ( ) ?;
180+ // f. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
181+ let overflow = if let Some ( resolved_options) = resolved_options {
182+ get_temporal_overflow_option ( agent, resolved_options, gc. reborrow ( ) )
183+ . map_err ( |e| e. unbind ( ) ) ?
184+ } else {
185+ Overflow :: Constrain
186+ } ;
187+ // g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], overflow).
188+ return temporal_rs:: PlainTime :: from_partial ( result, Some ( overflow) )
189+ . map_err ( |err| temporal_err_to_js_err ( agent, err, gc. into_nogc ( ) ) ) ;
190+ }
191+
192+ // 3. Else,
193+ // a. If item is not a String, throw a TypeError exception.
194+ let Ok ( item) = String :: try_from ( item) else {
195+ return Err ( agent. throw_exception_with_static_message (
196+ ExceptionType :: TypeError ,
197+ "item is not a String" ,
198+ gc. into_nogc ( ) ,
199+ ) ) ;
200+ } ;
201+
202+ // b. Let parseResult be ? ParseISODateTime(item, « TemporalTimeString »).
203+ // c. Assert: parseResult.[[Time]] is not start-of-day.
204+ // d. Set result to parseResult.[[Time]].
205+ // e. NOTE: A successful parse using TemporalTimeString guarantees absence of ambiguity with respect to any ISO 8601 date-only, year-month, or month-day representation.
206+ let result = match temporal_rs:: PlainTime :: from_utf8 ( item. as_bytes ( agent) ) {
207+ Ok ( v) => v,
208+ Err ( err) => return Err ( temporal_err_to_js_err ( agent, err, gc. into_nogc ( ) ) ) ,
209+ } ;
210+ // f. Let resolvedOptions be ? GetOptionsObject(options).
211+ let resolved_options = get_options_object ( agent, options, gc. nogc ( ) ) . unbind ( ) ?;
212+ // g. Perform ? GetTemporalOverflowOption(resolvedOptions).
213+ if let Some ( resolved_options) = resolved_options {
214+ get_temporal_overflow_option ( agent, resolved_options, gc. reborrow ( ) )
215+ . map_err ( |e| e. unbind ( ) ) ?;
216+ }
217+
218+ // 4. Return ! CreateTemporalTime(result).
219+ Ok ( result)
220+ }
221+ /// ### [4.5.12 ToTemporalTimeRecord ( temporalTimeLike [ , completeness ] )](https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimerecord)
222+ /// The abstract operation ToTemporalTimeRecord takes argument temporalTimeLike (an Object) and optional argument completeness (either partial or complete) and returns either a normal
223+ /// completion containing a TemporalTimeLike Record or a throw completion. It converts temporalTimeLike to a TemporalTimeLike Record by reading time component properties, with missing
224+ /// components set to 0 if completeness is complete or to unset if partial. It throws a TypeError if temporalTimeLike has no recognized time component properties. It performs the following steps when called:
225+ fn to_temporal_time_record < ' gc > (
226+ agent : & mut Agent ,
227+ item : Object ,
228+ mut gc : GcScope < ' gc , ' _ > ,
229+ ) -> JsResult < ' gc , temporal_rs:: partial:: PartialTime > {
230+ let item = item. scope ( agent, gc. nogc ( ) ) ;
231+ // 1. If completeness is not present, set completeness to complete.
232+ // 2. If completeness is complete, then
233+ // a. Let result be a new TemporalTimeLike Record with each field set to 0.
234+ // 3. Else,
235+ // a. Let result be a new TemporalTimeLike Record with each field set to unset.
236+ let mut result = temporal_rs:: partial:: PartialTime :: new ( ) ;
237+ // 4. Let any be false.
238+ let mut any = false ;
239+ // 5. Let hour be ? Get(temporalTimeLike, "hour").
240+ let hour = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . hour . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
241+ // 6. If hour is not undefined, then
242+ if !hour. is_undefined ( ) {
243+ // a. Set result.[[Hour]] to ? ToIntegerWithTruncation(hour).
244+ result. hour = Some ( u8:: try_from ( to_integer_with_truncation ( agent, hour. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u8:: MAX ) ) ;
245+ // b. Set any to true.
246+ any = true ;
247+ }
248+ // 7. Let microsecond be ? Get(temporalTimeLike, "microsecond").
249+ let microsecond = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . microsecond . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
250+ // 8. If microsecond is not undefined, then
251+ if !microsecond. is_undefined ( ) {
252+ // a. Set result.[[Microsecond]] to ? ToIntegerWithTruncation(microsecond).
253+ result. microsecond = Some ( u16:: try_from ( to_integer_with_truncation ( agent, microsecond. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u16:: MAX ) ) ;
254+ // b. Set any to true.
255+ any = true ;
256+ }
257+ // 9. Let millisecond be ? Get(temporalTimeLike, "millisecond").
258+ let millisecond = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . millisecond . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
259+ // 10. If millisecond is not undefined, then
260+ if !millisecond. is_undefined ( ) {
261+ // a. Set result.[[Millisecond]] to ? ToIntegerWithTruncation(millisecond).
262+ result. millisecond = Some ( u16:: try_from ( to_integer_with_truncation ( agent, millisecond. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u16:: MAX ) ) ;
263+ // b. Set any to true.
264+ any = true ;
265+ }
266+ // 11. Let minute be ? Get(temporalTimeLike, "minute").
267+ let minute = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . minute . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
268+ // 12. If minute is not undefined, then
269+ if !minute. is_undefined ( ) {
270+ // a. Set result.[[Minute]] to ? ToIntegerWithTruncation(minute).
271+ result. minute = Some ( u8:: try_from ( to_integer_with_truncation ( agent, minute. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u8:: MAX ) ) ;
272+ // b. Set any to true.
273+ any = true ;
274+ }
275+ // 13. Let nanosecond be ? Get(temporalTimeLike, "nanosecond").
276+ let nanosecond = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . nanosecond . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
277+ // 14. If nanosecond is not undefined, then
278+ if !nanosecond. is_undefined ( ) {
279+ // a. Set result.[[Nanosecond]] to ? ToIntegerWithTruncation(nanosecond).
280+ result. nanosecond = Some ( u16:: try_from ( to_integer_with_truncation ( agent, nanosecond. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u16:: MAX ) ) ;
281+ // b. Set any to true.
282+ any = true ;
283+ }
284+ // 15. Let second be ? Get(temporalTimeLike, "second").
285+ let second = get ( agent, item. get ( agent) , BUILTIN_STRING_MEMORY . second . to_property_key ( ) , gc. reborrow ( ) ) . unbind ( ) ?. bind ( gc. nogc ( ) ) ;
286+ // 16. If second is not undefined, then
287+ if !second. is_undefined ( ) {
288+ // a. Set result.[[Second]] to ? ToIntegerWithTruncation(second).
289+ result. second = Some ( u8:: try_from ( to_integer_with_truncation ( agent, second. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?) . unwrap_or ( u8:: MAX ) ) ;
290+ // b. Set any to true.
291+ any = true ;
292+ }
293+ // 17. If any is false, throw a TypeError exception.
294+ if !any {
295+ return Err ( agent. throw_exception_with_static_message (
296+ ExceptionType :: TypeError ,
297+ "TemporalTimeLike must have at least one time field" ,
298+ gc. into_nogc ( ) ,
299+ ) ) ;
300+ }
301+ // 18. Return result.
302+ Ok ( result)
303+ }
304+
305+ /// ### [4.5.17 DifferenceTemporalPlainTime ( operation, temporalTime, other, options )](https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalplaintime)
306+ /// The abstract operation DifferenceTemporalPlainTime takes arguments
307+ /// operation (either since or until), temporalTime (a Temporal.PlainTime),
308+ /// other (an ECMAScript language value), and options
309+ /// (an ECMAScript language value) and returns either
310+ /// a normal completion containing a Temporal.Duration or a
311+ /// throw completion. It computes the difference between the
312+ /// two times represented by temporalTime and other, optionally
313+ /// rounds it, and returns it as a Temporal.Duration object.
314+ pub ( super ) fn difference_temporal_plain_time < ' gc , const IS_UNTIL : bool > (
315+ agent : & mut Agent ,
316+ plain_time : TemporalPlainTime ,
317+ other : Value ,
318+ options : Value ,
319+ mut gc : GcScope < ' gc , ' _ > ,
320+ ) -> JsResult < ' gc , TemporalDuration < ' gc > > {
321+ let plain_time = plain_time. scope ( agent, gc. nogc ( ) ) ;
322+ let other = other. bind ( gc. nogc ( ) ) ;
323+ let options = options. scope ( agent, gc. nogc ( ) ) ;
324+ // 1. Set other to ? ToTemporalTime(other).
325+ let other = to_temporal_time ( agent, other. unbind ( ) , None , gc. reborrow ( ) )
326+ . unbind ( ) ?;
327+ // 2. Let resolvedOptions be ? GetOptionsObject(options).
328+ let resolved_option = get_options_object ( agent, options. get ( agent) , gc. nogc ( ) )
329+ . unbind ( ) ?
330+ . bind ( gc. nogc ( ) ) ;
331+ // 3. Let settings be ? GetDifferenceSettings(operation, resolvedOptions,
332+ // time, « », nanosecond, hour).
333+ // 4. Let timeDuration be
334+ // DifferenceTime(temporalTime.[[Time]], other.[[Time]]).
335+ // 5. Set timeDuration to ! RoundTimeDuration(timeDuration,
336+ // settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
337+ // 6. Let duration be
338+ // CombineDateAndTimeDuration(ZeroDateDuration(), timeDuration).
339+ // 7. Let result be !
340+ // TemporalDurationFromInternal(duration, settings.[[LargestUnit]]).
341+ // 8. If operation is since, set result to
342+ // CreateNegatedTemporalDuration(result).
343+ let duration = if IS_UNTIL {
344+ const UNTIL : bool = true ;
345+ let settings = get_difference_settings :: < UNTIL > (
346+ agent,
347+ resolved_option. unbind ( ) ,
348+ UnitGroup :: Time ,
349+ & [ ] ,
350+ Unit :: Nanosecond ,
351+ Unit :: Hour ,
352+ gc. reborrow ( ) ,
353+ )
354+ . unbind ( ) ?;
355+ temporal_rs:: PlainTime :: until (
356+ plain_time. get ( agent) . inner_plain_time ( agent) ,
357+ & other,
358+ settings,
359+ )
360+ } else {
361+ const SINCE : bool = false ;
362+ let settings = get_difference_settings :: < SINCE > (
363+ agent,
364+ resolved_option. unbind ( ) ,
365+ UnitGroup :: Time ,
366+ & [ ] ,
367+ Unit :: Nanosecond ,
368+ Unit :: Hour ,
369+ gc. reborrow ( ) ,
370+ )
371+ . unbind ( ) ?;
372+ temporal_rs:: PlainTime :: since (
373+ plain_time. get ( agent) . inner_plain_time ( agent) ,
374+ & other,
375+ settings,
376+ )
377+ } ;
378+ let gc = gc. into_nogc ( ) ;
379+ let duration = duration. map_err ( |err| temporal_err_to_js_err ( agent, err, gc) ) ?;
380+
381+ // 9. Return result.
382+ Ok ( agent. heap . create ( DurationRecord {
383+ object_index : None ,
384+ duration,
385+ } ) )
386+ }
0 commit comments