@@ -1099,7 +1099,7 @@ fn is_prim_type_id(resolve: &Resolve, id: TypeId) -> bool {
10991099 | TypeDefKind :: Stream ( _)
11001100 | TypeDefKind :: Unknown => false ,
11011101 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
1102- TypeDefKind :: Map ( .. ) => todo ! ( ) ,
1102+ TypeDefKind :: Map ( key , value ) => is_prim_type ( resolve , key ) && is_prim_type ( resolve , value ) ,
11031103 }
11041104}
11051105
@@ -1185,7 +1185,12 @@ pub fn push_ty_name(resolve: &Resolve, ty: &Type, src: &mut String) {
11851185 }
11861186 TypeDefKind :: Unknown => unreachable ! ( ) ,
11871187 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
1188- TypeDefKind :: Map ( ..) => todo ! ( ) ,
1188+ TypeDefKind :: Map ( key, value) => {
1189+ src. push_str ( "map_" ) ;
1190+ push_ty_name ( resolve, key, src) ;
1191+ src. push_str ( "_" ) ;
1192+ push_ty_name ( resolve, value, src) ;
1193+ }
11891194 }
11901195 }
11911196 }
@@ -1394,12 +1399,12 @@ impl Return {
13941399 TypeDefKind :: Tuple ( _)
13951400 | TypeDefKind :: Record ( _)
13961401 | TypeDefKind :: List ( _)
1402+ | TypeDefKind :: Map ( ..)
13971403 | TypeDefKind :: Variant ( _) => { }
13981404
13991405 TypeDefKind :: Resource => todo ! ( "return_single for resource" ) ,
14001406 TypeDefKind :: Unknown => unreachable ! ( ) ,
14011407 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
1402- TypeDefKind :: Map ( ..) => todo ! ( ) ,
14031408 }
14041409
14051410 self . retptrs . push ( * orig_ty) ;
@@ -1757,8 +1762,15 @@ void __wasm_export_{ns}_{snake}_dtor({ns}_{snake}_t* arg) {{
17571762 todo ! ( "named fixed-length list types are not yet supported in the C backend" )
17581763 }
17591764
1760- fn type_map ( & mut self , _id : TypeId , _name : & str , _key : & Type , _value : & Type , _docs : & Docs ) {
1761- todo ! ( "map types are not yet supported in the C backend" )
1765+ fn type_map ( & mut self , id : TypeId , _name : & str , key : & Type , value : & Type , docs : & Docs ) {
1766+ self . src . h_defs ( "\n " ) ;
1767+ self . docs ( docs, SourceType :: HDefs ) ;
1768+ self . print_map_entry_typedef ( id, key, value) ;
1769+ self . start_typedef_struct ( id) ;
1770+ self . print_map_entry_typename ( id) ;
1771+ self . src . h_defs ( " *ptr;\n " ) ;
1772+ self . src . h_defs ( "size_t len;\n " ) ;
1773+ self . finish_typedef_struct ( id) ;
17621774 }
17631775
17641776 fn type_future ( & mut self , id : TypeId , _name : & str , _ty : & Option < Type > , docs : & Docs ) {
@@ -1883,8 +1895,16 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a>
18831895 todo ! ( "print_anonymous_type for fixed length list" ) ;
18841896 }
18851897
1886- fn anonymous_type_map ( & mut self , _id : TypeId , _key : & Type , _value : & Type , _docs : & Docs ) {
1887- todo ! ( "anonymous map types are not yet supported in the C backend" ) ;
1898+ fn anonymous_type_map ( & mut self , id : TypeId , key : & Type , value : & Type , _docs : & Docs ) {
1899+ self . print_map_entry_typedef ( id, key, value) ;
1900+ self . src . h_defs ( "\n typedef " ) ;
1901+ self . src . h_defs ( "struct {\n " ) ;
1902+ self . print_map_entry_typename ( id) ;
1903+ self . src . h_defs ( " *ptr;\n " ) ;
1904+ self . src . h_defs ( "size_t len;\n " ) ;
1905+ self . src . h_defs ( "}" ) ;
1906+ self . src . h_defs ( " " ) ;
1907+ self . print_typedef_target ( id) ;
18881908 }
18891909}
18901910
@@ -2064,7 +2084,19 @@ impl InterfaceGenerator<'_> {
20642084 }
20652085 TypeDefKind :: Unknown => unreachable ! ( ) ,
20662086 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
2067- TypeDefKind :: Map ( ..) => todo ! ( ) ,
2087+ TypeDefKind :: Map ( key, value) => {
2088+ let entry_name = self . map_entry_typename ( id) ;
2089+ self . src . c_helpers ( "size_t map_len = ptr->len;\n " ) ;
2090+ uwriteln ! ( self . src. c_helpers, "if (map_len > 0) {{" ) ;
2091+ uwriteln ! ( self . src. c_helpers, "{entry_name} *map_ptr = ptr->ptr;" ) ;
2092+ self . src
2093+ . c_helpers ( "for (size_t i = 0; i < map_len; i++) {\n " ) ;
2094+ self . free ( key, "&map_ptr[i].key" ) ;
2095+ self . free ( value, "&map_ptr[i].value" ) ;
2096+ self . src . c_helpers ( "}\n " ) ;
2097+ uwriteln ! ( self . src. c_helpers, "free(map_ptr);" ) ;
2098+ uwriteln ! ( self . src. c_helpers, "}}" ) ;
2099+ }
20682100 }
20692101 if c_helpers_body_start == self . src . c_helpers . len ( ) {
20702102 self . src . c_helpers . as_mut_string ( ) . truncate ( c_helpers_start) ;
@@ -2673,6 +2705,31 @@ void {name}_return({return_ty}) {{
26732705 self . print_typedef_target ( id) ;
26742706 }
26752707
2708+ /// Returns the typedef name of the synthetic entry struct used as the
2709+ /// element type of a `map<K, V>`'s flat-pair representation.
2710+ fn map_entry_typename ( & self , id : TypeId ) -> String {
2711+ let map_name = & self . r#gen . type_names [ & id] ;
2712+ let prefix = map_name. strip_suffix ( "_t" ) . unwrap_or ( map_name. as_str ( ) ) ;
2713+ format ! ( "{prefix}_entry_t" )
2714+ }
2715+
2716+ fn print_map_entry_typename ( & mut self , id : TypeId ) {
2717+ let entry_name = self . map_entry_typename ( id) ;
2718+ self . src . h_defs ( & entry_name) ;
2719+ }
2720+
2721+ /// Emits the `typedef struct { K key; V value; } <map>_entry_t;` companion
2722+ /// declaration that precedes the map struct itself.
2723+ fn print_map_entry_typedef ( & mut self , id : TypeId , key : & Type , value : & Type ) {
2724+ self . src . h_defs ( "\n typedef struct {\n " ) ;
2725+ self . print_ty ( SourceType :: HDefs , key) ;
2726+ self . src . h_defs ( " key;\n " ) ;
2727+ self . print_ty ( SourceType :: HDefs , value) ;
2728+ self . src . h_defs ( " value;\n } " ) ;
2729+ self . print_map_entry_typename ( id) ;
2730+ self . src . h_defs ( ";\n " ) ;
2731+ }
2732+
26762733 fn owner_namespace ( & self , id : TypeId ) -> String {
26772734 owner_namespace (
26782735 self . interface ,
@@ -2758,7 +2815,9 @@ void {name}_return({return_ty}) {{
27582815
27592816 TypeDefKind :: Unknown => false ,
27602817 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
2761- TypeDefKind :: Map ( ..) => todo ! ( ) ,
2818+ TypeDefKind :: Map ( key, value) => {
2819+ self . contains_droppable_borrow ( key) || self . contains_droppable_borrow ( value)
2820+ }
27622821 }
27632822 } else {
27642823 false
@@ -3640,7 +3699,35 @@ impl Bindgen for FunctionBindgen<'_, '_> {
36403699 list_name, elem_name, operands[ 0 ] , operands[ 1 ]
36413700 ) ) ;
36423701 }
3702+
3703+ // Maps share the canonical "flat array of entries" layout with the
3704+ // C struct emitted by `type_map`/`anonymous_type_map`, so the body
3705+ // block is discarded and we splice `.ptr` / `.len` through directly
3706+ // (mirroring how `ListLower`/`ListLift` work above).
3707+ Instruction :: MapLower { .. } => {
3708+ let _body = self . blocks . pop ( ) . unwrap ( ) ;
3709+ results. push ( format ! ( "(uint8_t *) ({}).ptr" , operands[ 0 ] ) ) ;
3710+ results. push ( format ! ( "({}).len" , operands[ 0 ] ) ) ;
3711+ }
3712+
3713+ Instruction :: MapLift { ty, .. } => {
3714+ self . assert_no_droppable_borrows ( "map" , & Type :: Id ( * ty) ) ;
3715+
3716+ let _body = self . blocks . pop ( ) . unwrap ( ) ;
3717+ let map_name = self . r#gen . r#gen . type_name ( & Type :: Id ( * ty) ) ;
3718+ let entry_name = {
3719+ let prefix = map_name. strip_suffix ( "_t" ) . unwrap_or ( & map_name) ;
3720+ format ! ( "{prefix}_entry_t" )
3721+ } ;
3722+ results. push ( format ! (
3723+ "({}) {{ ({}*)({}), ({}) }}" ,
3724+ map_name, entry_name, operands[ 0 ] , operands[ 1 ]
3725+ ) ) ;
3726+ }
3727+
36433728 Instruction :: IterElem { .. } => results. push ( "e" . to_string ( ) ) ,
3729+ Instruction :: IterMapKey { .. } => results. push ( "map_key" . to_string ( ) ) ,
3730+ Instruction :: IterMapValue { .. } => results. push ( "map_value" . to_string ( ) ) ,
36443731 Instruction :: IterBasePointer => results. push ( "base" . to_string ( ) ) ,
36453732
36463733 Instruction :: CallWasm { sig, .. } => {
@@ -3976,6 +4063,29 @@ impl Bindgen for FunctionBindgen<'_, '_> {
39764063 uwriteln ! ( self . src, "}}" ) ;
39774064 }
39784065
4066+ Instruction :: GuestDeallocateMap { key, value } => {
4067+ let ( body, results) = self . blocks . pop ( ) . unwrap ( ) ;
4068+ assert ! ( results. is_empty( ) ) ;
4069+ let len = self . locals . tmp ( "len" ) ;
4070+ uwriteln ! ( self . src, "size_t {len} = {};" , operands[ 1 ] ) ;
4071+ uwriteln ! ( self . src, "if ({len} > 0) {{" ) ;
4072+ let ptr = self . locals . tmp ( "ptr" ) ;
4073+ uwriteln ! ( self . src, "uint8_t *{ptr} = {};" , operands[ 0 ] ) ;
4074+ let i = self . locals . tmp ( "i" ) ;
4075+ uwriteln ! ( self . src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{" ) ;
4076+ let entry = self . r#gen . r#gen . sizes . record ( [ * key, * value] ) ;
4077+ uwriteln ! (
4078+ self . src,
4079+ "uint8_t *base = {ptr} + {i} * {};" ,
4080+ entry. size. format( POINTER_SIZE_EXPRESSION )
4081+ ) ;
4082+ uwriteln ! ( self . src, "(void) base;" ) ;
4083+ uwrite ! ( self . src, "{body}" ) ;
4084+ uwriteln ! ( self . src, "}}" ) ;
4085+ uwriteln ! ( self . src, "free({ptr});" ) ;
4086+ uwriteln ! ( self . src, "}}" ) ;
4087+ }
4088+
39794089 Instruction :: Flush { amt } => {
39804090 results. extend ( operands. iter ( ) . take ( * amt) . cloned ( ) ) ;
39814091 }
@@ -4122,13 +4232,15 @@ pub fn is_arg_by_pointer(resolve: &Resolve, ty: &Type) -> bool {
41224232 TypeDefKind :: Enum ( _) => false ,
41234233 TypeDefKind :: Flags ( _) => false ,
41244234 TypeDefKind :: Handle ( _) => false ,
4125- TypeDefKind :: Tuple ( _) | TypeDefKind :: Record ( _) | TypeDefKind :: List ( _) => true ,
4235+ TypeDefKind :: Tuple ( _)
4236+ | TypeDefKind :: Record ( _)
4237+ | TypeDefKind :: List ( _)
4238+ | TypeDefKind :: Map ( ..) => true ,
41264239 TypeDefKind :: Future ( _) => false ,
41274240 TypeDefKind :: Stream ( _) => false ,
41284241 TypeDefKind :: Resource => todo ! ( "is_arg_by_pointer for resource" ) ,
41294242 TypeDefKind :: Unknown => unreachable ! ( ) ,
41304243 TypeDefKind :: FixedLengthList ( ..) => todo ! ( ) ,
4131- TypeDefKind :: Map ( ..) => todo ! ( ) ,
41324244 } ,
41334245 Type :: String => true ,
41344246 _ => false ,
0 commit comments