|
@@ -2,6 +2,8 @@ package reflect
|
|
|
|
|
|
import "core:runtime"
|
|
|
import "core:mem"
|
|
|
+import "intrinsics"
|
|
|
+_ :: intrinsics;
|
|
|
|
|
|
Type_Info :: runtime.Type_Info;
|
|
|
|
|
@@ -551,11 +553,22 @@ union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
|
|
|
return type_info_of(id);
|
|
|
}
|
|
|
|
|
|
+type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
|
|
+ return info.maybe && len(info.variants) == 1 && is_pointer(info.variants[0]);
|
|
|
+}
|
|
|
+
|
|
|
union_variant_typeid :: proc(a: any) -> typeid {
|
|
|
if a == nil { return nil; }
|
|
|
|
|
|
ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ if type_info_union_is_pure_maybe(info) {
|
|
|
+ if a.data != nil {
|
|
|
+ return info.variants[0].id;
|
|
|
+ }
|
|
|
+ return nil;
|
|
|
+ }
|
|
|
+
|
|
|
tag_ptr := uintptr(a.data) + info.tag_offset;
|
|
|
tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
|
|
|
|
@@ -573,15 +586,159 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|
|
}
|
|
|
|
|
|
if a.data != nil && tag != 0 {
|
|
|
- return info.variants[tag-1].id;
|
|
|
+ i := tag if info.no_nil else tag-1;
|
|
|
+ return info.variants[i].id;
|
|
|
}
|
|
|
- } else {
|
|
|
- panic("expected a union to reflect.union_variant_typeid");
|
|
|
+
|
|
|
+ return nil;
|
|
|
}
|
|
|
+ panic("expected a union to reflect.union_variant_typeid");
|
|
|
|
|
|
- return nil;
|
|
|
}
|
|
|
|
|
|
+get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
|
|
+ if a == nil { return -1; }
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ if type_info_union_is_pure_maybe(info) {
|
|
|
+ return 1 if a.data != nil else 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ return tag;
|
|
|
+ }
|
|
|
+ panic("expected a union to reflect.get_union_variant_raw_tag");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+set_union_variant_raw_tag :: proc(a: any, tag: i64) {
|
|
|
+ if a == nil { return; }
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ if type_info_union_is_pure_maybe(info) {
|
|
|
+ // Cannot do anything
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tag_ptr := uintptr(a.data) + info.tag_offset;
|
|
|
+ tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
|
|
+
|
|
|
+ switch i in &tag_any {
|
|
|
+ case u8: i = u8(tag);
|
|
|
+ case i8: i = i8(tag);
|
|
|
+ case u16: i = u16(tag);
|
|
|
+ case i16: i = i16(tag);
|
|
|
+ case u32: i = u32(tag);
|
|
|
+ case i32: i = i32(tag);
|
|
|
+ case u64: i = u64(tag);
|
|
|
+ case i64: i = i64(tag);
|
|
|
+ case: unimplemented();
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ panic("expected a union to reflect.set_union_variant_raw_tag");
|
|
|
+}
|
|
|
+
|
|
|
+set_union_variant_typeid :: proc(a: any, id: typeid) {
|
|
|
+ if a == nil { return; }
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ if type_info_union_is_pure_maybe(info) {
|
|
|
+ // Cannot do anything
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if id == nil && !info.no_nil {
|
|
|
+ set_union_variant_raw_tag(a, 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for variant, i in info.variants {
|
|
|
+ if variant.id == id {
|
|
|
+ tag := i64(i);
|
|
|
+ if !info.no_nil {
|
|
|
+ tag += 1;
|
|
|
+ }
|
|
|
+ set_union_variant_raw_tag(a, tag);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ panic("expected a union to reflect.set_union_variant_typeid");
|
|
|
+}
|
|
|
+
|
|
|
+set_union_variant_type_info :: proc(a: any, tag_ti: ^Type_Info) {
|
|
|
+ if a == nil { return; }
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ if type_info_union_is_pure_maybe(info) {
|
|
|
+ // Cannot do anything
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if tag_ti == nil && !info.no_nil {
|
|
|
+ set_union_variant_raw_tag(a, 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for variant, i in info.variants {
|
|
|
+ if variant == tag_ti {
|
|
|
+ tag := i64(i);
|
|
|
+ if !info.no_nil {
|
|
|
+ tag += 1;
|
|
|
+ }
|
|
|
+ set_union_variant_raw_tag(a, tag);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ panic("expected a union to reflect.set_union_variant_type_info");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
|
|
+ if a == nil { return; }
|
|
|
+ a := a;
|
|
|
+ ti := runtime.type_info_core(type_info_of(a.id));
|
|
|
+ a.id = ti.id;
|
|
|
+
|
|
|
+ #partial switch info in ti.variant {
|
|
|
+ case Type_Info_Boolean:
|
|
|
+ valid = true;
|
|
|
+ switch v in a {
|
|
|
+ case bool: value = bool(v);
|
|
|
+ case b8: value = bool(v);
|
|
|
+ case b16: value = bool(v);
|
|
|
+ case b32: value = bool(v);
|
|
|
+ case b64: value = bool(v);
|
|
|
+ case: valid = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
|
|
|
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
|
|
v: i64;
|
|
@@ -915,3 +1072,137 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+as_string :: proc(a: any) -> (value: string, valid: bool) {
|
|
|
+ if a == nil { return; }
|
|
|
+ a := a;
|
|
|
+ ti := runtime.type_info_core(type_info_of(a.id));
|
|
|
+ a.id = ti.id;
|
|
|
+
|
|
|
+ #partial switch info in ti.variant {
|
|
|
+ case Type_Info_String:
|
|
|
+ valid = true;
|
|
|
+ switch v in a {
|
|
|
+ case string: value = string(v);
|
|
|
+ case cstring: value = string(v);
|
|
|
+ case: valid = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
|
|
+ if a == nil { return nil; }
|
|
|
+ a := a;
|
|
|
+ ti := runtime.type_info_core(type_info_of(a.id));
|
|
|
+ a.id = ti.id;
|
|
|
+
|
|
|
+ #partial switch info in ti.variant {
|
|
|
+ case Type_Info_Relative_Pointer:
|
|
|
+ return relative_pointer_to_absolute_raw(a.data, info.base_integer.id);
|
|
|
+ }
|
|
|
+ return nil;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
|
|
+ _handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
|
|
+ if ptr^ == 0 {
|
|
|
+ return nil;
|
|
|
+ }
|
|
|
+ when intrinsics.type_is_unsigned(T) {
|
|
|
+ return rawptr(uintptr(ptr) + uintptr(ptr^));
|
|
|
+ } else {
|
|
|
+ return rawptr(uintptr(ptr) + uintptr(i64(ptr^)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr_any := any{data, base_integer_id};
|
|
|
+ ptr: rawptr;
|
|
|
+ switch i in &ptr_any {
|
|
|
+ case u8: ptr = _handle(&i);
|
|
|
+ case u16: ptr = _handle(&i);
|
|
|
+ case u32: ptr = _handle(&i);
|
|
|
+ case u64: ptr = _handle(&i);
|
|
|
+ case i8: ptr = _handle(&i);
|
|
|
+ case i16: ptr = _handle(&i);
|
|
|
+ case i32: ptr = _handle(&i);
|
|
|
+ case i64: ptr = _handle(&i);
|
|
|
+ case u16le: ptr = _handle(&i);
|
|
|
+ case u32le: ptr = _handle(&i);
|
|
|
+ case u64le: ptr = _handle(&i);
|
|
|
+ case i16le: ptr = _handle(&i);
|
|
|
+ case i32le: ptr = _handle(&i);
|
|
|
+ case i64le: ptr = _handle(&i);
|
|
|
+ case u16be: ptr = _handle(&i);
|
|
|
+ case u32be: ptr = _handle(&i);
|
|
|
+ case u64be: ptr = _handle(&i);
|
|
|
+ case i16be: ptr = _handle(&i);
|
|
|
+ case i32be: ptr = _handle(&i);
|
|
|
+ case i64be: ptr = _handle(&i);
|
|
|
+ }
|
|
|
+ return ptr;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
|
|
+ if a == nil { return; }
|
|
|
+ a := a;
|
|
|
+ ti := runtime.type_info_core(type_info_of(a.id));
|
|
|
+ a.id = ti.id;
|
|
|
+
|
|
|
+ #partial switch info in ti.variant {
|
|
|
+ case Type_Info_Pointer:
|
|
|
+ valid = true;
|
|
|
+ value = a.data;
|
|
|
+
|
|
|
+ case Type_Info_String:
|
|
|
+ valid = true;
|
|
|
+ switch v in a {
|
|
|
+ case cstring: value = rawptr(v);
|
|
|
+ case: valid = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ case Type_Info_Relative_Pointer:
|
|
|
+ valid = true;
|
|
|
+ value = relative_pointer_to_absolute_raw(a.data, info.base_integer.id);
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
|
|
+ if a == nil { return; }
|
|
|
+ a := a;
|
|
|
+ ti := runtime.type_info_core(type_info_of(a.id));
|
|
|
+ a.id = ti.id;
|
|
|
+
|
|
|
+ #partial switch info in ti.variant {
|
|
|
+ case Type_Info_String:
|
|
|
+ valid = true;
|
|
|
+ switch v in a {
|
|
|
+ case string: value = raw_data(v);
|
|
|
+ case cstring: value = rawptr(v); // just in case
|
|
|
+ case: valid = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ case Type_Info_Array:
|
|
|
+ valid = true;
|
|
|
+ value = a.data;
|
|
|
+
|
|
|
+ case Type_Info_Slice:
|
|
|
+ valid = true;
|
|
|
+ value = (^mem.Raw_Slice)(a.data).data;
|
|
|
+
|
|
|
+ case Type_Info_Dynamic_Array:
|
|
|
+ valid = true;
|
|
|
+ value = (^mem.Raw_Dynamic_Array)(a.data).data;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|