mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-11 10:29:32 +00:00
90 lines
2.6 KiB
Odin
90 lines
2.6 KiB
Odin
package encoding_json
|
|
|
|
import "base:runtime"
|
|
import "core:strings"
|
|
import "core:io"
|
|
import "core:slice"
|
|
|
|
Unparse_Error :: union #shared_nil {
|
|
io.Error,
|
|
runtime.Allocator_Error,
|
|
}
|
|
|
|
@(require_results)
|
|
unparse :: proc(v: Value, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: string, err: Unparse_Error) {
|
|
b := strings.builder_make(allocator, loc)
|
|
defer if err != nil {
|
|
strings.builder_destroy(&b)
|
|
}
|
|
|
|
// temp guard in case we are sorting map keys, which will use temp allocations
|
|
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
|
|
|
opt := opt
|
|
unparse_to_builder(&b, v, &opt) or_return
|
|
data = string(b.buf[:])
|
|
return
|
|
}
|
|
|
|
@(require_results)
|
|
unparse_to_builder :: proc(b: ^strings.Builder, v: Value, opt: ^Marshal_Options) -> Unparse_Error {
|
|
return unparse_to_writer(strings.to_writer(b), v, opt)
|
|
}
|
|
|
|
@(require_results)
|
|
unparse_to_writer :: proc(w: io.Writer, value: Value, opt: ^Marshal_Options) -> Unparse_Error {
|
|
switch v in value {
|
|
case nil, Null:
|
|
io.write_string(w, "null") or_return
|
|
case Integer:
|
|
base := 16 if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) else 10
|
|
io.write_i64(w, v, base) or_return
|
|
case Float:
|
|
io.write_f64(w, v) or_return
|
|
case Boolean:
|
|
io.write_string(w, "true" if v else "false") or_return
|
|
case String:
|
|
io.write_quoted_string(w, v, '"', nil, true) or_return
|
|
case Array:
|
|
opt_write_start(w, opt, '[') or_return
|
|
for e, i in v {
|
|
opt_write_iteration(w, opt, i == 0) or_return
|
|
unparse_to_writer (w, e, opt) or_return
|
|
}
|
|
opt_write_end(w, opt, ']') or_return
|
|
case Object:
|
|
if !opt.sort_maps_by_key {
|
|
opt_write_start(w, opt, '{') or_return
|
|
for first_iteration := true; key, val in v {
|
|
opt_write_iteration(w, opt, first_iteration) or_return
|
|
opt_write_key (w, opt, key) or_return
|
|
unparse_to_writer (w, val, opt) or_return
|
|
first_iteration = false
|
|
}
|
|
opt_write_end(w, opt, '}') or_return
|
|
} else {
|
|
Map_Entry :: struct {
|
|
key: string,
|
|
value: Value,
|
|
}
|
|
|
|
entries := make([dynamic]Map_Entry, 0, len(v), context.temp_allocator) or_return
|
|
for key, val in v {
|
|
_, _ = append(&entries, Map_Entry{key, val})
|
|
}
|
|
|
|
slice.sort_by(entries[:], proc(i, j: Map_Entry) -> bool { return i.key < j.key })
|
|
|
|
opt_write_start(w, opt, '{') or_return
|
|
for e, i in entries {
|
|
opt_write_iteration(w, opt, i == 0) or_return
|
|
opt_write_key (w, opt, e.key) or_return
|
|
unparse_to_writer (w, e.value, opt) or_return
|
|
}
|
|
opt_write_end(w, opt, '}') or_return
|
|
}
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|