diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 23c0f803e..aff82136a 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -496,6 +496,64 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr { return nil } +Struct_Field_Count_Method :: enum { + Top_Level, + Using, + Recursive, +} + +/* +Counts the number of fields in a struct + +This procedure returns the number of fields in a struct, counting in one of three ways: +- .Top_Level: Only counts the top-level fields +- .Using: Same count as .Top_Level, and adds the field count of any `using s: Struct` it encounters (in addition to itself) +- .Recursive: The count of all top-level fields, plus the count of any child struct's fields, recursively + +Inputs: +- T: The struct type +- method: The counting method + +Returns: +- The `count`, enumerated using the `method`, which will be `0` if the type is not a struct + +Example: + symbols_loaded, ok := dynlib.initialize_symbols(&game_api, "game.dll") + symbols_expected := reflect.struct_field_count(Game_Api) - API_PRIVATE_COUNT + + if symbols_loaded != symbols_expected { + fmt.eprintf("Expected %v symbols, got %v", symbols_expected, symbols_loaded) + return + } +*/ +@(require_results) +struct_field_count :: proc(T: typeid, method := Struct_Field_Count_Method.Top_Level) -> (count: int) { + ti := runtime.type_info_base(type_info_of(T)) + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + switch method { + case .Top_Level: + return int(s.field_count) + + case .Using: + count = int(s.field_count) + for type, i in s.types[:s.field_count] { + if s.usings[i] { + count += struct_field_count(type.id) + } + } + + case .Recursive: + count = int(s.field_count) + for type in s.types[:s.field_count] { + count += struct_field_count(type.id) + } + + case: return 0 + } + } + return +} + @(require_results) struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) { ti := runtime.type_info_base(type_info_of(T))