@@ -336,16 +336,15 @@ impl JsValue {
336336 #[ allow( clippy:: float_cmp) ]
337337 pub fn as_i32 ( & self ) -> Option < i32 > {
338338 if let Some ( integer) = self . 0 . as_integer32 ( ) {
339- Some ( integer)
340- } else if let Some ( rational) = self . 0 . as_float64 ( ) {
341- if rational == f64:: from ( rational as i32 ) {
342- Some ( rational as i32 )
343- } else {
344- None
345- }
346- } else {
347- None
339+ return Some ( integer) ;
340+ }
341+
342+ if let Some ( rational) = self . 0 . as_float64 ( )
343+ && rational == f64:: from ( rational as i32 )
344+ {
345+ return Some ( rational as i32 ) ;
348346 }
347+ None
349348 }
350349
351350 /// Returns true if the value is a number.
@@ -431,52 +430,16 @@ impl JsValue {
431430 /// `PreferredType`.
432431 ///
433432 /// <https://tc39.es/ecma262/#sec-toprimitive>
433+ #[ inline]
434434 pub fn to_primitive (
435435 & self ,
436436 context : & mut Context ,
437437 preferred_type : PreferredType ,
438438 ) -> JsResult < Self > {
439439 // 1. Assert: input is an ECMAScript language value. (always a value not need to check)
440440 // 2. If Type(input) is Object, then
441- if let Some ( input) = self . as_object ( ) {
442- // a. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
443- let exotic_to_prim = input. get_method ( JsSymbol :: to_primitive ( ) , context) ?;
444-
445- // b. If exoticToPrim is not undefined, then
446- if let Some ( exotic_to_prim) = exotic_to_prim {
447- // i. If preferredType is not present, let hint be "default".
448- // ii. Else if preferredType is string, let hint be "string".
449- // iii. Else,
450- // 1. Assert: preferredType is number.
451- // 2. Let hint be "number".
452- let hint = match preferred_type {
453- PreferredType :: Default => js_string ! ( "default" ) ,
454- PreferredType :: String => js_string ! ( "string" ) ,
455- PreferredType :: Number => js_string ! ( "number" ) ,
456- }
457- . into ( ) ;
458-
459- // iv. Let result be ? Call(exoticToPrim, input, « hint »).
460- let result = exotic_to_prim. call ( self , & [ hint] , context) ?;
461- // v. If Type(result) is not Object, return result.
462- // vi. Throw a TypeError exception.
463- return if result. is_object ( ) {
464- Err ( JsNativeError :: typ ( )
465- . with_message ( "Symbol.toPrimitive cannot return an object" )
466- . into ( ) )
467- } else {
468- Ok ( result)
469- } ;
470- }
471-
472- // c. If preferredType is not present, let preferredType be number.
473- let preferred_type = match preferred_type {
474- PreferredType :: Default | PreferredType :: Number => PreferredType :: Number ,
475- PreferredType :: String => PreferredType :: String ,
476- } ;
477-
478- // d. Return ? OrdinaryToPrimitive(input, preferredType).
479- return input. ordinary_to_primitive ( context, preferred_type) ;
441+ if let Some ( o) = self . as_object ( ) {
442+ return o. to_primitive ( context, preferred_type) ;
480443 }
481444
482445 // 3. Return input.
@@ -513,11 +476,10 @@ impl JsValue {
513476 JsVariant :: Integer32 ( _) | JsVariant :: Float64 ( _) => Err ( JsNativeError :: typ ( )
514477 . with_message ( "cannot convert Number to a BigInt" )
515478 . into ( ) ) ,
516- JsVariant :: BigInt ( b) => Ok ( b. clone ( ) ) ,
517- JsVariant :: Object ( _) => {
518- let primitive = self . to_primitive ( context, PreferredType :: Number ) ?;
519- primitive. to_bigint ( context)
520- }
479+ JsVariant :: BigInt ( b) => Ok ( b) ,
480+ JsVariant :: Object ( o) => o
481+ . to_primitive ( context, PreferredType :: Number ) ?
482+ . to_bigint ( context) ,
521483 JsVariant :: Symbol ( _) => Err ( JsNativeError :: typ ( )
522484 . with_message ( "cannot convert Symbol to a BigInt" )
523485 . into ( ) ) ,
@@ -558,15 +520,14 @@ impl JsValue {
558520 JsVariant :: Boolean ( false ) => Ok ( js_string ! ( "false" ) ) ,
559521 JsVariant :: Float64 ( rational) => Ok ( JsString :: from ( rational) ) ,
560522 JsVariant :: Integer32 ( integer) => Ok ( JsString :: from ( integer) ) ,
561- JsVariant :: String ( string) => Ok ( string. clone ( ) ) ,
523+ JsVariant :: String ( string) => Ok ( string) ,
562524 JsVariant :: Symbol ( _) => Err ( JsNativeError :: typ ( )
563525 . with_message ( "can't convert symbol to string" )
564526 . into ( ) ) ,
565527 JsVariant :: BigInt ( bigint) => Ok ( bigint. to_string ( ) . into ( ) ) ,
566- JsVariant :: Object ( _) => {
567- let primitive = self . to_primitive ( context, PreferredType :: String ) ?;
568- primitive. to_string ( context)
569- }
528+ JsVariant :: Object ( o) => o
529+ . to_primitive ( context, PreferredType :: String ) ?
530+ . to_string ( context) ,
570531 }
571532 }
572533
@@ -595,22 +556,25 @@ impl JsValue {
595556 . templates ( )
596557 . number ( )
597558 . create ( rational, Vec :: default ( ) ) ) ,
598- JsVariant :: String ( string) => Ok ( context
599- . intrinsics ( )
600- . templates ( )
601- . string ( )
602- . create ( string. clone ( ) , vec ! [ string. len( ) . into( ) ] ) ) ,
559+ JsVariant :: String ( string) => {
560+ let len = string. len ( ) ;
561+ Ok ( context
562+ . intrinsics ( )
563+ . templates ( )
564+ . string ( )
565+ . create ( string, vec ! [ len. into( ) ] ) )
566+ }
603567 JsVariant :: Symbol ( symbol) => Ok ( context
604568 . intrinsics ( )
605569 . templates ( )
606570 . symbol ( )
607- . create ( symbol. clone ( ) , Vec :: default ( ) ) ) ,
571+ . create ( symbol, Vec :: default ( ) ) ) ,
608572 JsVariant :: BigInt ( bigint) => Ok ( context
609573 . intrinsics ( )
610574 . templates ( )
611575 . bigint ( )
612- . create ( bigint. clone ( ) , Vec :: default ( ) ) ) ,
613- JsVariant :: Object ( jsobject) => Ok ( jsobject. clone ( ) ) ,
576+ . create ( bigint, Vec :: default ( ) ) ) ,
577+ JsVariant :: Object ( jsobject) => Ok ( jsobject) ,
614578 }
615579 }
616580
@@ -635,23 +599,32 @@ impl JsValue {
635599 ///
636600 /// See <https://tc39.es/ecma262/#sec-topropertykey>
637601 pub fn to_property_key ( & self , context : & mut Context ) -> JsResult < PropertyKey > {
638- Ok ( match self . variant ( ) {
639- // Fast path:
640- JsVariant :: String ( string) => string. clone ( ) . into ( ) ,
641- JsVariant :: Symbol ( symbol) => symbol. clone ( ) . into ( ) ,
642- JsVariant :: Integer32 ( integer) => integer. into ( ) ,
643- // Slow path:
644- JsVariant :: Object ( _) => {
645- let primitive = self . to_primitive ( context, PreferredType :: String ) ?;
646- match primitive. variant ( ) {
647- JsVariant :: String ( string) => string. clone ( ) . into ( ) ,
648- JsVariant :: Symbol ( symbol) => symbol. clone ( ) . into ( ) ,
649- JsVariant :: Integer32 ( integer) => integer. into ( ) ,
650- _ => primitive. to_string ( context) ?. into ( ) ,
651- }
652- }
653- _ => self . to_string ( context) ?. into ( ) ,
654- } )
602+ match self . variant ( ) {
603+ // fast path
604+ //
605+ // The compiler will surely make this a jump table, but in case it
606+ // doesn't, we put the "expected" property key types first
607+ // (integer, string, symbol), then the rest of the variants.
608+ JsVariant :: Integer32 ( integer) => Ok ( integer. into ( ) ) ,
609+ JsVariant :: String ( string) => Ok ( string. into ( ) ) ,
610+ JsVariant :: Symbol ( symbol) => Ok ( symbol. into ( ) ) ,
611+
612+ // We also inline the call to `to_string`, removing the
613+ // double match against `self.variant()`.
614+ JsVariant :: Float64 ( float) => Ok ( JsString :: from ( float) . into ( ) ) ,
615+ JsVariant :: Undefined => Ok ( js_string ! ( "undefined" ) . into ( ) ) ,
616+ JsVariant :: Null => Ok ( js_string ! ( "null" ) . into ( ) ) ,
617+ JsVariant :: Boolean ( true ) => Ok ( js_string ! ( "true" ) . into ( ) ) ,
618+ JsVariant :: Boolean ( false ) => Ok ( js_string ! ( "false" ) . into ( ) ) ,
619+ JsVariant :: BigInt ( bigint) => Ok ( JsString :: from ( bigint. to_string ( ) ) . into ( ) ) ,
620+
621+ // slow path
622+ // Cannot infinitely recurse since it is guaranteed that `to_primitive` returns a non-object
623+ // value or errors.
624+ JsVariant :: Object ( o) => o
625+ . to_primitive ( context, PreferredType :: String ) ?
626+ . to_property_key ( context) ,
627+ }
655628 }
656629
657630 /// It returns value converted to a numeric value of type `Number` or `BigInt`.
@@ -663,7 +636,7 @@ impl JsValue {
663636
664637 // 2. If primValue is a BigInt, return primValue.
665638 if let Some ( bigint) = primitive. as_bigint ( ) {
666- return Ok ( bigint. clone ( ) . into ( ) ) ;
639+ return Ok ( bigint. into ( ) ) ;
667640 }
668641
669642 // 3. Return ? ToNumber(primValue).
0 commit comments