Skip to content

Commit

Permalink
added always_omitempty and always_omitnil flags to encoding_json.Mars…
Browse files Browse the repository at this point in the history
…hal_Options
  • Loading branch information
jkenda committed Feb 18, 2025
1 parent f0b1357 commit 9b65f90
Showing 1 changed file with 48 additions and 18 deletions.
66 changes: 48 additions & 18 deletions core/encoding/json/marshal.odin
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ Marshal_Options :: struct {
// NOTE: If a name isn't found it'll use the underlying value.
use_enum_names: bool,

// Always omit empty values including empty (c)strings, (dynamic) arrays,
// slices, unions, bit sets, maps, and nil values.
always_omitempty: bool,

// Always omit nil values.
//
// Doesn't omit empty values, unlike always_omitempty.
always_omitnil: bool,

// Internal state
indentation: int,
mjson_skipped_first_braces_start: bool,
Expand Down Expand Up @@ -345,6 +354,27 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:

case runtime.Type_Info_Struct:
is_omitempty :: proc(v: any) -> bool {
v := v
ti := runtime.type_info_core(type_info_of(v.id))
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch x in v {
case string:
return x == ""
case cstring:
return x == ""
}
case runtime.Type_Info_Dynamic_Array:
return (^runtime.Raw_Dynamic_Array)(v.data).len == 0
case runtime.Type_Info_Slice:
return (^runtime.Raw_Slice)(v.data).len == 0
case runtime.Type_Info_Map:
return (^runtime.Raw_Map)(v.data).len == 0
}
return false
}

is_omitnil :: proc(v: any) -> bool {
v := v
if v == nil {
return true
Expand All @@ -353,57 +383,57 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch x in v {
case string:
return x == ""
case cstring:
return x == nil || x == ""
return x == nil
}
case runtime.Type_Info_Any:
return v.(any) == nil
case runtime.Type_Info_Type_Id:
return v.(typeid) == nil
case runtime.Type_Info_Pointer,
runtime.Type_Info_Multi_Pointer,
runtime.Type_Info_Procedure:
runtime.Type_Info_Multi_Pointer,
runtime.Type_Info_Procedure:
return (^rawptr)(v.data)^ == nil
case runtime.Type_Info_Dynamic_Array:
return (^runtime.Raw_Dynamic_Array)(v.data).len == 0
case runtime.Type_Info_Slice:
return (^runtime.Raw_Slice)(v.data).len == 0
case runtime.Type_Info_Union,
runtime.Type_Info_Bit_Set,
runtime.Type_Info_Soa_Pointer:
runtime.Type_Info_Bit_Set,
runtime.Type_Info_Soa_Pointer:
return reflect.is_nil(v)
case runtime.Type_Info_Map:
return (^runtime.Raw_Map)(v.data).len == 0
}
return false
}


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))
info := ti.variant.(runtime.Type_Info_Struct)
first_iteration := true
for name, i in info.names[:info.field_count] {
omitempty := false
omitempty := opt.always_omitempty
omitnil := opt.always_omitnil || omitempty

json_name, extra := json_name_from_tag_value(reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "json"))

if json_name == "-" {
continue
}

id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
the_value := any{data, id}

for flag in strings.split_iterator(&extra, ",") {
switch flag {
case "omitempty":
omitempty = true
fallthrough
case "omitnil":
omitnil = true
}
}

id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
the_value := any{data, id}

if omitnil && is_omitnil(the_value) {
continue
}
if omitempty && is_omitempty(the_value) {
continue
}
Expand Down

0 comments on commit 9b65f90

Please sign in to comment.