reflect.odin 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. package reflect
  2. import "core:runtime"
  3. import "core:mem"
  4. Type_Kind :: enum {
  5. Invalid,
  6. Named,
  7. Integer,
  8. Rune,
  9. Float,
  10. Complex,
  11. Quaternion,
  12. String,
  13. Boolean,
  14. Any,
  15. Type_Id,
  16. Pointer,
  17. Procedure,
  18. Array,
  19. Dynamic_Array,
  20. Slice,
  21. Tuple,
  22. Struct,
  23. Union,
  24. Enum,
  25. Map,
  26. Bit_Field,
  27. Bit_Set,
  28. Opaque,
  29. Simd_Vector,
  30. }
  31. type_kind :: proc(T: typeid) -> Type_Kind {
  32. ti := type_info_of(T);
  33. if ti != nil {
  34. #complete switch _ in ti.variant {
  35. case runtime.Type_Info_Named: return .Named;
  36. case runtime.Type_Info_Integer: return .Integer;
  37. case runtime.Type_Info_Rune: return .Rune;
  38. case runtime.Type_Info_Float: return .Float;
  39. case runtime.Type_Info_Complex: return .Complex;
  40. case runtime.Type_Info_Quaternion: return .Quaternion;
  41. case runtime.Type_Info_String: return .String;
  42. case runtime.Type_Info_Boolean: return .Boolean;
  43. case runtime.Type_Info_Any: return .Any;
  44. case runtime.Type_Info_Type_Id: return .Type_Id;
  45. case runtime.Type_Info_Pointer: return .Pointer;
  46. case runtime.Type_Info_Procedure: return .Procedure;
  47. case runtime.Type_Info_Array: return .Array;
  48. case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
  49. case runtime.Type_Info_Slice: return .Slice;
  50. case runtime.Type_Info_Tuple: return .Tuple;
  51. case runtime.Type_Info_Struct: return .Struct;
  52. case runtime.Type_Info_Union: return .Union;
  53. case runtime.Type_Info_Enum: return .Enum;
  54. case runtime.Type_Info_Map: return .Map;
  55. case runtime.Type_Info_Bit_Field: return .Bit_Field;
  56. case runtime.Type_Info_Bit_Set: return .Bit_Set;
  57. case runtime.Type_Info_Opaque: return .Opaque;
  58. case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
  59. }
  60. }
  61. return .Invalid;
  62. }
  63. // TODO(bill): Better name
  64. underlying_type_kind :: proc(T: typeid) -> Type_Kind {
  65. return type_kind(runtime.typeid_base(T));
  66. }
  67. // TODO(bill): Better name
  68. backing_type_kind :: proc(T: typeid) -> Type_Kind {
  69. return type_kind(runtime.typeid_core(T));
  70. }
  71. size_of_typeid :: proc(T: typeid) -> int {
  72. if ti := type_info_of(T); ti != nil {
  73. return ti.size;
  74. }
  75. return 0;
  76. }
  77. align_of_typeid :: proc(T: typeid) -> int {
  78. if ti := type_info_of(T); ti != nil {
  79. return ti.align;
  80. }
  81. return 1;
  82. }
  83. to_bytes :: proc(v: any) -> []byte {
  84. if v != nil {
  85. sz := size_of_typeid(v.id);
  86. return mem.slice_ptr((^byte)(v.data), sz);
  87. }
  88. return nil;
  89. }
  90. any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
  91. return v.data, v.id;
  92. }
  93. is_nil :: proc(v: any) -> bool {
  94. data := to_bytes(v);
  95. if data != nil {
  96. return true;
  97. }
  98. for v in data do if v != 0 {
  99. return false;
  100. }
  101. return true;
  102. }
  103. length :: proc(val: any) -> int {
  104. if val == nil do return 0;
  105. v := val;
  106. v.id = runtime.typeid_base(v.id);
  107. switch a in v {
  108. case runtime.Type_Info_Array:
  109. return a.count;
  110. case runtime.Type_Info_Slice:
  111. return (^mem.Raw_Slice)(v.data).len;
  112. case runtime.Type_Info_Dynamic_Array:
  113. return (^mem.Raw_Dynamic_Array)(v.data).len;
  114. case runtime.Type_Info_String:
  115. if a.is_cstring {
  116. return len((^cstring)(v.data)^);
  117. } else {
  118. return (^mem.Raw_String)(v.data).len;
  119. }
  120. }
  121. return 0;
  122. }
  123. index :: proc(val: any, i: int, loc := #caller_location) -> any {
  124. if val == nil do return nil;
  125. v := val;
  126. v.id = runtime.typeid_base(v.id);
  127. switch a in v {
  128. case runtime.Type_Info_Array:
  129. runtime.bounds_check_error_loc(loc, i, a.count);
  130. offset := uintptr(a.elem.size * i);
  131. data := rawptr(uintptr(v.data) + offset);
  132. return any{data, a.elem.id};
  133. case runtime.Type_Info_Slice:
  134. raw := (^mem.Raw_Slice)(v.data);
  135. runtime.bounds_check_error_loc(loc, i, raw.len);
  136. offset := uintptr(a.elem.size * i);
  137. data := rawptr(uintptr(raw.data) + offset);
  138. return any{data, a.elem.id};
  139. case runtime.Type_Info_Dynamic_Array:
  140. raw := (^mem.Raw_Dynamic_Array)(v.data);
  141. runtime.bounds_check_error_loc(loc, i, raw.len);
  142. offset := uintptr(a.elem.size * i);
  143. data := rawptr(uintptr(raw.data) + offset);
  144. return any{data, a.elem.id};
  145. case runtime.Type_Info_String:
  146. if a.is_cstring do return nil;
  147. raw := (^mem.Raw_String)(v.data);
  148. runtime.bounds_check_error_loc(loc, i, raw.len);
  149. offset := uintptr(size_of(u8) * i);
  150. data := rawptr(uintptr(raw.data) + offset);
  151. return any{data, typeid_of(u8)};
  152. }
  153. return nil;
  154. }
  155. Struct_Tag :: distinct string;
  156. Struct_Field :: struct {
  157. name: string,
  158. type: typeid,
  159. tag: Struct_Tag,
  160. offset: uintptr,
  161. }
  162. struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
  163. ti := runtime.type_info_base(type_info_of(T));
  164. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  165. if 0 <= i && i < len(s.names) {
  166. field.name = s.names[i];
  167. field.type = s.types[i].id;
  168. field.tag = Struct_Tag(s.tags[i]);
  169. field.offset = s.offsets[i];
  170. }
  171. }
  172. return;
  173. }
  174. struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
  175. ti := runtime.type_info_base(type_info_of(T));
  176. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  177. for fname, i in s.names {
  178. if fname == name {
  179. field.name = s.names[i];
  180. field.type = s.types[i].id;
  181. field.tag = Struct_Tag(s.tags[i]);
  182. field.offset = s.offsets[i];
  183. break;
  184. }
  185. }
  186. }
  187. return;
  188. }
  189. struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
  190. if a == nil do return nil;
  191. ti := runtime.type_info_base(type_info_of(a.id));
  192. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  193. for name, i in s.names {
  194. if name == field {
  195. return any{
  196. rawptr(uintptr(a.data) + s.offsets[i]),
  197. s.types[i].id,
  198. };
  199. }
  200. if recurse && s.usings[i] {
  201. f := any{
  202. rawptr(uintptr(a.data) + s.offsets[i]),
  203. s.types[i].id,
  204. };
  205. if res := struct_field_value_by_name(f, field, recurse); res != nil {
  206. return res;
  207. }
  208. }
  209. }
  210. }
  211. return nil;
  212. }
  213. struct_field_names :: proc(T: typeid) -> []string {
  214. ti := runtime.type_info_base(type_info_of(T));
  215. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  216. return s.names;
  217. }
  218. return nil;
  219. }
  220. struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
  221. ti := runtime.type_info_base(type_info_of(T));
  222. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  223. return s.types;
  224. }
  225. return nil;
  226. }
  227. struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
  228. ti := runtime.type_info_base(type_info_of(T));
  229. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  230. return transmute([]Struct_Tag)s.tags;
  231. }
  232. return nil;
  233. }
  234. struct_field_offsets :: proc(T: typeid) -> []uintptr {
  235. ti := runtime.type_info_base(type_info_of(T));
  236. if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
  237. return s.offsets;
  238. }
  239. return nil;
  240. }
  241. struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
  242. value, _ = struct_tag_lookup(tag, key);
  243. return;
  244. }
  245. struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
  246. for t := tag; t != ""; /**/ {
  247. i := 0;
  248. for i < len(t) && t[i] == ' ' { // Skip whitespace
  249. i += 1;
  250. }
  251. t = t[i:];
  252. if len(t) == 0 do break;
  253. i = 0;
  254. loop: for i < len(t) {
  255. switch t[i] {
  256. case ':', '"':
  257. break loop;
  258. case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
  259. break loop;
  260. }
  261. i += 1;
  262. }
  263. if i == 0 do break;
  264. if i+1 >= len(t) do break;
  265. if t[i] != ':' || t[i+1] != '"' {
  266. break;
  267. }
  268. name := string(t[:i]);
  269. t = t[i+1:];
  270. i = 1;
  271. for i < len(t) && t[i] != '"' { // find closing quote
  272. if t[i] == '\\' do i += 1; // Skip escaped characters
  273. i += 1;
  274. }
  275. if i >= len(t) do break;
  276. val := string(t[:i+1]);
  277. t = t[i+1:];
  278. if key == name {
  279. return val[1:i], true;
  280. }
  281. }
  282. return;
  283. }
  284. enum_string :: proc(a: any) -> string {
  285. if a == nil do return "";
  286. ti := runtime.type_info_base(type_info_of(a.id));
  287. if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
  288. for _, i in e.values {
  289. value := &e.values[i];
  290. n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
  291. if n == 0 {
  292. return e.names[i];
  293. }
  294. }
  295. } else {
  296. panic("expected an enum to reflect.enum_string");
  297. }
  298. return "";
  299. }
  300. union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
  301. id := union_variant_typeid(a);
  302. return type_info_of(id);
  303. }
  304. union_variant_typeid :: proc(a: any) -> typeid {
  305. if a == nil do return nil;
  306. ti := runtime.type_info_base(type_info_of(a.id));
  307. if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
  308. tag_ptr := uintptr(a.data) + info.tag_offset;
  309. tag_any := any{rawptr(tag_ptr), info.tag_type.id};
  310. tag: i64 = ---;
  311. switch i in tag_any {
  312. case u8: tag = i64(i);
  313. case i8: tag = i64(i);
  314. case u16: tag = i64(i);
  315. case i16: tag = i64(i);
  316. case u32: tag = i64(i);
  317. case i32: tag = i64(i);
  318. case u64: tag = i64(i);
  319. case i64: tag = i64(i);
  320. case: unimplemented();
  321. }
  322. if a.data != nil && tag != 0 {
  323. return info.variants[tag-1].id;
  324. }
  325. } else {
  326. panic("expected a union to reflect.union_variant_typeid");
  327. }
  328. return nil;
  329. }