@@ -521,19 +521,54 @@ impl<'a> IdlType<'a> {
521
521
} ,
522
522
IdlType :: Enum ( name) => Some ( ident_ty ( rust_ident ( camel_case_ident ( name) . as_str ( ) ) ) ) ,
523
523
524
- 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
+ }
525
544
IdlType :: FrozenArray ( _idl_type) => None ,
526
545
IdlType :: Sequence ( _idl_type) => None ,
527
546
IdlType :: Promise ( _idl_type) => js_sys ( "Promise" ) ,
528
547
IdlType :: Record ( _idl_type_from, _idl_type_to) => None ,
529
548
IdlType :: Union ( idl_types) => {
530
- // Handles union types in all places except operation argument types.
531
- // Currently treats them as object type, if possible.
532
- // TODO: add better support for union types here?
533
- // Approaches for it:
534
- // 1. Use strategy of finding the nearest common subclass (finding the best type
535
- // that is suitable for all values of this union)
536
- // 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.
537
572
if idl_types
538
573
. iter ( )
539
574
. all ( |idl_type|
@@ -544,7 +579,7 @@ impl<'a> IdlType<'a> {
544
579
) {
545
580
IdlType :: Object . to_syn_type ( pos)
546
581
} else {
547
- None
582
+ IdlType :: Any . to_syn_type ( pos )
548
583
}
549
584
} ,
550
585
0 commit comments