Browse Source

Merge pull request #4030 from Kelimion/struct_field_count

Add `reflect.struct_field_count` that returns the number of fields in a struct type
gingerBill 1 year ago
parent
commit
94ded29b5f
1 changed files with 58 additions and 0 deletions
  1. 58 0
      core/reflect/reflect.odin

+ 58 - 0
core/reflect/reflect.odin

@@ -496,6 +496,64 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
 	return nil
 	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)
 @(require_results)
 struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
 struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
 	ti := runtime.type_info_base(type_info_of(T))
 	ti := runtime.type_info_base(type_info_of(T))