util.odin 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package flags
  2. import "base:runtime"
  3. import "core:fmt"
  4. import "core:mem"
  5. import "core:reflect"
  6. import "core:strconv"
  7. import "core:strings"
  8. import "core:unicode/utf8"
  9. _, _, _, _, _, _, _ :: runtime, fmt, mem, reflect, strconv, strings, utf8
  10. @(private)
  11. parse_and_set_pointer_by_type :: proc(ptr: rawptr, value: string, ti: ^runtime.Type_Info) -> bool {
  12. set_bool :: proc(ptr: rawptr, $T: typeid, str: string) -> bool {
  13. (^T)(ptr)^ = (T)(strconv.parse_bool(str) or_return)
  14. return true
  15. }
  16. set_i128 :: proc(ptr: rawptr, $T: typeid, str: string) -> bool {
  17. value := strconv.parse_i128(str) or_return
  18. if value > cast(i128)max(T) || value < cast(i128)min(T) {
  19. return false
  20. }
  21. (^T)(ptr)^ = (T)(value)
  22. return true
  23. }
  24. set_u128 :: proc(ptr: rawptr, $T: typeid, str: string) -> bool {
  25. value := strconv.parse_u128(str) or_return
  26. if value > cast(u128)max(T) {
  27. return false
  28. }
  29. (^T)(ptr)^ = (T)(value)
  30. return true
  31. }
  32. set_f64 :: proc(ptr: rawptr, $T: typeid, str: string) -> bool {
  33. (^T)(ptr)^ = (T)(strconv.parse_f64(str) or_return)
  34. return true
  35. }
  36. a := any{ptr, ti.id}
  37. #partial switch t in ti.variant {
  38. case runtime.Type_Info_Dynamic_Array:
  39. ptr := (^runtime.Raw_Dynamic_Array)(ptr)
  40. // Try to convert the value first.
  41. elem_backing, mem_err := mem.alloc_bytes(t.elem.size, t.elem.align)
  42. if mem_err != nil {
  43. return false
  44. }
  45. defer delete(elem_backing)
  46. parse_and_set_pointer_by_type(raw_data(elem_backing), value, t.elem) or_return
  47. runtime.__dynamic_array_resize(ptr, t.elem.size, t.elem.align, ptr.len + 1) or_return
  48. subptr := cast(rawptr)(uintptr(ptr.data) + uintptr((ptr.len - 1) * t.elem.size))
  49. mem.copy(subptr, raw_data(elem_backing), len(elem_backing))
  50. case runtime.Type_Info_Boolean:
  51. switch b in a {
  52. case bool: set_bool(ptr, bool, value) or_return
  53. case b8: set_bool(ptr, b8, value) or_return
  54. case b16: set_bool(ptr, b16, value) or_return
  55. case b32: set_bool(ptr, b32, value) or_return
  56. case b64: set_bool(ptr, b64, value) or_return
  57. }
  58. case runtime.Type_Info_Rune:
  59. r := utf8.rune_at_pos(value, 0)
  60. if r == utf8.RUNE_ERROR { return false }
  61. (^rune)(ptr)^ = r
  62. case runtime.Type_Info_String:
  63. switch s in a {
  64. case string: (^string)(ptr)^ = value
  65. case cstring: (^cstring)(ptr)^ = strings.clone_to_cstring(value)
  66. }
  67. case runtime.Type_Info_Integer:
  68. switch i in a {
  69. case int: set_i128(ptr, int, value) or_return
  70. case i8: set_i128(ptr, i8, value) or_return
  71. case i16: set_i128(ptr, i16, value) or_return
  72. case i32: set_i128(ptr, i32, value) or_return
  73. case i64: set_i128(ptr, i64, value) or_return
  74. case i128: set_i128(ptr, i128, value) or_return
  75. case i16le: set_i128(ptr, i16le, value) or_return
  76. case i32le: set_i128(ptr, i32le, value) or_return
  77. case i64le: set_i128(ptr, i64le, value) or_return
  78. case i128le: set_i128(ptr, i128le, value) or_return
  79. case i16be: set_i128(ptr, i16be, value) or_return
  80. case i32be: set_i128(ptr, i32be, value) or_return
  81. case i64be: set_i128(ptr, i64be, value) or_return
  82. case i128be: set_i128(ptr, i128be, value) or_return
  83. case uint: set_u128(ptr, uint, value) or_return
  84. case uintptr: set_u128(ptr, uintptr, value) or_return
  85. case u8: set_u128(ptr, u8, value) or_return
  86. case u16: set_u128(ptr, u16, value) or_return
  87. case u32: set_u128(ptr, u32, value) or_return
  88. case u64: set_u128(ptr, u64, value) or_return
  89. case u128: set_u128(ptr, u128, value) or_return
  90. case u16le: set_u128(ptr, u16le, value) or_return
  91. case u32le: set_u128(ptr, u32le, value) or_return
  92. case u64le: set_u128(ptr, u64le, value) or_return
  93. case u128le: set_u128(ptr, u128le, value) or_return
  94. case u16be: set_u128(ptr, u16be, value) or_return
  95. case u32be: set_u128(ptr, u32be, value) or_return
  96. case u64be: set_u128(ptr, u64be, value) or_return
  97. case u128be: set_u128(ptr, u128be, value) or_return
  98. }
  99. case runtime.Type_Info_Float:
  100. switch f in a {
  101. case f16: set_f64(ptr, f16, value) or_return
  102. case f32: set_f64(ptr, f32, value) or_return
  103. case f64: set_f64(ptr, f64, value) or_return
  104. case f16le: set_f64(ptr, f16le, value) or_return
  105. case f32le: set_f64(ptr, f32le, value) or_return
  106. case f64le: set_f64(ptr, f64le, value) or_return
  107. case f16be: set_f64(ptr, f16be, value) or_return
  108. case f32be: set_f64(ptr, f32be, value) or_return
  109. case f64be: set_f64(ptr, f64be, value) or_return
  110. }
  111. case:
  112. return false
  113. }
  114. return true
  115. }
  116. @(private)
  117. get_struct_subtag :: proc(tag, id: string) -> (value: string, ok: bool) {
  118. tag := tag
  119. for subtag in strings.split_iterator(&tag, ",") {
  120. if equals := strings.index_byte(subtag, '='); equals != -1 && id == subtag[:equals] {
  121. return subtag[1 + equals:], true
  122. } else if id == subtag {
  123. return "", true
  124. }
  125. }
  126. return "", false
  127. }
  128. @(private)
  129. get_field_name :: proc(field: reflect.Struct_Field) -> string {
  130. if args_tag, ok := reflect.struct_tag_lookup(field.tag, TAG_FLAGS); ok {
  131. if name_subtag, name_ok := get_struct_subtag(args_tag, SUBTAG_NAME); name_ok {
  132. return name_subtag
  133. }
  134. }
  135. return field.name
  136. }
  137. // Get a struct field by its field name or "name" subtag.
  138. // NOTE: `Error` uses the `context.temp_allocator` to give context about the error message
  139. get_field_by_name :: proc(data: ^$T, name: string) -> (field: reflect.Struct_Field, err: Error) {
  140. for field in reflect.struct_fields_zipped(T) {
  141. if get_field_name(field) == name {
  142. return field, nil
  143. }
  144. }
  145. return {}, Parse_Error {
  146. .Missing_Field,
  147. fmt.tprintf("unable to find argument by name `%s`", name),
  148. }
  149. }
  150. // Get a struct field by its "pos" subtag.
  151. get_field_by_pos :: proc(data: ^$T, index: int) -> (field: reflect.Struct_Field, ok: bool) {
  152. fields := reflect.struct_fields_zipped(T)
  153. for field in fields {
  154. args_tag := reflect.struct_tag_lookup(field.tag, TAG_FLAGS) or_continue
  155. pos_subtag := get_struct_subtag(args_tag, SUBTAG_POS) or_continue
  156. value := strconv.parse_int(pos_subtag) or_continue
  157. if value == index {
  158. return field, true
  159. }
  160. }
  161. return {}, false
  162. }