marshal.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. package json
  2. import "core:mem"
  3. import "core:math/bits"
  4. import "core:runtime"
  5. import "core:strconv"
  6. import "core:strings"
  7. import "core:reflect"
  8. import "core:io"
  9. Marshal_Data_Error :: enum {
  10. None,
  11. Unsupported_Type,
  12. }
  13. Marshal_Error :: union #shared_nil {
  14. Marshal_Data_Error,
  15. io.Error,
  16. }
  17. // careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results
  18. Marshal_Options :: struct {
  19. // output based on spec
  20. spec: Specification,
  21. // use line breaks & tab|spaces
  22. pretty: bool,
  23. // spacing
  24. use_spaces: bool,
  25. spaces: int,
  26. // state
  27. indentation: int,
  28. // option to output uint in JSON5 & MJSON
  29. write_uint_as_hex: bool,
  30. // mjson output options
  31. mjson_keys_use_quotes: bool,
  32. mjson_keys_use_equal_sign: bool,
  33. // mjson state
  34. mjson_skipped_first_braces_start: bool,
  35. mjson_skipped_first_braces_end: bool,
  36. }
  37. marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
  38. b := strings.builder_make(allocator)
  39. defer if err != nil {
  40. strings.builder_destroy(&b)
  41. }
  42. opt := opt
  43. marshal_to_builder(&b, v, &opt) or_return
  44. if len(b.buf) != 0 {
  45. data = b.buf[:]
  46. }
  47. return data, nil
  48. }
  49. marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> Marshal_Error {
  50. return marshal_to_writer(strings.to_writer(b), v, opt)
  51. }
  52. marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
  53. if v == nil {
  54. io.write_string(w, "null") or_return
  55. return
  56. }
  57. ti := runtime.type_info_base(type_info_of(v.id))
  58. a := any{v.data, ti.id}
  59. switch info in ti.variant {
  60. case runtime.Type_Info_Named:
  61. unreachable()
  62. case runtime.Type_Info_Integer:
  63. buf: [40]byte
  64. u: u128
  65. switch i in a {
  66. case i8: u = u128(i)
  67. case i16: u = u128(i)
  68. case i32: u = u128(i)
  69. case i64: u = u128(i)
  70. case i128: u = u128(i)
  71. case int: u = u128(i)
  72. case u8: u = u128(i)
  73. case u16: u = u128(i)
  74. case u32: u = u128(i)
  75. case u64: u = u128(i)
  76. case u128: u = u128(i)
  77. case uint: u = u128(i)
  78. case uintptr: u = u128(i)
  79. case i16le: u = u128(i)
  80. case i32le: u = u128(i)
  81. case i64le: u = u128(i)
  82. case u16le: u = u128(i)
  83. case u32le: u = u128(i)
  84. case u64le: u = u128(i)
  85. case u128le: u = u128(i)
  86. case i16be: u = u128(i)
  87. case i32be: u = u128(i)
  88. case i64be: u = u128(i)
  89. case u16be: u = u128(i)
  90. case u32be: u = u128(i)
  91. case u64be: u = u128(i)
  92. case u128be: u = u128(i)
  93. }
  94. s: string
  95. // allow uints to be printed as hex
  96. if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
  97. switch i in a {
  98. case u8, u16, u32, u64, u128:
  99. s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
  100. case:
  101. s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
  102. }
  103. } else {
  104. s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
  105. }
  106. io.write_string(w, s) or_return
  107. case runtime.Type_Info_Rune:
  108. r := a.(rune)
  109. io.write_byte(w, '"') or_return
  110. io.write_escaped_rune(w, r, '"', true) or_return
  111. io.write_byte(w, '"') or_return
  112. case runtime.Type_Info_Float:
  113. switch f in a {
  114. case f16: io.write_f16(w, f) or_return
  115. case f32: io.write_f32(w, f) or_return
  116. case f64: io.write_f64(w, f) or_return
  117. case: return .Unsupported_Type
  118. }
  119. case runtime.Type_Info_Complex:
  120. r, i: f64
  121. switch z in a {
  122. case complex32: r, i = f64(real(z)), f64(imag(z))
  123. case complex64: r, i = f64(real(z)), f64(imag(z))
  124. case complex128: r, i = f64(real(z)), f64(imag(z))
  125. case: return .Unsupported_Type
  126. }
  127. io.write_byte(w, '[') or_return
  128. io.write_f64(w, r) or_return
  129. io.write_string(w, ", ") or_return
  130. io.write_f64(w, i) or_return
  131. io.write_byte(w, ']') or_return
  132. case runtime.Type_Info_Quaternion:
  133. return .Unsupported_Type
  134. case runtime.Type_Info_String:
  135. switch s in a {
  136. case string: io.write_quoted_string(w, s, '"', nil, true) or_return
  137. case cstring: io.write_quoted_string(w, string(s), '"', nil, true) or_return
  138. }
  139. case runtime.Type_Info_Boolean:
  140. val: bool
  141. switch b in a {
  142. case bool: val = bool(b)
  143. case b8: val = bool(b)
  144. case b16: val = bool(b)
  145. case b32: val = bool(b)
  146. case b64: val = bool(b)
  147. }
  148. io.write_string(w, val ? "true" : "false") or_return
  149. case runtime.Type_Info_Any:
  150. return .Unsupported_Type
  151. case runtime.Type_Info_Type_Id:
  152. return .Unsupported_Type
  153. case runtime.Type_Info_Pointer:
  154. return .Unsupported_Type
  155. case runtime.Type_Info_Multi_Pointer:
  156. return .Unsupported_Type
  157. case runtime.Type_Info_Soa_Pointer:
  158. return .Unsupported_Type
  159. case runtime.Type_Info_Procedure:
  160. return .Unsupported_Type
  161. case runtime.Type_Info_Parameters:
  162. return .Unsupported_Type
  163. case runtime.Type_Info_Simd_Vector:
  164. return .Unsupported_Type
  165. case runtime.Type_Info_Relative_Pointer:
  166. return .Unsupported_Type
  167. case runtime.Type_Info_Relative_Multi_Pointer:
  168. return .Unsupported_Type
  169. case runtime.Type_Info_Matrix:
  170. return .Unsupported_Type
  171. case runtime.Type_Info_Array:
  172. opt_write_start(w, opt, '[') or_return
  173. for i in 0..<info.count {
  174. opt_write_iteration(w, opt, i) or_return
  175. data := uintptr(v.data) + uintptr(i*info.elem_size)
  176. marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
  177. }
  178. opt_write_end(w, opt, ']') or_return
  179. case runtime.Type_Info_Enumerated_Array:
  180. index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
  181. opt_write_start(w, opt, '[') or_return
  182. for i in 0..<info.count {
  183. opt_write_iteration(w, opt, i) or_return
  184. data := uintptr(v.data) + uintptr(i*info.elem_size)
  185. marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
  186. }
  187. opt_write_end(w, opt, ']') or_return
  188. case runtime.Type_Info_Dynamic_Array:
  189. opt_write_start(w, opt, '[') or_return
  190. array := cast(^mem.Raw_Dynamic_Array)v.data
  191. for i in 0..<array.len {
  192. opt_write_iteration(w, opt, i) or_return
  193. data := uintptr(array.data) + uintptr(i*info.elem_size)
  194. marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
  195. }
  196. opt_write_end(w, opt, ']') or_return
  197. case runtime.Type_Info_Slice:
  198. opt_write_start(w, opt, '[') or_return
  199. slice := cast(^mem.Raw_Slice)v.data
  200. for i in 0..<slice.len {
  201. opt_write_iteration(w, opt, i) or_return
  202. data := uintptr(slice.data) + uintptr(i*info.elem_size)
  203. marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
  204. }
  205. opt_write_end(w, opt, ']') or_return
  206. case runtime.Type_Info_Map:
  207. m := (^mem.Raw_Map)(v.data)
  208. opt_write_start(w, opt, '{') or_return
  209. if m != nil {
  210. if info.map_info == nil {
  211. return .Unsupported_Type
  212. }
  213. map_cap := uintptr(runtime.map_cap(m^))
  214. ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
  215. i := 0
  216. for bucket_index in 0..<map_cap {
  217. runtime.map_hash_is_valid(hs[bucket_index]) or_continue
  218. opt_write_iteration(w, opt, i) or_return
  219. i += 1
  220. key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
  221. value := rawptr(runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index))
  222. // check for string type
  223. {
  224. v := any{key, info.key.id}
  225. ti := runtime.type_info_base(type_info_of(v.id))
  226. a := any{v.data, ti.id}
  227. name: string
  228. #partial switch info in ti.variant {
  229. case runtime.Type_Info_String:
  230. switch s in a {
  231. case string: name = s
  232. case cstring: name = string(s)
  233. }
  234. opt_write_key(w, opt, name) or_return
  235. case: return .Unsupported_Type
  236. }
  237. }
  238. marshal_to_writer(w, any{value, info.value.id}, opt) or_return
  239. }
  240. }
  241. opt_write_end(w, opt, '}') or_return
  242. case runtime.Type_Info_Struct:
  243. opt_write_start(w, opt, '{') or_return
  244. for name, i in info.names {
  245. opt_write_iteration(w, opt, i) or_return
  246. if json_name := string(reflect.struct_tag_get(auto_cast info.tags[i], "json")); json_name != "" {
  247. opt_write_key(w, opt, json_name) or_return
  248. } else {
  249. opt_write_key(w, opt, name) or_return
  250. }
  251. id := info.types[i].id
  252. data := rawptr(uintptr(v.data) + info.offsets[i])
  253. marshal_to_writer(w, any{data, id}, opt) or_return
  254. }
  255. opt_write_end(w, opt, '}') or_return
  256. case runtime.Type_Info_Union:
  257. tag_ptr := uintptr(v.data) + info.tag_offset
  258. tag_any := any{rawptr(tag_ptr), info.tag_type.id}
  259. tag: i64 = -1
  260. switch i in tag_any {
  261. case u8: tag = i64(i)
  262. case i8: tag = i64(i)
  263. case u16: tag = i64(i)
  264. case i16: tag = i64(i)
  265. case u32: tag = i64(i)
  266. case i32: tag = i64(i)
  267. case u64: tag = i64(i)
  268. case i64: tag = i64(i)
  269. case: panic("Invalid union tag type")
  270. }
  271. if v.data == nil || tag == 0 {
  272. io.write_string(w, "null") or_return
  273. } else {
  274. id := info.variants[tag-1].id
  275. return marshal_to_writer(w, any{v.data, id}, opt)
  276. }
  277. case runtime.Type_Info_Enum:
  278. return marshal_to_writer(w, any{v.data, info.base.id}, opt)
  279. case runtime.Type_Info_Bit_Set:
  280. is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
  281. if ti == nil {
  282. return false
  283. }
  284. t := runtime.type_info_base(ti)
  285. #partial switch info in t.variant {
  286. case runtime.Type_Info_Integer:
  287. switch info.endianness {
  288. case .Platform: return false
  289. case .Little: return ODIN_ENDIAN != .Little
  290. case .Big: return ODIN_ENDIAN != .Big
  291. }
  292. }
  293. return false
  294. }
  295. bit_data: u64
  296. bit_size := u64(8*ti.size)
  297. do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying)
  298. switch bit_size {
  299. case 0: bit_data = 0
  300. case 8:
  301. x := (^u8)(v.data)^
  302. bit_data = u64(x)
  303. case 16:
  304. x := (^u16)(v.data)^
  305. if do_byte_swap {
  306. x = bits.byte_swap(x)
  307. }
  308. bit_data = u64(x)
  309. case 32:
  310. x := (^u32)(v.data)^
  311. if do_byte_swap {
  312. x = bits.byte_swap(x)
  313. }
  314. bit_data = u64(x)
  315. case 64:
  316. x := (^u64)(v.data)^
  317. if do_byte_swap {
  318. x = bits.byte_swap(x)
  319. }
  320. bit_data = u64(x)
  321. case: panic("unknown bit_size size")
  322. }
  323. io.write_u64(w, bit_data) or_return
  324. return .Unsupported_Type
  325. }
  326. return
  327. }
  328. // write key as quoted string or with optional quotes in mjson
  329. opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) {
  330. switch opt.spec {
  331. case .JSON, .JSON5:
  332. io.write_quoted_string(w, name) or_return
  333. io.write_string(w, ": " if opt.pretty else ":") or_return
  334. case .MJSON:
  335. if opt.mjson_keys_use_quotes {
  336. io.write_quoted_string(w, name) or_return
  337. } else {
  338. io.write_string(w, name) or_return
  339. }
  340. if opt.mjson_keys_use_equal_sign {
  341. io.write_string(w, " = " if opt.pretty else "=") or_return
  342. } else {
  343. io.write_string(w, ": " if opt.pretty else ":") or_return
  344. }
  345. }
  346. return
  347. }
  348. // insert start byte and increase indentation on pretty
  349. opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
  350. // skip mjson starting braces
  351. if opt.spec == .MJSON && !opt.mjson_skipped_first_braces_start {
  352. opt.mjson_skipped_first_braces_start = true
  353. return
  354. }
  355. io.write_byte(w, c) or_return
  356. opt.indentation += 1
  357. if opt.pretty {
  358. io.write_byte(w, '\n') or_return
  359. }
  360. return
  361. }
  362. // insert comma separation and write indentations
  363. opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) {
  364. switch opt.spec {
  365. case .JSON, .JSON5:
  366. if iteration > 0 {
  367. io.write_byte(w, ',') or_return
  368. if opt.pretty {
  369. io.write_byte(w, '\n') or_return
  370. }
  371. }
  372. opt_write_indentation(w, opt) or_return
  373. case .MJSON:
  374. if iteration > 0 {
  375. // on pretty no commas necessary
  376. if opt.pretty {
  377. io.write_byte(w, '\n') or_return
  378. } else {
  379. // comma separation necessary for non pretty output!
  380. io.write_byte(w, ',') or_return
  381. }
  382. }
  383. opt_write_indentation(w, opt) or_return
  384. }
  385. return
  386. }
  387. // decrease indent, write spacing and insert end byte
  388. opt_write_end :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
  389. if opt.spec == .MJSON && opt.mjson_skipped_first_braces_start && !opt.mjson_skipped_first_braces_end {
  390. if opt.indentation == 0 {
  391. opt.mjson_skipped_first_braces_end = true
  392. return
  393. }
  394. }
  395. opt.indentation -= 1
  396. if opt.pretty {
  397. io.write_byte(w, '\n') or_return
  398. opt_write_indentation(w, opt) or_return
  399. }
  400. io.write_byte(w, c) or_return
  401. return
  402. }
  403. // writes current indentation level based on options
  404. opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.Error) {
  405. if !opt.pretty {
  406. return
  407. }
  408. if opt.use_spaces {
  409. spaces := opt.spaces == 0 ? 4 : opt.spaces
  410. for _ in 0..<opt.indentation * spaces {
  411. io.write_byte(w, ' ') or_return
  412. }
  413. } else {
  414. for _ in 0..<opt.indentation {
  415. io.write_byte(w, '\t') or_return
  416. }
  417. }
  418. return
  419. }