package reflect import "core:runtime" import "core:mem" import "intrinsics" _ :: intrinsics; Type_Info :: runtime.Type_Info; Type_Info_Named :: runtime.Type_Info_Named; Type_Info_Integer :: runtime.Type_Info_Integer; Type_Info_Rune :: runtime.Type_Info_Rune; Type_Info_Float :: runtime.Type_Info_Float; Type_Info_Complex :: runtime.Type_Info_Complex; Type_Info_Quaternion :: runtime.Type_Info_Quaternion; Type_Info_String :: runtime.Type_Info_String; Type_Info_Boolean :: runtime.Type_Info_Boolean; Type_Info_Any :: runtime.Type_Info_Any; Type_Info_Type_Id :: runtime.Type_Info_Type_Id; Type_Info_Pointer :: runtime.Type_Info_Pointer; Type_Info_Procedure :: runtime.Type_Info_Procedure; Type_Info_Array :: runtime.Type_Info_Array; Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array; Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array; Type_Info_Slice :: runtime.Type_Info_Slice; Type_Info_Tuple :: runtime.Type_Info_Tuple; Type_Info_Struct :: runtime.Type_Info_Struct; Type_Info_Union :: runtime.Type_Info_Union; Type_Info_Enum :: runtime.Type_Info_Enum; Type_Info_Map :: runtime.Type_Info_Map; Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set; Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector; Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer; Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice; Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value; Type_Kind :: enum { Invalid, Named, Integer, Rune, Float, Complex, Quaternion, String, Boolean, Any, Type_Id, Pointer, Procedure, Array, Enumerated_Array, Dynamic_Array, Slice, Tuple, Struct, Union, Enum, Map, Bit_Set, Simd_Vector, Relative_Pointer, Relative_Slice, } type_kind :: proc(T: typeid) -> Type_Kind { ti := type_info_of(T); if ti != nil { switch _ in ti.variant { case Type_Info_Named: return .Named; case Type_Info_Integer: return .Integer; case Type_Info_Rune: return .Rune; case Type_Info_Float: return .Float; case Type_Info_Complex: return .Complex; case Type_Info_Quaternion: return .Quaternion; case Type_Info_String: return .String; case Type_Info_Boolean: return .Boolean; case Type_Info_Any: return .Any; case Type_Info_Type_Id: return .Type_Id; case Type_Info_Pointer: return .Pointer; case Type_Info_Procedure: return .Procedure; case Type_Info_Array: return .Array; case Type_Info_Enumerated_Array: return .Enumerated_Array; case Type_Info_Dynamic_Array: return .Dynamic_Array; case Type_Info_Slice: return .Slice; case Type_Info_Tuple: return .Tuple; case Type_Info_Struct: return .Struct; case Type_Info_Union: return .Union; case Type_Info_Enum: return .Enum; case Type_Info_Map: return .Map; case Type_Info_Bit_Set: return .Bit_Set; case Type_Info_Simd_Vector: return .Simd_Vector; case Type_Info_Relative_Pointer: return .Relative_Pointer; case Type_Info_Relative_Slice: return .Relative_Slice; } } 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)); } type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { if info == nil { return nil; } base := info; loop: for { #partial switch i in base.variant { case Type_Info_Named: base = i.base; case: break loop; } } return base; } type_info_core :: proc(info: ^Type_Info) -> ^Type_Info { if info == nil { return nil; } base := info; loop: for { #partial switch i in base.variant { case Type_Info_Named: base = i.base; case Type_Info_Enum: base = i.base; case: break loop; } } return base; } type_info_base_without_enum :: type_info_core; typeid_base :: proc(id: typeid) -> typeid { ti := type_info_of(id); ti = type_info_base(ti); return ti.id; } typeid_core :: proc(id: typeid) -> typeid { ti := type_info_base_without_enum(type_info_of(id)); return ti.id; } typeid_base_without_enum :: typeid_core; typeid_elem :: proc(id: typeid) -> typeid { ti := type_info_of(id); if ti == nil { return nil; } bits := 8*ti.size; #partial switch v in ti.variant { case Type_Info_Complex: switch bits { case 64: return f32; case 128: return f64; } case Type_Info_Quaternion: switch bits { case 128: return f32; case 256: return f64; } case Type_Info_Pointer: return v.elem.id; case Type_Info_Array: return v.elem.id; case Type_Info_Enumerated_Array: return v.elem.id; case Type_Info_Slice: return v.elem.id; case Type_Info_Dynamic_Array: return v.elem.id; } return id; } 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; } as_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 :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) { return v.data, v.id; } is_nil :: proc(v: any) -> bool { if v == nil { return true; } data := as_bytes(v); if data != nil { return true; } for v in data { if v != 0 { return false; } } return true; } length :: proc(val: any) -> int { if val == nil { return 0; } #partial switch a in type_info_of(val.id).variant { case Type_Info_Named: return length({val.data, a.base.id}); case Type_Info_Pointer: return length({val.data, a.elem.id}); case Type_Info_Array: return a.count; case Type_Info_Enumerated_Array: return a.count; case Type_Info_Slice: return (^mem.Raw_Slice)(val.data).len; case Type_Info_Dynamic_Array: return (^mem.Raw_Dynamic_Array)(val.data).len; case Type_Info_Map: return (^mem.Raw_Map)(val.data).entries.len; case Type_Info_String: if a.is_cstring { return len((^cstring)(val.data)^); } else { return (^mem.Raw_String)(val.data).len; } } return 0; } capacity :: proc(val: any) -> int { if val == nil { return 0; } #partial switch a in type_info_of(val.id).variant { case Type_Info_Named: return capacity({val.data, a.base.id}); case Type_Info_Pointer: return capacity({val.data, a.elem.id}); case Type_Info_Array: return a.count; case Type_Info_Enumerated_Array: return a.count; case Type_Info_Dynamic_Array: return (^mem.Raw_Dynamic_Array)(val.data).cap; case Type_Info_Map: return (^mem.Raw_Map)(val.data).entries.cap; } return 0; } index :: proc(val: any, i: int, loc := #caller_location) -> any { if val == nil { return nil; } #partial switch a in type_info_of(val.id).variant { case Type_Info_Named: return index({val.data, a.base.id}, i, loc); case Type_Info_Pointer: ptr := (^rawptr)(val.data)^; if ptr == nil { return nil; } return index({ptr, a.elem.id}, i, loc); case Type_Info_Array: runtime.bounds_check_error_loc(loc, i, a.count); offset := uintptr(a.elem.size * i); data := rawptr(uintptr(val.data) + offset); return any{data, a.elem.id}; case Type_Info_Enumerated_Array: runtime.bounds_check_error_loc(loc, i, a.count); offset := uintptr(a.elem.size * i); data := rawptr(uintptr(val.data) + offset); return any{data, a.elem.id}; case Type_Info_Slice: raw := (^mem.Raw_Slice)(val.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 Type_Info_Dynamic_Array: raw := (^mem.Raw_Dynamic_Array)(val.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 Type_Info_String: if a.is_cstring { return nil; } raw := (^mem.Raw_String)(val.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 represents the type of the string of a struct field // // Through convention, tags are the concatenation of optionally space separationed key:"value" pairs. // Each key is a non-empty string which contains no control characters other than space, quotes, and colon. Struct_Tag :: distinct string; Struct_Field :: struct { name: string, type: ^Type_Info, tag: Struct_Tag, offset: uintptr, is_using: bool, } 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]; field.tag = Struct_Tag(s.tags[i]); field.offset = s.offsets[i]; field.is_using = s.usings[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]; field.tag = Struct_Tag(s.tags[i]); field.offset = s.offsets[i]; field.is_using = s.usings[i]; break; } } } return; } struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any { if a == nil { 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 allow_using && 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, allow_using); 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) -> []^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_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) { ti := runtime.type_info_base(type_info_of(T)); if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { return soa_zip( name = s.names, type = s.types, tag = transmute([]Struct_Tag)s.tags, offset = s.offsets, is_using = s.usings, ); } return nil; } struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) { value, _ = struct_tag_lookup(tag, key); return; } struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, 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 { 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 { break; } if i+1 >= len(t) { 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] == '\\' { i += 1; // Skip escaped characters } i += 1; } if i >= len(t) { break; } val := string(t[:i+1]); t = t[i+1:]; if key == name { return Struct_Tag(val[1:i]), true; } } return; } enum_string :: proc(a: any) -> string { if a == nil { return ""; } ti := runtime.type_info_base(type_info_of(a.id)); if e, ok := ti.variant.(runtime.Type_Info_Enum); ok { v, _ := as_i64(a); for value, i in e.values { if value == Type_Info_Enum_Value(v) { return e.names[i]; } } } else { panic("expected an enum to reflect.enum_string"); } return ""; } // Given a enum type and a value name, get the enum value. enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) { ti := type_info_base(type_info_of(Enum_Type)); if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok { for value_name, i in eti.names { if value_name != name { continue; } v := eti.values[i]; value = Enum_Type(v); ok = true; return; } } return; } enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) { ti := runtime.type_info_base(type_info_of(Enum_Type)); if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok { for value_name, i in eti.names { if value_name != name { continue; } value = eti.values[i]; ok = true; return; } } return; } enum_field_names :: proc(Enum_Type: typeid) -> []string { ti := runtime.type_info_base(type_info_of(Enum_Type)); if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok { return eti.names; } return nil; } enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value { ti := runtime.type_info_base(type_info_of(Enum_Type)); if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok { return eti.values; } return nil; } Enum_Field :: struct { name: string, value: Type_Info_Enum_Value, } enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) { ti := runtime.type_info_base(type_info_of(Enum_Type)); if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok { return soa_zip(name=eti.names, value=eti.values); } return nil; } union_variant_type_info :: proc(a: any) -> ^Type_Info { id := union_variant_typeid(a); 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}; 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 = i; case: unimplemented(); } if a.data != nil && tag != 0 { i := tag if info.no_nil else tag-1; return info.variants[i].id; } return nil; } panic("expected a union to reflect.union_variant_typeid"); } 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 = 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 = 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 = 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; v, valid = as_i64(a); value = int(v); return; } as_uint :: proc(a: any) -> (value: uint, valid: bool) { v: u64; v, valid = as_u64(a); value = uint(v); return; } as_i64 :: proc(a: any) -> (value: i64, 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_Integer: valid = true; switch v in a { case i8: value = i64(v); case i16: value = i64(v); case i32: value = i64(v); case i64: value = v; case i128: value = i64(v); case int: value = i64(v); case u8: value = i64(v); case u16: value = i64(v); case u32: value = i64(v); case u64: value = i64(v); case u128: value = i64(v); case uint: value = i64(v); case uintptr: value = i64(v); case u16le: value = i64(v); case u32le: value = i64(v); case u64le: value = i64(v); case u128le: value = i64(v); case i16le: value = i64(v); case i32le: value = i64(v); case i64le: value = i64(v); case i128le: value = i64(v); case u16be: value = i64(v); case u32be: value = i64(v); case u64be: value = i64(v); case u128be: value = i64(v); case i16be: value = i64(v); case i32be: value = i64(v); case i64be: value = i64(v); case i128be: value = i64(v); case: valid = false; } case Type_Info_Rune: r := a.(rune); value = i64(r); valid = true; case Type_Info_Float: valid = true; switch v in a { case f32: value = i64(v); case f64: value = i64(v); case f32le: value = i64(v); case f64le: value = i64(v); case f32be: value = i64(v); case f64be: value = i64(v); case: valid = false; } case Type_Info_Boolean: valid = true; switch v in a { case bool: value = i64(v); case b8: value = i64(v); case b16: value = i64(v); case b32: value = i64(v); case b64: value = i64(v); case: valid = false; } case Type_Info_Complex: switch v in a { case complex64: if imag(v) == 0 { value = i64(real(v)); valid = true; } case complex128: if imag(v) == 0 { value = i64(real(v)); valid = true; } } case Type_Info_Quaternion: switch v in a { case quaternion128: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = i64(real(v)); valid = true; } case quaternion256: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = i64(real(v)); valid = true; } } } return; } as_u64 :: proc(a: any) -> (value: u64, 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_Integer: valid = true; switch v in a { case i8: value = u64(v); case i16: value = u64(v); case i32: value = u64(v); case i64: value = u64(v); case i128: value = u64(v); case int: value = u64(v); case u8: value = u64(v); case u16: value = u64(v); case u32: value = u64(v); case u64: value = (v); case u128: value = u64(v); case uint: value = u64(v); case uintptr:value = u64(v); case u16le: value = u64(v); case u32le: value = u64(v); case u64le: value = u64(v); case u128le: value = u64(v); case i16le: value = u64(v); case i32le: value = u64(v); case i64le: value = u64(v); case i128le: value = u64(v); case u16be: value = u64(v); case u32be: value = u64(v); case u64be: value = u64(v); case u128be: value = u64(v); case i16be: value = u64(v); case i32be: value = u64(v); case i64be: value = u64(v); case i128be: value = u64(v); case: valid = false; } case Type_Info_Rune: r := a.(rune); value = u64(r); valid = true; case Type_Info_Float: valid = true; switch v in a { case f32: value = u64(v); case f64: value = u64(v); case f32le: value = u64(v); case f64le: value = u64(v); case f32be: value = u64(v); case f64be: value = u64(v); case: valid = false; } case Type_Info_Boolean: valid = true; switch v in a { case bool: value = u64(v); case b8: value = u64(v); case b16: value = u64(v); case b32: value = u64(v); case b64: value = u64(v); case: valid = false; } case Type_Info_Complex: switch v in a { case complex64: if imag(v) == 0 { value = u64(real(v)); valid = true; } case complex128: if imag(v) == 0 { value = u64(real(v)); valid = true; } } case Type_Info_Quaternion: switch v in a { case quaternion128: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = u64(real(v)); valid = true; } case quaternion256: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = u64(real(v)); valid = true; } } } return; } as_f64 :: proc(a: any) -> (value: f64, 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_Integer: valid = true; switch v in a { case i8: value = f64(v); case i16: value = f64(v); case i32: value = f64(v); case i64: value = f64(v); case i128: value = f64(v); case u8: value = f64(v); case u16: value = f64(v); case u32: value = f64(v); case u64: value = f64(v); case u128: value = f64(v); case u16le: value = f64(v); case u32le: value = f64(v); case u64le: value = f64(v); case u128le:value = f64(v); case i16le: value = f64(v); case i32le: value = f64(v); case i64le: value = f64(v); case i128le:value = f64(v); case u16be: value = f64(v); case u32be: value = f64(v); case u64be: value = f64(v); case u128be:value = f64(v); case i16be: value = f64(v); case i32be: value = f64(v); case i64be: value = f64(v); case i128be:value = f64(v); case: valid = false; } case Type_Info_Rune: r := a.(rune); value = f64(i32(r)); valid = true; case Type_Info_Float: valid = true; switch v in a { case f32: value = f64(v); case f64: value = (v); case f32le: value = f64(v); case f64le: value = f64(v); case f32be: value = f64(v); case f64be: value = f64(v); case: valid = false; } case Type_Info_Boolean: valid = true; switch v in a { case bool: value = f64(i32(v)); case b8: value = f64(i32(v)); case b16: value = f64(i32(v)); case b32: value = f64(i32(v)); case b64: value = f64(i32(v)); case: valid = false; } case Type_Info_Complex: switch v in a { case complex64: if imag(v) == 0 { value = f64(real(v)); valid = true; } case complex128: if imag(v) == 0 { value = real(v); valid = true; } } case Type_Info_Quaternion: switch v in a { case quaternion128: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = f64(real(v)); valid = true; } case quaternion256: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = real(v); valid = true; } } } 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 = 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; } /* not_equal :: proc(a, b: any) -> bool { return !equal(a, b); } equal :: proc(a, b: any) -> bool { if a == nil && b == nil { return true; } if a.id != b.id { return false; } if a.data == b.data { return true; } t := type_info_of(a.id); if .Comparable not_in t.flags { return false; } if t.size == 0 { return true; } if .Simple_Compare in t.flags { return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0; } t = runtime.type_info_core(t); #partial switch v in t.variant { case Type_Info_String: if v.is_cstring { x := string((^cstring)(a.data)^); y := string((^cstring)(b.data)^); return x == y; } else { x := (^string)(a.data)^; y := (^string)(b.data)^; return x == y; } case Type_Info_Array: for i in 0..