From 414566966d92d3e4d9ab2d36f6297fe830f044ed Mon Sep 17 00:00:00 2001 From: Hitalo Souza <63821277+enghitalo@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:15:07 -0400 Subject: [PATCH] Json2: reorganizing functions in files (#20832) --- vlib/x/json2/decoder.v | 155 ++++++++++++++++++++++++++++++++ vlib/x/json2/encoder.v | 45 ++++++++++ vlib/x/json2/json2.v | 198 ----------------------------------------- 3 files changed, 200 insertions(+), 198 deletions(-) diff --git a/vlib/x/json2/decoder.v b/vlib/x/json2/decoder.v index 6464c65e5eb328..d255a5430bc13a 100644 --- a/vlib/x/json2/decoder.v +++ b/vlib/x/json2/decoder.v @@ -3,6 +3,8 @@ // that can be found in the LICENSE file. module json2 +import time + fn format_message(msg string, line int, column int) string { return '[x.json2] ${msg} (${line}:${column})' } @@ -117,6 +119,159 @@ fn new_parser(srce string, convert_type bool) Parser { } } +// Decodes a JSON string into an `Any` type. Returns an option. +pub fn raw_decode(src string) !Any { + mut p := new_parser(src, true) + return p.decode() +} + +// Same with `raw_decode`, but skips the type conversion for certain types when decoding a certain value. +pub fn fast_raw_decode(src string) !Any { + mut p := new_parser(src, false) + return p.decode() +} + +// decode is a generic function that decodes a JSON string into the target type. +pub fn decode[T](src string) !T { + res := raw_decode(src)!.as_map() + return decode_struct[T](T{}, res) +} + +// decode_struct is a generic function that decodes a JSON map into the struct T. +fn decode_struct[T](_ T, res map[string]Any) !T { + mut typ := T{} + $if T is $struct { + $for field in T.fields { + mut json_name := field.name + for attr in field.attrs { + if attr.contains('json: ') { + json_name = attr.replace('json: ', '') + break + } + } + + $if field.is_enum { + if v := res[json_name] { + typ.$(field.name) = v.int() + } else { + $if field.is_option { + typ.$(field.name) = none + } + } + } $else $if field.typ is u8 { + typ.$(field.name) = res[json_name]!.u64() + } $else $if field.typ is u16 { + typ.$(field.name) = res[json_name]!.u64() + } $else $if field.typ is u32 { + typ.$(field.name) = res[json_name]!.u64() + } $else $if field.typ is u64 { + typ.$(field.name) = res[json_name]!.u64() + } $else $if field.typ is int { + typ.$(field.name) = res[json_name]!.int() + } $else $if field.typ is i8 { + typ.$(field.name) = res[json_name]!.int() + } $else $if field.typ is i16 { + typ.$(field.name) = res[json_name]!.int() + } $else $if field.typ is i32 { + typ.$(field.name) = i32(res[field.name]!.int()) + } $else $if field.typ is i64 { + typ.$(field.name) = res[json_name]!.i64() + } $else $if field.typ is ?u8 { + if json_name in res { + typ.$(field.name) = ?u8(res[json_name]!.i64()) + } + } $else $if field.typ is ?i8 { + if json_name in res { + typ.$(field.name) = ?i8(res[json_name]!.i64()) + } + } $else $if field.typ is ?u16 { + if json_name in res { + typ.$(field.name) = ?u16(res[json_name]!.i64()) + } + } $else $if field.typ is ?i16 { + if json_name in res { + typ.$(field.name) = ?i16(res[json_name]!.i64()) + } + } $else $if field.typ is ?u32 { + if json_name in res { + typ.$(field.name) = ?u32(res[json_name]!.i64()) + } + } $else $if field.typ is ?i32 { + if json_name in res { + typ.$(field.name) = ?i32(res[json_name]!.i64()) + } + } $else $if field.typ is ?u64 { + if json_name in res { + typ.$(field.name) = ?u64(res[json_name]!.i64()) + } + } $else $if field.typ is ?i64 { + if json_name in res { + typ.$(field.name) = ?i64(res[json_name]!.i64()) + } + } $else $if field.typ is ?int { + if json_name in res { + typ.$(field.name) = ?int(res[json_name]!.i64()) + } + } $else $if field.typ is f32 { + typ.$(field.name) = res[json_name]!.f32() + } $else $if field.typ is ?f32 { + if json_name in res { + typ.$(field.name) = res[json_name]!.f32() + } + } $else $if field.typ is f64 { + typ.$(field.name) = res[json_name]!.f64() + } $else $if field.typ is ?f64 { + if json_name in res { + typ.$(field.name) = res[json_name]!.f64() + } + } $else $if field.typ is bool { + typ.$(field.name) = res[json_name]!.bool() + } $else $if field.typ is ?bool { + if json_name in res { + typ.$(field.name) = res[json_name]!.bool() + } + } $else $if field.typ is string { + typ.$(field.name) = res[json_name]!.str() + } $else $if field.typ is ?string { + if json_name in res { + typ.$(field.name) = res[json_name]!.str() + } + } $else $if field.typ is time.Time { + typ.$(field.name) = res[json_name]!.to_time()! + } $else $if field.typ is ?time.Time { + if json_name in res { + typ.$(field.name) = res[json_name]!.to_time()! + } + } $else $if field.is_array { + } $else $if field.is_struct { + typ.$(field.name) = decode_struct(typ.$(field.name), res[field.name]!.as_map())! + } $else $if field.is_alias { + } $else $if field.is_map { + } $else { + return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose") + } + } + } $else $if T is $map { + for k, v in res { + // // TODO - make this work to decode types like `map[string]StructType[bool]` + // $if typeof(typ[k]).idx is string { + // typ[k] = v.str() + // } $else $if typeof(typ[k]).idx is $struct { + + // } + match v { + string { + typ[k] = v.str() + } + else {} + } + } + } $else { + return error("The type `${T.name}` can't be decoded.") + } + return typ +} + // decode - decodes provided JSON pub fn (mut p Parser) decode() !Any { p.next() diff --git a/vlib/x/json2/encoder.v b/vlib/x/json2/encoder.v index 5f53173edb1df3..25c1eb2ff31f50 100644 --- a/vlib/x/json2/encoder.v +++ b/vlib/x/json2/encoder.v @@ -36,6 +36,51 @@ const curly_open_rune = `{` const curly_close_rune = `}` +// encode is a generic function that encodes a type into a JSON string. +pub fn encode[T](val T) string { + $if T is $array { + return encode_array(val) + } $else { + mut buf := []u8{} + + defer { + unsafe { buf.free() } + } + encoder := Encoder{} + + encoder.encode_value(val, mut buf) or { + println(err) + encoder.encode_value[string]('null', mut buf) or {} + } + + return buf.bytestr() + } +} + +// encode_array is a generic function that encodes a array into a JSON string. +fn encode_array[T](val []T) string { + mut buf := []u8{} + + defer { + unsafe { buf.free() } + } + + encoder := Encoder{} + encoder.encode_array(val, 1, mut buf) or { + println(err) + encoder.encode_value[string]('null', mut buf) or {} + } + + return buf.bytestr() +} + +// encode_pretty ... +pub fn encode_pretty[T](typed_data T) string { + encoded := encode(typed_data) + raw_decoded := raw_decode(encoded) or { 0 } + return raw_decoded.prettify_json_str() +} + // encode_value encodes a value to the specific buffer. pub fn (e &Encoder) encode_value[T](val T, mut buf []u8) ! { e.encode_value_with_level[T](val, 1, mut buf)! diff --git a/vlib/x/json2/json2.v b/vlib/x/json2/json2.v index 969328f34e4a61..2cf3890a876e10 100644 --- a/vlib/x/json2/json2.v +++ b/vlib/x/json2/json2.v @@ -5,204 +5,6 @@ module json2 import time -// Decodes a JSON string into an `Any` type. Returns an option. -pub fn raw_decode(src string) !Any { - mut p := new_parser(src, true) - return p.decode() -} - -// Same with `raw_decode`, but skips the type conversion for certain types when decoding a certain value. -pub fn fast_raw_decode(src string) !Any { - mut p := new_parser(src, false) - return p.decode() -} - -// decode is a generic function that decodes a JSON string into the target type. -pub fn decode[T](src string) !T { - res := raw_decode(src)!.as_map() - return decode_struct[T](T{}, res) -} - -// decode_struct is a generic function that decodes a JSON map into the struct T. -fn decode_struct[T](_ T, res map[string]Any) !T { - mut typ := T{} - $if T is $struct { - $for field in T.fields { - mut json_name := field.name - for attr in field.attrs { - if attr.contains('json: ') { - json_name = attr.replace('json: ', '') - break - } - } - - $if field.is_enum { - if v := res[json_name] { - typ.$(field.name) = v.int() - } else { - $if field.is_option { - typ.$(field.name) = none - } - } - } $else $if field.typ is u8 { - typ.$(field.name) = res[json_name]!.u64() - } $else $if field.typ is u16 { - typ.$(field.name) = res[json_name]!.u64() - } $else $if field.typ is u32 { - typ.$(field.name) = res[json_name]!.u64() - } $else $if field.typ is u64 { - typ.$(field.name) = res[json_name]!.u64() - } $else $if field.typ is int { - typ.$(field.name) = res[json_name]!.int() - } $else $if field.typ is i8 { - typ.$(field.name) = res[json_name]!.int() - } $else $if field.typ is i16 { - typ.$(field.name) = res[json_name]!.int() - } $else $if field.typ is i32 { - typ.$(field.name) = i32(res[field.name]!.int()) - } $else $if field.typ is i64 { - typ.$(field.name) = res[json_name]!.i64() - } $else $if field.typ is ?u8 { - if json_name in res { - typ.$(field.name) = ?u8(res[json_name]!.i64()) - } - } $else $if field.typ is ?i8 { - if json_name in res { - typ.$(field.name) = ?i8(res[json_name]!.i64()) - } - } $else $if field.typ is ?u16 { - if json_name in res { - typ.$(field.name) = ?u16(res[json_name]!.i64()) - } - } $else $if field.typ is ?i16 { - if json_name in res { - typ.$(field.name) = ?i16(res[json_name]!.i64()) - } - } $else $if field.typ is ?u32 { - if json_name in res { - typ.$(field.name) = ?u32(res[json_name]!.i64()) - } - } $else $if field.typ is ?i32 { - if json_name in res { - typ.$(field.name) = ?i32(res[json_name]!.i64()) - } - } $else $if field.typ is ?u64 { - if json_name in res { - typ.$(field.name) = ?u64(res[json_name]!.i64()) - } - } $else $if field.typ is ?i64 { - if json_name in res { - typ.$(field.name) = ?i64(res[json_name]!.i64()) - } - } $else $if field.typ is ?int { - if json_name in res { - typ.$(field.name) = ?int(res[json_name]!.i64()) - } - } $else $if field.typ is f32 { - typ.$(field.name) = res[json_name]!.f32() - } $else $if field.typ is ?f32 { - if json_name in res { - typ.$(field.name) = res[json_name]!.f32() - } - } $else $if field.typ is f64 { - typ.$(field.name) = res[json_name]!.f64() - } $else $if field.typ is ?f64 { - if json_name in res { - typ.$(field.name) = res[json_name]!.f64() - } - } $else $if field.typ is bool { - typ.$(field.name) = res[json_name]!.bool() - } $else $if field.typ is ?bool { - if json_name in res { - typ.$(field.name) = res[json_name]!.bool() - } - } $else $if field.typ is string { - typ.$(field.name) = res[json_name]!.str() - } $else $if field.typ is ?string { - if json_name in res { - typ.$(field.name) = res[json_name]!.str() - } - } $else $if field.typ is time.Time { - typ.$(field.name) = res[json_name]!.to_time()! - } $else $if field.typ is ?time.Time { - if json_name in res { - typ.$(field.name) = res[json_name]!.to_time()! - } - } $else $if field.is_array { - } $else $if field.is_struct { - typ.$(field.name) = decode_struct(typ.$(field.name), res[field.name]!.as_map())! - } $else $if field.is_alias { - } $else $if field.is_map { - } $else { - return error("The type of `${field.name}` can't be decoded. Please open an issue at https://github.com/vlang/v/issues/new/choose") - } - } - } $else $if T is $map { - for k, v in res { - // // TODO - make this work to decode types like `map[string]StructType[bool]` - // $if typeof(typ[k]).idx is string { - // typ[k] = v.str() - // } $else $if typeof(typ[k]).idx is $struct { - - // } - match v { - string { - typ[k] = v.str() - } - else {} - } - } - } $else { - return error("The type `${T.name}` can't be decoded.") - } - return typ -} - -// encode is a generic function that encodes a type into a JSON string. -pub fn encode[T](val T) string { - $if T is $array { - return encode_array(val) - } $else { - mut buf := []u8{} - - defer { - unsafe { buf.free() } - } - encoder := Encoder{} - - encoder.encode_value(val, mut buf) or { - println(err) - encoder.encode_value[string]('null', mut buf) or {} - } - - return buf.bytestr() - } -} - -// encode_array is a generic function that encodes a array into a JSON string. -fn encode_array[T](val []T) string { - mut buf := []u8{} - - defer { - unsafe { buf.free() } - } - - encoder := Encoder{} - encoder.encode_array(val, 1, mut buf) or { - println(err) - encoder.encode_value[string]('null', mut buf) or {} - } - - return buf.bytestr() -} - -// encode_pretty ... -pub fn encode_pretty[T](typed_data T) string { - encoded := encode(typed_data) - raw_decoded := raw_decode(encoded) or { 0 } - return raw_decoded.prettify_json_str() -} - // i8 - TODO pub fn (f Any) i8() i8 { match f {