@@ -517,27 +517,58 @@ impl<'a> IdlType<'a> {
517
517
| IdlType :: Dictionary ( name)
518
518
| IdlType :: CallbackInterface { name, .. } => {
519
519
let ty = ident_ty ( rust_ident ( camel_case_ident ( name) . as_str ( ) ) ) ;
520
- if pos == TypePosition :: Argument {
521
- Some ( shared_ref ( ty, false ) )
522
- } else {
523
- Some ( ty)
524
- }
520
+ anyref ( ty)
525
521
} ,
526
522
IdlType :: Enum ( name) => Some ( ident_ty ( rust_ident ( camel_case_ident ( name) . as_str ( ) ) ) ) ,
527
523
528
- IdlType :: Nullable ( idl_type) => Some ( option_ty ( idl_type. to_syn_type ( pos) ?) ) ,
524
+ IdlType :: Nullable ( idl_type) => {
525
+ let inner = idl_type. to_syn_type ( pos) ?;
526
+
527
+ // TODO: this is a bit of a hack, but `Option<JsValue>` isn't
528
+ // supported right now. As a result if we see `JsValue` for our
529
+ // inner type, leave that as the same when we create a nullable
530
+ // version of that. That way `any?` just becomes `JsValue` and
531
+ // it's up to users to dispatch and/or create instances
532
+ // appropriately.
533
+ if let syn:: Type :: Path ( path) = & inner {
534
+ if path. qself . is_none ( ) &&
535
+ path. path . segments . last ( ) . map ( |p| p. value ( ) . ident == "JsValue" )
536
+ . unwrap_or ( false )
537
+ {
538
+ return Some ( inner. clone ( ) )
539
+ }
540
+ }
541
+
542
+ Some ( option_ty ( inner) )
543
+ }
529
544
IdlType :: FrozenArray ( _idl_type) => None ,
530
545
IdlType :: Sequence ( _idl_type) => None ,
531
546
IdlType :: Promise ( _idl_type) => js_sys ( "Promise" ) ,
532
547
IdlType :: Record ( _idl_type_from, _idl_type_to) => None ,
533
548
IdlType :: Union ( idl_types) => {
534
- // Handles union types in all places except operation argument types.
535
- // Currently treats them as object type, if possible.
536
- // TODO: add better support for union types here?
537
- // Approaches for it:
538
- // 1. Use strategy of finding the nearest common subclass (finding the best type
539
- // that is suitable for all values of this union)
540
- // 2. Generate enum with payload in Rust for each union type
549
+ // Note that most union types have already been expanded to
550
+ // their components via `flatten`. Unions in a return position
551
+ // or dictionary fields, however, haven't been flattened, which
552
+ // means we may need to conver them to a `syn` type.
553
+ //
554
+ // Currently this does a bit of a "poor man's" tree traversal by
555
+ // saying that if all union members are interfaces we can assume
556
+ // they've all got `Object` as a superclass, so we can take an
557
+ // object here. If any are not an interface though we
558
+ // pessimisitcally translate the union into a `JsValue`,
559
+ // absolutely anything. It's up to the application to figure out
560
+ // what to do with that.
561
+ //
562
+ // TODO: we should probably do a better job here translating
563
+ // unions to a single type. Two possible strategies could be:
564
+ //
565
+ // 1. Use strategy of finding the nearest common subclass
566
+ // (finding the best type that is suitable for all values of
567
+ // this union) instead of always assuming `Object`.
568
+ // 2. Generate enum with payload in Rust for each union type.
569
+ // Such an enum, however, might have a relatively high
570
+ // overhead in creating it from a JS value, but would be
571
+ // cheap to convert from a variant back to a JS value.
541
572
if idl_types
542
573
. iter ( )
543
574
. all ( |idl_type|
@@ -548,7 +579,7 @@ impl<'a> IdlType<'a> {
548
579
) {
549
580
IdlType :: Object . to_syn_type ( pos)
550
581
} else {
551
- None
582
+ IdlType :: Any . to_syn_type ( pos )
552
583
}
553
584
} ,
554
585
0 commit comments