123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- package reflect
- import "core:runtime"
- import "core:mem"
- Type_Kind :: enum {
- Invalid,
- Named,
- Integer,
- Rune,
- Float,
- Complex,
- Quaternion,
- String,
- Boolean,
- Any,
- Type_Id,
- Pointer,
- Procedure,
- Array,
- Dynamic_Array,
- Slice,
- Tuple,
- Struct,
- Union,
- Enum,
- Map,
- Bit_Field,
- Bit_Set,
- Opaque,
- Simd_Vector,
- }
- type_kind :: proc(T: typeid) -> Type_Kind {
- ti := type_info_of(T);
- if ti != nil {
- #complete switch _ in ti.variant {
- case runtime.Type_Info_Named: return .Named;
- case runtime.Type_Info_Integer: return .Integer;
- case runtime.Type_Info_Rune: return .Rune;
- case runtime.Type_Info_Float: return .Float;
- case runtime.Type_Info_Complex: return .Complex;
- case runtime.Type_Info_Quaternion: return .Quaternion;
- case runtime.Type_Info_String: return .String;
- case runtime.Type_Info_Boolean: return .Boolean;
- case runtime.Type_Info_Any: return .Any;
- case runtime.Type_Info_Type_Id: return .Type_Id;
- case runtime.Type_Info_Pointer: return .Pointer;
- case runtime.Type_Info_Procedure: return .Procedure;
- case runtime.Type_Info_Array: return .Array;
- case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
- case runtime.Type_Info_Slice: return .Slice;
- case runtime.Type_Info_Tuple: return .Tuple;
- case runtime.Type_Info_Struct: return .Struct;
- case runtime.Type_Info_Union: return .Union;
- case runtime.Type_Info_Enum: return .Enum;
- case runtime.Type_Info_Map: return .Map;
- case runtime.Type_Info_Bit_Field: return .Bit_Field;
- case runtime.Type_Info_Bit_Set: return .Bit_Set;
- case runtime.Type_Info_Opaque: return .Opaque;
- case runtime.Type_Info_Simd_Vector: return .Simd_Vector;
- }
- }
- return .Invalid;
- }
- // TODO(bill): Better name
- underlying_type_kind :: proc(T: typeid) -> Type_Kind {
- return type_kind(runtime.typeid_base(T));
- }
- // TODO(bill): Better name
- backing_type_kind :: proc(T: typeid) -> Type_Kind {
- return type_kind(runtime.typeid_core(T));
- }
- size_of_typeid :: proc(T: typeid) -> int {
- if ti := type_info_of(T); ti != nil {
- return ti.size;
- }
- return 0;
- }
- align_of_typeid :: proc(T: typeid) -> int {
- if ti := type_info_of(T); ti != nil {
- return ti.align;
- }
- return 1;
- }
- to_bytes :: proc(v: any) -> []byte {
- if v != nil {
- sz := size_of_typeid(v.id);
- return mem.slice_ptr((^byte)(v.data), sz);
- }
- return nil;
- }
- any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
- return v.data, v.id;
- }
- is_nil :: proc(v: any) -> bool {
- data := to_bytes(v);
- if data != nil {
- return true;
- }
- for v in data do if v != 0 {
- return false;
- }
- return true;
- }
- length :: proc(val: any) -> int {
- if val == nil do return 0;
- v := val;
- v.id = runtime.typeid_base(v.id);
- switch a in v {
- case runtime.Type_Info_Array:
- return a.count;
- case runtime.Type_Info_Slice:
- return (^mem.Raw_Slice)(v.data).len;
- case runtime.Type_Info_Dynamic_Array:
- return (^mem.Raw_Dynamic_Array)(v.data).len;
- case runtime.Type_Info_String:
- if a.is_cstring {
- return len((^cstring)(v.data)^);
- } else {
- return (^mem.Raw_String)(v.data).len;
- }
- }
- return 0;
- }
- index :: proc(val: any, i: int, loc := #caller_location) -> any {
- if val == nil do return nil;
- v := val;
- v.id = runtime.typeid_base(v.id);
- switch a in v {
- case runtime.Type_Info_Array:
- runtime.bounds_check_error_loc(loc, i, a.count);
- offset := uintptr(a.elem.size * i);
- data := rawptr(uintptr(v.data) + offset);
- return any{data, a.elem.id};
- case runtime.Type_Info_Slice:
- raw := (^mem.Raw_Slice)(v.data);
- runtime.bounds_check_error_loc(loc, i, raw.len);
- offset := uintptr(a.elem.size * i);
- data := rawptr(uintptr(raw.data) + offset);
- return any{data, a.elem.id};
- case runtime.Type_Info_Dynamic_Array:
- raw := (^mem.Raw_Dynamic_Array)(v.data);
- runtime.bounds_check_error_loc(loc, i, raw.len);
- offset := uintptr(a.elem.size * i);
- data := rawptr(uintptr(raw.data) + offset);
- return any{data, a.elem.id};
- case runtime.Type_Info_String:
- if a.is_cstring do return nil;
- raw := (^mem.Raw_String)(v.data);
- runtime.bounds_check_error_loc(loc, i, raw.len);
- offset := uintptr(size_of(u8) * i);
- data := rawptr(uintptr(raw.data) + offset);
- return any{data, typeid_of(u8)};
- }
- return nil;
- }
- Struct_Tag :: distinct string;
- Struct_Field :: struct {
- name: string,
- type: typeid,
- tag: Struct_Tag,
- offset: uintptr,
- }
- struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- if 0 <= i && i < len(s.names) {
- field.name = s.names[i];
- field.type = s.types[i].id;
- field.tag = Struct_Tag(s.tags[i]);
- field.offset = s.offsets[i];
- }
- }
- return;
- }
- struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- for fname, i in s.names {
- if fname == name {
- field.name = s.names[i];
- field.type = s.types[i].id;
- field.tag = Struct_Tag(s.tags[i]);
- field.offset = s.offsets[i];
- break;
- }
- }
- }
- return;
- }
- struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
- if a == nil do return nil;
- ti := runtime.type_info_base(type_info_of(a.id));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- for name, i in s.names {
- if name == field {
- return any{
- rawptr(uintptr(a.data) + s.offsets[i]),
- s.types[i].id,
- };
- }
- if recurse && s.usings[i] {
- f := any{
- rawptr(uintptr(a.data) + s.offsets[i]),
- s.types[i].id,
- };
- if res := struct_field_value_by_name(f, field, recurse); res != nil {
- return res;
- }
- }
- }
- }
- return nil;
- }
- struct_field_names :: proc(T: typeid) -> []string {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- return s.names;
- }
- return nil;
- }
- struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- return s.types;
- }
- return nil;
- }
- struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- return transmute([]Struct_Tag)s.tags;
- }
- return nil;
- }
- struct_field_offsets :: proc(T: typeid) -> []uintptr {
- ti := runtime.type_info_base(type_info_of(T));
- if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
- return s.offsets;
- }
- return nil;
- }
- struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
- value, _ = struct_tag_lookup(tag, key);
- return;
- }
- struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
- for t := tag; t != ""; /**/ {
- i := 0;
- for i < len(t) && t[i] == ' ' { // Skip whitespace
- i += 1;
- }
- t = t[i:];
- if len(t) == 0 do break;
- i = 0;
- loop: for i < len(t) {
- switch t[i] {
- case ':', '"':
- break loop;
- case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found
- break loop;
- }
- i += 1;
- }
- if i == 0 do break;
- if i+1 >= len(t) do break;
- if t[i] != ':' || t[i+1] != '"' {
- break;
- }
- name := string(t[:i]);
- t = t[i+1:];
- i = 1;
- for i < len(t) && t[i] != '"' { // find closing quote
- if t[i] == '\\' do i += 1; // Skip escaped characters
- i += 1;
- }
- if i >= len(t) do break;
- val := string(t[:i+1]);
- t = t[i+1:];
- if key == name {
- return val[1:i], true;
- }
- }
- return;
- }
- enum_string :: proc(a: any) -> string {
- if a == nil do return "";
- ti := runtime.type_info_base(type_info_of(a.id));
- if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
- for _, i in e.values {
- value := &e.values[i];
- n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
- if n == 0 {
- return e.names[i];
- }
- }
- } else {
- panic("expected an enum to reflect.enum_string");
- }
- return "";
- }
- union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
- id := union_variant_typeid(a);
- return type_info_of(id);
- }
- union_variant_typeid :: proc(a: any) -> typeid {
- if a == nil do return nil;
- ti := runtime.type_info_base(type_info_of(a.id));
- if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
- tag_ptr := uintptr(a.data) + info.tag_offset;
- tag_any := any{rawptr(tag_ptr), info.tag_type.id};
- tag: i64 = ---;
- switch i in tag_any {
- case u8: tag = i64(i);
- case i8: tag = i64(i);
- case u16: tag = i64(i);
- case i16: tag = i64(i);
- case u32: tag = i64(i);
- case i32: tag = i64(i);
- case u64: tag = i64(i);
- case i64: tag = i64(i);
- case: unimplemented();
- }
- if a.data != nil && tag != 0 {
- return info.variants[tag-1].id;
- }
- } else {
- panic("expected a union to reflect.union_variant_typeid");
- }
- return nil;
- }
|