encoding/json: Fix struct marshal() emitting comma after omitted field

Previously:
```odin
package main

import "core:fmt"
import "core:encoding/json"

T :: struct {
	a: string `json:",omitempty"`,
	b: string,
}

main :: proc() {
	data, _ := json.marshal(T{b = "foo"})
	fmt.println(string(data))
}
```
would output:
```
{,"b":"foo"}
```

which is not correct.

Also cleaned up some whitespace while I'm at it.
This commit is contained in:
korvahkh
2024-05-27 16:59:46 -05:00
parent 75f1215ed2
commit a7a6ff8c69
+12 -10
View File
@@ -239,7 +239,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Array: case runtime.Type_Info_Array:
opt_write_start(w, opt, '[') or_return opt_write_start(w, opt, '[') or_return
for i in 0..<info.count { for i in 0..<info.count {
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size) data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
} }
@@ -248,7 +248,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Enumerated_Array: case runtime.Type_Info_Enumerated_Array:
opt_write_start(w, opt, '[') or_return opt_write_start(w, opt, '[') or_return
for i in 0..<info.count { for i in 0..<info.count {
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size) data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
} }
@@ -258,7 +258,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
opt_write_start(w, opt, '[') or_return opt_write_start(w, opt, '[') or_return
array := cast(^mem.Raw_Dynamic_Array)v.data array := cast(^mem.Raw_Dynamic_Array)v.data
for i in 0..<array.len { for i in 0..<array.len {
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
data := uintptr(array.data) + uintptr(i*info.elem_size) data := uintptr(array.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
} }
@@ -268,7 +268,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
opt_write_start(w, opt, '[') or_return opt_write_start(w, opt, '[') or_return
slice := cast(^mem.Raw_Slice)v.data slice := cast(^mem.Raw_Slice)v.data
for i in 0..<slice.len { for i in 0..<slice.len {
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
data := uintptr(slice.data) + uintptr(i*info.elem_size) data := uintptr(slice.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
} }
@@ -290,7 +290,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
for bucket_index in 0..<map_cap { for bucket_index in 0..<map_cap {
runtime.map_hash_is_valid(hs[bucket_index]) or_continue runtime.map_hash_is_valid(hs[bucket_index]) or_continue
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
i += 1 i += 1
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index)) key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
@@ -356,7 +356,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
slice.sort_by(sorted[:], proc(i, j: Entry) -> bool { return i.key < j.key }) slice.sort_by(sorted[:], proc(i, j: Entry) -> bool { return i.key < j.key })
for s, i in sorted { for s, i in sorted {
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, i == 0) or_return
opt_write_key(w, opt, s.key) or_return opt_write_key(w, opt, s.key) or_return
marshal_to_writer(w, s.value, opt) or_return marshal_to_writer(w, s.value, opt) or_return
} }
@@ -405,6 +405,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
marshal_struct_fields :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) { marshal_struct_fields :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
ti := runtime.type_info_base(type_info_of(v.id)) ti := runtime.type_info_base(type_info_of(v.id))
info := ti.variant.(runtime.Type_Info_Struct) info := ti.variant.(runtime.Type_Info_Struct)
first_iteration := true
for name, i in info.names { for name, i in info.names {
omitempty := false omitempty := false
@@ -424,7 +425,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
continue continue
} }
opt_write_iteration(w, opt, i) or_return opt_write_iteration(w, opt, first_iteration) or_return
first_iteration = false
if json_name != "" { if json_name != "" {
opt_write_key(w, opt, json_name) or_return opt_write_key(w, opt, json_name) or_return
} else { } else {
@@ -588,10 +590,10 @@ opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: i
} }
// insert comma separation and write indentations // insert comma separation and write indentations
opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) { opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, first_iteration: bool) -> (err: io.Error) {
switch opt.spec { switch opt.spec {
case .JSON, .JSON5: case .JSON, .JSON5:
if iteration > 0 { if !first_iteration {
io.write_byte(w, ',') or_return io.write_byte(w, ',') or_return
if opt.pretty { if opt.pretty {
@@ -602,7 +604,7 @@ opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int)
opt_write_indentation(w, opt) or_return opt_write_indentation(w, opt) or_return
case .MJSON: case .MJSON:
if iteration > 0 { if !first_iteration {
// on pretty no commas necessary // on pretty no commas necessary
if opt.pretty { if opt.pretty {
io.write_byte(w, '\n') or_return io.write_byte(w, '\n') or_return