reflect.odin 8.8 KB

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