@@ -53,6 +53,7 @@ struct EnumDef {
5353struct EnumVariant {
5454 name : String ,
5555 value : i64 ,
56+ rust_type : Option < String > ,
5657}
5758
5859#[ derive( Debug , Clone ) ]
@@ -196,6 +197,9 @@ fn process_schema(
196197 let schema = reflection:: root_as_schema ( schema_bytes)
197198 . map_err ( |e| format ! ( "Failed to parse schema: {}" , e) ) ?;
198199
200+ // Collect objects (tables and structs) first so we can resolve union variants
201+ let schema_objects = schema. objects ( ) ;
202+
199203 // Collect enums
200204 let schema_enums = schema. enums ( ) ;
201205 for i in 0 ..schema_enums. len ( ) {
@@ -213,9 +217,29 @@ fn process_schema(
213217 let vals = e. values ( ) ;
214218 for j in 0 ..vals. len ( ) {
215219 let v = vals. get ( j) ;
220+ let rust_type = if is_union {
221+ if let Some ( union_type) = v. union_type ( ) {
222+ let base = union_type. base_type ( ) ;
223+ let idx = union_type. index ( ) ;
224+ if base == BaseType :: Obj {
225+ let obj_fqn = schema_objects. get ( idx as usize ) . name ( ) . to_string ( ) ;
226+ Some ( leaf_name ( & obj_fqn) . to_string ( ) )
227+ } else if base == BaseType :: String {
228+ Some ( "String" . to_string ( ) )
229+ } else {
230+ None
231+ }
232+ } else {
233+ None
234+ }
235+ } else {
236+ None
237+ } ;
238+
216239 variants. push ( EnumVariant {
217240 name : v. name ( ) . to_string ( ) ,
218241 value : v. value ( ) ,
242+ rust_type,
219243 } ) ;
220244 }
221245
@@ -229,8 +253,7 @@ fn process_schema(
229253 ) ;
230254 }
231255
232- // Collect objects (tables and structs)
233- let schema_objects = schema. objects ( ) ;
256+ // Process fields for objects
234257 for i in 0 ..schema_objects. len ( ) {
235258 let obj = schema_objects. get ( i) ;
236259 let fqn = obj. name ( ) . to_string ( ) ;
@@ -253,17 +276,17 @@ fn process_schema(
253276 continue ;
254277 }
255278
256- // Skip union fields — unions require special handling (TODO: Story 2c.2)
257- if base == BaseType :: Union {
258- continue ;
259- }
279+ // Union fields are now processed
280+ // if base == BaseType::Union {
281+ // continue;
282+ // }
260283
261- // Skip union vector fields (vector of unions or their discriminators)
262- if base == BaseType :: Vector
263- && ( ty. element ( ) == BaseType :: Union || ty. element ( ) == BaseType :: UType )
264- {
265- continue ;
266- }
284+ // Union vector fields are now processed
285+ // if base == BaseType::Vector
286+ // && (ty.element() == BaseType::Union || ty.element() == BaseType::UType)
287+ // {
288+ // continue;
289+ // }
267290
268291 // Determine the Rust type for this field
269292 let Some ( ( rust_type, is_optional, default_value, serde_rename) ) =
@@ -357,6 +380,14 @@ fn resolve_field_type(
357380 }
358381
359382 match base {
383+ BaseType :: Union => {
384+ let enum_fqn = schema_enums. get ( idx as usize ) . name ( ) . to_string ( ) ;
385+ let enum_name = all_enum_names
386+ . get ( & enum_fqn)
387+ . cloned ( )
388+ . unwrap_or_else ( || leaf_name ( & enum_fqn) . to_string ( ) ) ;
389+ Some ( ( enum_name, is_opt, None , None ) )
390+ }
360391 BaseType :: Obj => {
361392 let obj_fqn = objects. get ( idx as usize ) . name ( ) . to_string ( ) ;
362393 let obj_name = leaf_name ( & obj_fqn) . to_string ( ) ;
@@ -365,6 +396,10 @@ fn resolve_field_type(
365396 }
366397 BaseType :: Vector => {
367398 let inner = match ty. element ( ) {
399+ BaseType :: Union => {
400+ let enum_fqn = schema_enums. get ( idx as usize ) . name ( ) . to_string ( ) ;
401+ leaf_name ( & enum_fqn) . to_string ( )
402+ }
368403 BaseType :: Obj => {
369404 let obj_fqn = objects. get ( idx as usize ) . name ( ) . to_string ( ) ;
370405 leaf_name ( & obj_fqn) . to_string ( )
@@ -453,10 +488,21 @@ fn generate_code(
453488 if def. is_union {
454489 writeln ! (
455490 out,
456- "// TODO: Union type {} skipped — requires special serde handling (Story 2c.2)" ,
457- def. name
491+ "#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]"
458492 )
459493 . unwrap ( ) ;
494+ writeln ! ( out, "#[serde(untagged)]" ) . unwrap ( ) ;
495+ writeln ! ( out, "pub enum {} {{" , def. name) . unwrap ( ) ;
496+ for variant in & def. variants {
497+ let rust_name = & variant. name ;
498+ if rust_name == "NONE" {
499+ writeln ! ( out, " None," ) . unwrap ( ) ;
500+ } else {
501+ let ty = variant. rust_type . as_deref ( ) . unwrap_or ( rust_name) ;
502+ writeln ! ( out, " {}({})," , rust_name, ty) . unwrap ( ) ;
503+ }
504+ }
505+ writeln ! ( out, "}}" ) . unwrap ( ) ;
460506 writeln ! ( out) . unwrap ( ) ;
461507 continue ;
462508 }
@@ -738,7 +784,7 @@ See the README for detailed setup instructions.
738784 let union_count = enums. values ( ) . filter ( |e| e. is_union ) . count ( ) ;
739785 let struct_count = structs. len ( ) ;
740786 println ! (
741- "cargo:warning=Generated asset types from {} schema files: {} enums, {} structs ({} unions skipped )" ,
787+ "cargo:warning=Generated asset types from {} schema files: {} enums, {} structs ({} unions processed )" ,
742788 bfbs_files. len( ) ,
743789 enum_count,
744790 struct_count,
0 commit comments