@@ -9,13 +9,20 @@ mod plain_time_prototype;
99pub ( crate ) use data:: * ;
1010pub ( crate ) use plain_time_constructor:: * ;
1111pub ( crate ) use plain_time_prototype:: * ;
12+ use sonic_rs:: { Object , value:: object:: IterMut } ;
13+ use temporal_rs:: {
14+ duration,
15+ options:: { Unit , UnitGroup } ,
16+ } ;
1217
1318use crate :: {
1419 ecmascript:: {
15- Agent , ExceptionType , Function , InternalMethods , InternalSlots , JsResult , OrdinaryObject ,
16- ProtoIntrinsics , Value , object_handle, ordinary_populate_from_constructor,
20+ Agent , DurationRecord , ExceptionType , Function , InternalMethods , InternalSlots , JsResult ,
21+ Object , OrdinaryObject , ProtoIntrinsics , String , TemporalDuration , Value ,
22+ get_difference_settings, get_options_object, object_handle,
23+ ordinary_populate_from_constructor, temporal_err_to_js_err,
1724 } ,
18- engine:: { Bindable , GcScope , NoGcScope } ,
25+ engine:: { Bindable , GcScope , NoGcScope , Scopable } ,
1926 heap:: {
2027 ArenaAccess , ArenaAccessMut , BaseIndex , CompactionLists , CreateHeapData , Heap ,
2128 HeapMarkAndSweep , HeapSweepWeakReference , WorkQueues , arena_vec_access,
@@ -133,3 +140,162 @@ pub(crate) fn create_temporal_plain_time<'gc>(
133140 . unwrap ( ) ,
134141 )
135142}
143+
144+ /// ### [4.5.6 ToTemporalTime ( item [ , options ] )](https://tc39.es/proposal-temporal/#sec-temporal-totemporaltime)
145+ ///
146+ /// The abstract operation ToTemporalTime takes argument item (an ECMAScript language value) and optional argument
147+ /// options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime
148+ /// or a throw Completion. Converts item to a new Temporal.PlainTime instance if possible, and throws otherwise.
149+ pub ( crate ) fn to_temporal_time < ' gc > (
150+ agent : & mut Agent ,
151+ item : Value ,
152+ options : Option < Value > ,
153+ mut gc : GcScope < ' gc , ' _ > ,
154+ ) -> JsResult < ' gc , temporal_rs:: PlainTime > {
155+ let item = item. bind ( gc. nogc ( ) ) ;
156+
157+ // 1. If options is not present, set options to undefined.
158+ let options = options. unwrap_or ( Value :: Undefined ) ;
159+
160+ // 2. If item is an Object, then
161+ if let Ok ( item) = Object :: try_from ( item) {
162+ // a. If item has an [[InitializedTemporalTime]] internal slot, then
163+ if let Ok ( time) = TemporalPlainTime :: try_from ( item) {
164+ // i. Let resolvedOptions be ? GetOptionsObject(options).
165+ let resolved_options = get_options_object ( agent, options, gc. nogc ( ) ) . unbind ( ) ?;
166+ // ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
167+ get_temporal_overflow_option ( agent, resolved_options, gc. reborrow ( ) ) . unbind ( ) ?;
168+ // iii. Return ! CreateTemporalTime(item.[[Time]]).
169+ return Ok ( * time. inner_plain_time ( agent) ) ;
170+ }
171+
172+ // b. If item has an [[InitializedTemporalDateTime]] internal slot, then
173+ // i. Let resolvedOptions be ? GetOptionsObject(options).
174+ // ii. Perform ? GetTemporalOverflowOption(resolvedOptions).
175+ // iii. Return ! CreateTemporalTime(item.[[ISODateTime]].[[Time]]).
176+
177+ // c. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
178+ // i. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[EpochNanoseconds]]).
179+ // ii. Let resolvedOptions be ? GetOptionsObject(options).
180+ // iii. Perform ? GetTemporalOverflowOption(resolvedOptions).
181+ // iv. Return ! CreateTemporalTime(isoDateTime.[[Time]]).
182+
183+ // d. Let result be ? ToTemporalTimeRecord(item).
184+ let result = to_temporal_time_record ( agent, item. unbind ( ) , gc. reborrow ( ) ) . unbind ( ) ?;
185+ // e. Let resolvedOptions be ? GetOptionsObject(options).
186+ let resolved_options = get_options_object ( agent, options, gc. nogc ( ) ) . unbind ( ) ?;
187+ // f. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
188+ let overflow =
189+ get_temporal_overflow_option ( agent, resolved_options, gc. reborrow ( ) ) . unbind ( ) ?;
190+ // g. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], overflow).
191+ return result
192+ . regulate ( overflow)
193+ . map_err ( |err| temporal_err_to_js_err ( agent, err, gc. into_nogc ( ) ) ) ;
194+ }
195+
196+ // 3. Else,
197+ // a. If item is not a String, throw a TypeError exception.
198+ let Ok ( item) = String :: try_from ( item) else {
199+ return Err ( agent. throw_exception_with_static_message (
200+ ExceptionType :: TypeError ,
201+ "Item is not a String" ,
202+ gc. into_nogc ( ) ,
203+ ) ) ;
204+ } ;
205+
206+ // b. Let parseResult be ? ParseISODateTime(item, « TemporalTimeString »).
207+ // c. Assert: parseResult.[[Time]] is not start-of-day.
208+ // d. Set result to parseResult.[[Time]].
209+ // 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.
210+ let result = temporal_rs:: PlainTime :: from_utf8 ( item. as_bytes ( agent) )
211+ . map_err ( |err| temporal_err_to_js_err ( agent, err, gc. into_nogc ( ) ) ) ?;
212+ // f. Let resolvedOptions be ? GetOptionsObject(options).
213+ let resolved_options = get_options_object ( agent, options, gc. reborrow ( ) ) . unbind ( ) ?;
214+ // g. Perform ? GetTemporalOverflowOption(resolvedOptions).
215+ get_temporal_overflow_option ( agent, resolved_options, gc. reborrow ( ) ) . unbind ( ) ?;
216+
217+ // 4. Return ! CreateTemporalTime(result).
218+ Ok ( result)
219+ }
220+
221+ /// ### [4.5.17 DifferenceTemporalPlainTime ( operation, temporalTime, other, options )](https://tc39.es/proposal-temporal/#sec-temporal-differencetemporalplaintime)
222+ /// The abstract operation DifferenceTemporalPlainTime takes arguments
223+ /// operation (either since or until), temporalTime (a Temporal.PlainTime),
224+ /// other (an ECMAScript language value), and options
225+ /// (an ECMAScript language value) and returns either
226+ /// a normal completion containing a Temporal.Duration or a
227+ /// throw completion. It computes the difference between the
228+ /// two times represented by temporalTime and other, optionally
229+ /// rounds it, and returns it as a Temporal.Duration object.
230+ fn difference_temporal_plain_time < ' gc , const IS_UNTIL : bool > (
231+ agent : & mut Agent ,
232+ plain_time : TemporalPlainTime ,
233+ other : Value ,
234+ options : Value ,
235+ mut gc : GcScope < ' gc , ' _ > ,
236+ ) -> JsResult < ' gc , TemporalDuration < ' gc > > {
237+ let plain_time = plain_time. scope ( agent, gc. nogc ( ) ) ;
238+ let other = other. bind ( gc. nogc ( ) ) ;
239+ let options = options. scope ( agent, gc. nogc ( ) ) ;
240+ // 1. Set other to ? ToTemporalTime(other).
241+ let other = to_temporal_time ( agent, other. unbind ( ) , options, gc. reborrow ( ) ) ;
242+ // 2. Let resolvedOptions be ? GetOptionsObject(options).
243+ let resolved_option = get_options_object ( agent, options. get ( agent) , gc. nogc ( ) )
244+ . unbind ( ) ?
245+ . bind ( gc. nogc ( ) ) ;
246+ // 3. Let settings be ? GetDifferenceSettings(operation, resolvedOptions,
247+ // time, « », nanosecond, hour).
248+ // 4. Let timeDuration be
249+ // DifferenceTime(temporalTime.[[Time]], other.[[Time]]).
250+ // 5. Set timeDuration to ! RoundTimeDuration(timeDuration,
251+ // settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
252+ // 6. Let duration be
253+ // CombineDateAndTimeDuration(ZeroDateDuration(), timeDuration).
254+ // 7. Let result be !
255+ // TemporalDurationFromInternal(duration, settings.[[LargestUnit]]).
256+ // 8. If operation is since, set result to
257+ // CreateNegatedTemporalDuration(result).
258+ let duration = if IS_UNTIL {
259+ const UNTIL : bool = true ;
260+ let settings = get_difference_settings :: < UNTIL > (
261+ agent,
262+ resolved_option. unbind ( ) ,
263+ UnitGroup :: Time ,
264+ & [ ] ,
265+ Unit :: Nanosecond ,
266+ Unit :: Hour ,
267+ gc. reborrow ( ) ,
268+ )
269+ . unbind ( ) ?;
270+ temporal_rs:: PlainTime :: until (
271+ plain_time. get ( agent) . inner_plain_time ( agent) ,
272+ & other. unbind ( ) ?,
273+ settings,
274+ )
275+ } else {
276+ const SINCE : bool = false ;
277+ let settings = get_difference_settings :: < SINCE > (
278+ agent,
279+ resolved_option. unbind ( ) ,
280+ UnitGroup :: Time ,
281+ & [ ] ,
282+ Unit :: Nanosecond ,
283+ Unit :: Hour ,
284+ gc. reborrow ( ) ,
285+ )
286+ . unbind ( ) ?;
287+ temporal_rs:: PlainTime :: since (
288+ plain_time. get ( agent) . inner_plain_time ( agent) ,
289+ & other. unbind ( ) ?,
290+ settings,
291+ )
292+ } ;
293+ let gc = gc. into_nogc ( ) ;
294+ let duration = duration. map_err ( |err| temporal_err_to_js_err ( agent, err, gc) ) ?;
295+
296+ // 9. Return result.
297+ Ok ( agent. heap . create ( DurationRecord {
298+ object_index : None ,
299+ duration,
300+ } ) )
301+ }
0 commit comments