@@ -166,6 +166,7 @@ impl C {
166166 Type :: Id ( id) => match & iface. types [ * id] . kind {
167167 TypeDefKind :: Type ( t) => self . is_arg_by_pointer ( iface, t) ,
168168 TypeDefKind :: Variant ( _) => true ,
169+ TypeDefKind :: Union ( _) => true ,
169170 TypeDefKind :: Option ( _) => true ,
170171 TypeDefKind :: Expected ( _) => true ,
171172 TypeDefKind :: Enum ( _) => false ,
@@ -285,7 +286,8 @@ impl C {
285286 TypeDefKind :: Record ( _)
286287 | TypeDefKind :: Flags ( _)
287288 | TypeDefKind :: Enum ( _)
288- | TypeDefKind :: Variant ( _) => {
289+ | TypeDefKind :: Variant ( _)
290+ | TypeDefKind :: Union ( _) => {
289291 unimplemented ! ( )
290292 }
291293 TypeDefKind :: Tuple ( t) => {
@@ -324,7 +326,8 @@ impl C {
324326 | TypeDefKind :: Flags ( _)
325327 | TypeDefKind :: Record ( _)
326328 | TypeDefKind :: Enum ( _)
327- | TypeDefKind :: Variant ( _) => {
329+ | TypeDefKind :: Variant ( _)
330+ | TypeDefKind :: Union ( _) => {
328331 unreachable ! ( )
329332 }
330333 TypeDefKind :: Tuple ( t) => {
@@ -493,14 +496,29 @@ impl C {
493496 continue ;
494497 }
495498 self . src . c ( & format ! ( "case {}: {{\n " , i) ) ;
496- let expr = format ! ( "&ptr->val.{}" , case_field_name ( case) ) ;
499+ let expr = format ! ( "&ptr->val.{}" , case. name . to_snake_case ( ) ) ;
497500 self . free ( iface, case_ty, & expr) ;
498501 self . src . c ( "break;\n " ) ;
499502 self . src . c ( "}\n " ) ;
500503 }
501504 self . src . c ( "}\n " ) ;
502505 }
503506
507+ TypeDefKind :: Union ( u) => {
508+ self . src . c ( "switch ((int32_t) ptr->tag) {\n " ) ;
509+ for ( i, case) in u. cases . iter ( ) . enumerate ( ) {
510+ if !self . owns_anything ( iface, & case. ty ) {
511+ continue ;
512+ }
513+ self . src . c ( & format ! ( "case {i}: {{\n " ) ) ;
514+ let expr = format ! ( "&ptr->val.f{i}" ) ;
515+ self . free ( iface, & case. ty , & expr) ;
516+ self . src . c ( "break;\n " ) ;
517+ self . src . c ( "}\n " ) ;
518+ }
519+ self . src . c ( "}\n " ) ;
520+ }
521+
504522 TypeDefKind :: Option ( t) => {
505523 self . src . c ( "if (ptr->is_some) {\n " ) ;
506524 self . free ( iface, t, "&ptr->val" ) ;
@@ -541,6 +559,10 @@ impl C {
541559 . iter ( )
542560 . filter_map ( |c| c. ty . as_ref ( ) )
543561 . any ( |t| self . owns_anything ( iface, t) ) ,
562+ TypeDefKind :: Union ( v) => v
563+ . cases
564+ . iter ( )
565+ . any ( |case| self . owns_anything ( iface, & case. ty ) ) ,
544566 TypeDefKind :: Option ( t) => self . owns_anything ( iface, t) ,
545567 TypeDefKind :: Expected ( e) => {
546568 self . owns_anything ( iface, & e. ok ) || self . owns_anything ( iface, & e. err )
@@ -642,7 +664,7 @@ impl Return {
642664 self . retptrs . push ( * orig_ty) ;
643665 }
644666
645- TypeDefKind :: Variant ( _) => {
667+ TypeDefKind :: Variant ( _) | TypeDefKind :: Union ( _ ) => {
646668 self . retptrs . push ( * orig_ty) ;
647669 }
648670 }
@@ -778,7 +800,7 @@ impl Generator for C {
778800 if let Some ( ty) = & case. ty {
779801 self . print_ty ( iface, ty) ;
780802 self . src . h ( " " ) ;
781- self . src . h ( & case_field_name ( case) ) ;
803+ self . src . h ( & case. name . to_snake_case ( ) ) ;
782804 self . src . h ( ";\n " ) ;
783805 }
784806 }
@@ -801,6 +823,35 @@ impl Generator for C {
801823 . insert ( id, mem:: replace ( & mut self . src . header , prev) ) ;
802824 }
803825
826+ fn type_union (
827+ & mut self ,
828+ iface : & Interface ,
829+ id : TypeId ,
830+ name : & str ,
831+ union : & Union ,
832+ docs : & Docs ,
833+ ) {
834+ let prev = mem:: take ( & mut self . src . header ) ;
835+ self . docs ( docs) ;
836+ self . names . insert ( & name. to_snake_case ( ) ) . unwrap ( ) ;
837+ self . src . h ( "typedef struct {\n " ) ;
838+ self . src . h ( int_repr ( union. tag ( ) ) ) ;
839+ self . src . h ( " tag;\n " ) ;
840+ self . src . h ( "union {\n " ) ;
841+ for ( i, case) in union. cases . iter ( ) . enumerate ( ) {
842+ self . print_ty ( iface, & case. ty ) ;
843+ self . src . h ( & format ! ( " f{i};\n " ) ) ;
844+ }
845+ self . src . h ( "} val;\n " ) ;
846+ self . src . h ( "} " ) ;
847+ self . print_namespace ( iface) ;
848+ self . src . h ( & name. to_snake_case ( ) ) ;
849+ self . src . h ( "_t;\n " ) ;
850+
851+ self . types
852+ . insert ( id, mem:: replace ( & mut self . src . header , prev) ) ;
853+ }
854+
804855 fn type_option (
805856 & mut self ,
806857 iface : & Interface ,
@@ -1594,7 +1645,7 @@ impl Bindgen for FunctionBindgen<'_> {
15941645 ty, payload, operands[ 0 ] ,
15951646 ) ) ;
15961647 self . src . push_str ( "." ) ;
1597- self . src . push_str ( & case_field_name ( case) ) ;
1648+ self . src . push_str ( & case. name . to_snake_case ( ) ) ;
15981649 self . src . push_str ( ";\n " ) ;
15991650 }
16001651 }
@@ -1631,7 +1682,7 @@ impl Bindgen for FunctionBindgen<'_> {
16311682 assert ! ( block_results. len( ) == 1 ) ;
16321683 let mut dst = format ! ( "{}.val" , result) ;
16331684 dst. push_str ( "." ) ;
1634- dst. push_str ( & case_field_name ( case) ) ;
1685+ dst. push_str ( & case. name . to_snake_case ( ) ) ;
16351686 self . store_op ( & block_results[ 0 ] , & dst) ;
16361687 } else {
16371688 assert ! ( block_results. is_empty( ) ) ;
@@ -1642,6 +1693,78 @@ impl Bindgen for FunctionBindgen<'_> {
16421693 results. push ( result) ;
16431694 }
16441695
1696+ Instruction :: UnionLower {
1697+ union,
1698+ results : result_types,
1699+ ..
1700+ } => {
1701+ let blocks = self
1702+ . blocks
1703+ . drain ( self . blocks . len ( ) - union. cases . len ( ) ..)
1704+ . collect :: < Vec < _ > > ( ) ;
1705+ let payloads = self
1706+ . payloads
1707+ . drain ( self . payloads . len ( ) - union. cases . len ( ) ..)
1708+ . collect :: < Vec < _ > > ( ) ;
1709+
1710+ let mut union_results = Vec :: with_capacity ( result_types. len ( ) ) ;
1711+ for ty in result_types. iter ( ) {
1712+ let name = self . locals . tmp ( "unionres" ) ;
1713+ results. push ( name. clone ( ) ) ;
1714+ let ty = wasm_type ( * ty) ;
1715+ self . src . push_str ( & format ! ( "{ty} {name};\n " ) ) ;
1716+ union_results. push ( name) ;
1717+ }
1718+
1719+ let op0 = & operands[ 0 ] ;
1720+ self . src . push_str ( & format ! ( "switch (({op0}).tag) {{\n " ) ) ;
1721+ for ( i, ( ( case, ( block, block_results) ) , payload) ) in
1722+ union. cases . iter ( ) . zip ( blocks) . zip ( payloads) . enumerate ( )
1723+ {
1724+ self . src . push_str ( & format ! ( "case {i}: {{\n " ) ) ;
1725+ if !self . gen . is_empty_type ( iface, & case. ty ) {
1726+ let ty = self . gen . type_string ( iface, & case. ty ) ;
1727+ self . src
1728+ . push_str ( & format ! ( "const {ty} *{payload} = &({op0}).val.f{i};\n " ) ) ;
1729+ }
1730+ self . src . push_str ( & block) ;
1731+
1732+ for ( name, result) in union_results. iter ( ) . zip ( & block_results) {
1733+ self . src . push_str ( & format ! ( "{name} = {result};\n " ) ) ;
1734+ }
1735+ self . src . push_str ( "break;\n }\n " ) ;
1736+ }
1737+ self . src . push_str ( "}\n " ) ;
1738+ }
1739+
1740+ Instruction :: UnionLift { union, ty, .. } => {
1741+ let blocks = self
1742+ . blocks
1743+ . drain ( self . blocks . len ( ) - union. cases . len ( ) ..)
1744+ . collect :: < Vec < _ > > ( ) ;
1745+
1746+ let ty = self . gen . type_string ( iface, & Type :: Id ( * ty) ) ;
1747+ let result = self . locals . tmp ( "unionres" ) ;
1748+ self . src . push_str ( & format ! ( "{} {};\n " , ty, result) ) ;
1749+ self . src
1750+ . push_str ( & format ! ( "{}.tag = {};\n " , result, operands[ 0 ] ) ) ;
1751+ self . src
1752+ . push_str ( & format ! ( "switch ((int32_t) {}.tag) {{\n " , result) ) ;
1753+ for ( i, ( _case, ( block, block_results) ) ) in
1754+ union. cases . iter ( ) . zip ( blocks) . enumerate ( )
1755+ {
1756+ self . src . push_str ( & format ! ( "case {i}: {{\n " ) ) ;
1757+ self . src . push_str ( & block) ;
1758+
1759+ assert ! ( block_results. len( ) == 1 ) ;
1760+ let dst = format ! ( "{result}.val.f{i}" ) ;
1761+ self . store_op ( & block_results[ 0 ] , & dst) ;
1762+ self . src . push_str ( "break;\n }\n " ) ;
1763+ }
1764+ self . src . push_str ( "}\n " ) ;
1765+ results. push ( result) ;
1766+ }
1767+
16451768 Instruction :: OptionLower {
16461769 results : result_types,
16471770 payload,
@@ -2110,14 +2233,6 @@ fn int_repr(ty: Int) -> &'static str {
21102233 }
21112234}
21122235
2113- fn case_field_name ( case : & Case ) -> String {
2114- if case. name . parse :: < u32 > ( ) . is_ok ( ) {
2115- format ! ( "f{}" , case. name)
2116- } else {
2117- case. name . to_snake_case ( )
2118- }
2119- }
2120-
21212236fn flags_repr ( f : & Flags ) -> Int {
21222237 match f. repr ( ) {
21232238 FlagsRepr :: U8 => Int :: U8 ,
0 commit comments