Add reflect.struct_field_count that returns the number of fields in a struct type

Example:
```odin
package struct_count_example

import "core:fmt"
import "core:reflect"
import "core:dynlib"

Foo :: struct{
	one: int,
	two: f32,
}

Bar :: struct {
	three: int,
	four:  bool,
	five:  f64,
}

Game_Api :: struct {
	init:      proc(api: ^Game_Api),
	update:    proc(api: ^Game_Api),

	using foo: Foo,
	bar:       Bar,

	// Private stuff
	reload_count: int,
	__handle:     rawptr,
}
API_PRIVATE_COUNT :: 2

game_api: Game_Api

main :: proc() {
	fmt.printfln("Game_Api, .Top:       %v", reflect.struct_field_count(Game_Api))              // 6
	fmt.printfln("Game_Api, .Using:     %v", reflect.struct_field_count(Game_Api, .Using))      // 8
	fmt.printfln("Game_Api, .Recursive: %v", reflect.struct_field_count(Game_Api, .Recursive))  // 11

	symbols_loaded, _  := dynlib.initialize_symbols(&game_api, "game.dll")
	symbols_expected   := reflect.struct_field_count(Game_Api) - API_PRIVATE_COUNT

	if symbols_loaded == -1 {
		fmt.eprintln("Couldn't load game.dll")
		return
	} else if symbols_loaded != symbols_expected {
		fmt.eprintfln("Expected %v symbols, got %v", symbols_expected, symbols_loaded)
		return
	}
}
```
This commit is contained in:
Jeroen van Rijn
2024-08-05 22:04:16 +02:00
parent 7c3461b0df
commit 4902288a5a

View File

@@ -496,6 +496,62 @@ 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:
expected_count := reflect.struct_field_count(Game_API) - API_PRIVATE_COUNT
if symbols_loaded != expected_count {
fmt.eprintf("Expected %v symbols, got %v", expected_count, 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))