From 8986645ee93015bf9b44e7839c3a3370aff4f51b Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 05:10:54 +0300 Subject: [PATCH] all: markused/json2 fixes --- vlib/builtin/rune.v | 2 +- vlib/strconv/atof.c.v | 3 ++- vlib/strconv/atoi.v | 7 +++++- vlib/strconv/atou.v | 5 ++++ vlib/time/time.v | 1 + vlib/v/markused/walker.v | 46 +++++++++++++++++++++++------------ vlib/x/json2/attr_utils.v | 1 + vlib/x/json2/decode.v | 42 ++++++++++++++++++++++++++++---- vlib/x/json2/decode_sumtype.v | 27 +++++++++++--------- vlib/x/json2/encode.v | 22 ++++++++++++----- vlib/x/json2/strict/strict.v | 26 ++++++++++++++------ vlib/x/json2/types.v | 6 +++++ 12 files changed, 140 insertions(+), 48 deletions(-) diff --git a/vlib/builtin/rune.v b/vlib/builtin/rune.v index 14dd86241..6e212e53f 100644 --- a/vlib/builtin/rune.v +++ b/vlib/builtin/rune.v @@ -37,7 +37,7 @@ pub fn (c rune) repeat(count int) string { } // bytes converts a rune to an array of bytes. -@[manualfree] +@[manualfree; markused] pub fn (c rune) bytes() []u8 { mut res := []u8{cap: 5} mut buf := &u8(res.data) diff --git a/vlib/strconv/atof.c.v b/vlib/strconv/atof.c.v index 9afda7d6e..a75dd22a4 100644 --- a/vlib/strconv/atof.c.v +++ b/vlib/strconv/atof.c.v @@ -429,13 +429,14 @@ fn converter(mut pn PrepNumber) u64 { return result } -@[params] +@[markused; params] pub struct AtoF64Param { pub: allow_extra_chars bool // allow extra characters after number } // atof64 parses the string `s`, and if possible, converts it into a f64 number +@[markused] pub fn atof64(s string, param AtoF64Param) !f64 { if s.len == 0 { return error('expected a number found an empty string') diff --git a/vlib/strconv/atoi.v b/vlib/strconv/atoi.v index 07689fb99..7402d6edf 100644 --- a/vlib/strconv/atoi.v +++ b/vlib/strconv/atoi.v @@ -147,6 +147,7 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) { } // parse_uint is like parse_int but for unsigned numbers. +@[markused] pub fn parse_uint(s string, _base int, _bit_size int) !u64 { return common_parse_uint(s, _base, _bit_size, true, true) } @@ -286,31 +287,35 @@ fn atoi_common(s string, type_min i64, type_max i64) !i64 { // atoi is equivalent to parse_int(s, 10, 0), converted to type int. // It follows V scanner as much as observed. +@[markused] pub fn atoi(s string) !int { return int(atoi_common(s, i64_min_int32, i64_max_int32)!) } // atoi8 is equivalent to atoi(s), converted to type i8. // returns an i8 [-128 .. 127] or an error. +@[markused] pub fn atoi8(s string) !i8 { return i8(atoi_common(s, min_i8, max_i8)!) } // atoi16 is equivalent to atoi(s), converted to type i16. // returns an i16 [-32678 .. 32767] or an error. +@[markused] pub fn atoi16(s string) !i16 { return i16(atoi_common(s, min_i16, max_i16)!) } // atoi32 is equivalent to atoi(s), converted to type i32. // returns an i32 [-2147483648 .. 2147483647] or an error. +@[markused] pub fn atoi32(s string) !i32 { return i32(atoi_common(s, min_i32, max_i32)!) } // atoi64 converts radix 10 string to i64 type. // returns an i64 [-9223372036854775808 .. 9223372036854775807] or an error. -@[direct_array_access] +@[direct_array_access; markused] pub fn atoi64(s string) !i64 { mut sign, mut start_idx := atoi_common_check(s)! mut x := i64(0) diff --git a/vlib/strconv/atou.v b/vlib/strconv/atou.v index 03dd7e9bc..344d8683f 100644 --- a/vlib/strconv/atou.v +++ b/vlib/strconv/atou.v @@ -67,29 +67,34 @@ fn atou_common(s string, type_max u64) !u64 { // atou8 is equivalent to parse_uint(s, 10, 0), converted to type u8. // It returns u8 in range [0..255] or an Error. +@[markused] pub fn atou8(s string) !u8 { return u8(atou_common(s, max_u8)!) } // atou16 is equivalent to parse_uint(s, 10, 0), converted to type u16. // It returns u16 in range [0..65535] or an Error. +@[markused] pub fn atou16(s string) !u16 { return u16(atou_common(s, max_u16)!) } // atou is equivalent to parse_uint(s, 10, 0), converted to type u32. +@[markused] pub fn atou(s string) !u32 { return u32(atou_common(s, max_u32)!) } // atou32 is identical to atou. Here to provide a symmetrical API with atoi/atoi32 // It returns u32 in range [0..4294967295] or an Error. +@[markused] pub fn atou32(s string) !u32 { return u32(atou_common(s, max_u32)!) } // atou64 is equivalent to parse_uint(s, 10, 0), converted to type u64. // It returns u64 in range [0..18446744073709551615] or an Error. +@[markused] pub fn atou64(s string) !u64 { return u64(atou_common(s, max_u64)!) } diff --git a/vlib/time/time.v b/vlib/time/time.v index 4371d924c..8d10f13eb 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -35,6 +35,7 @@ pub const days_before = [ ]! // Time contains various time units for a point in time. +@[markused] pub struct Time { unix i64 pub: diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index ec99cc928..6a6fc11cd 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -36,17 +36,18 @@ mut: all_decltypes map[string]ast.TypeDecl all_structs map[string]ast.StructDecl - cur_fn string - cur_fn_concrete_types []ast.Type - level int - is_builtin_mod bool - is_direct_array_access bool - inside_in_op bool - inside_comptime int - inside_comptime_if int - used_fn_generic_types map[string][][]ast.Type - walked_fn_generic_types map[string][][]ast.Type - keep_all_fn_generic_types map[string]bool + cur_fn string + cur_fn_concrete_types []ast.Type + level int + is_builtin_mod bool + is_direct_array_access bool + inside_in_op bool + inside_comptime int + inside_comptime_if int + used_fn_generic_types map[string][][]ast.Type + walked_fn_generic_types map[string][][]ast.Type + keep_all_fn_generic_types map[string]bool + json2_encode_field_helpers map[string]bool // dependencies finding flags uses_atomic bool // has atomic @@ -269,6 +270,11 @@ fn (mut w Walker) mark_json2_optional_field_helpers(concrete_typ ast.Type) { } fn (mut w Walker) mark_json2_encode_field_helpers(receiver_typ ast.Type, concrete_typ ast.Type) { + helper_key := '${int(receiver_typ)}:${int(concrete_typ)}' + if w.json2_encode_field_helpers[helper_key] { + return + } + w.json2_encode_field_helpers[helper_key] = true concrete_sym := w.table.final_sym(w.table.unaliased_type(concrete_typ)) if concrete_sym.kind != .struct || concrete_sym.info !is ast.Struct { return @@ -1483,6 +1489,10 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type return } w.mark_fn_as_used(fkey) + if node.mod == 'x.json2' { + w.mark_by_sym_name('EnumData') + w.mark_by_sym_name('time.Time') + } last_is_direct_array_access := w.is_direct_array_access w.is_direct_array_access = node.is_direct_arr || w.pref.no_bounds_checking defer { w.is_direct_array_access = last_is_direct_array_access } @@ -1576,7 +1586,8 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type continue } concrete_typ := w.table.unaliased_type(concrete_type_list[0]) - if w.table.final_sym(concrete_typ).kind == .struct { + concrete_sym := w.table.final_sym(concrete_typ) + if concrete_sym.kind == .struct && concrete_sym.name != 'time.Time' { w.fn_decl_with_concrete_types(mut check_struct_type_valid_fn, concrete_type_list) } @@ -1597,7 +1608,7 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type } } } - if concrete_sym.kind == .struct { + if concrete_sym.kind == .struct && concrete_sym.name != 'time.Time' { if mut decode_struct_key_fn := w.all_fns['x.json2.decode_struct_key'] { w.fn_decl_with_concrete_types(mut decode_struct_key_fn, resolved_concrete_types) } @@ -1611,6 +1622,10 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type if node.mod == 'x.json2' && node.name == 'decode_struct_key' && resolved_concrete_types.len == 1 { w.mark_json2_optional_field_helpers(resolved_concrete_types[0]) } + if node.mod == 'x.json2' && node.name == 'decode_enum' { + w.uses_ct_values = true + w.mark_by_sym_name('EnumData') + } if node.mod == 'x.json2' && node.name == 'encode_value' && node.is_method && resolved_concrete_types.len == 1 { concrete_typ := w.table.unaliased_type(resolved_concrete_types[0]) @@ -1622,7 +1637,7 @@ fn (mut w Walker) fn_decl_with_concrete_types(mut node ast.FnDecl, concrete_type } } } - if concrete_sym.kind in [.array, .array_fixed] { + if concrete_sym.kind == .array { encode_array_fkey, _ := w.resolve_method_fkey_for_type(node.receiver.typ, 'encode_array') if encode_array_fkey != '' { @@ -2030,7 +2045,8 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { w.mark_by_type(concrete_type) } generic_call_inside_generic_caller := w.fn_generic_names(stmt).len > 0 - && node.raw_concrete_types.len == 0 && caller_generic_names.len > 0 + && call_concrete_types.len == 0 && node.raw_concrete_types.len == 0 + && caller_generic_names.len > 0 keep_all_generic_types := (stmt.generic_names.len > 0 && call_concrete_types.len == 0) || generic_call_inside_generic_caller if keep_all_generic_types { diff --git a/vlib/x/json2/attr_utils.v b/vlib/x/json2/attr_utils.v index 0ac790496..6fd9760e0 100644 --- a/vlib/x/json2/attr_utils.v +++ b/vlib/x/json2/attr_utils.v @@ -20,6 +20,7 @@ fn json_attr_value(attr string) ?string { return unquote_attr_value(attr[5..]) } +@[markused] fn json_attr_value_range(attr string) ?(int, int) { if !attr.starts_with('json:') { return none diff --git a/vlib/x/json2/decode.v b/vlib/x/json2/decode.v index d848114a2..97c00170f 100644 --- a/vlib/x/json2/decode.v +++ b/vlib/x/json2/decode.v @@ -1,6 +1,7 @@ module json2 import strconv +import time const null_in_string = 'null' @@ -36,6 +37,7 @@ struct DecoderFieldInfo { is_raw bool } +@[markused] struct StructFieldInfo { json_name_ptr voidptr json_name_len int @@ -375,7 +377,7 @@ fn (mut decoder Decoder) cached_struct_field_infos[T]() []StructFieldInfo { return *field_infos } -@[inline] +@[inline; markused] fn struct_field_is_decoded(decoded_mask u64, decoded_fields []bool, field_idx int) bool { if field_idx < 64 { return (decoded_mask & (u64(1) << u64(field_idx))) != 0 @@ -383,7 +385,7 @@ fn struct_field_is_decoded(decoded_mask u64, decoded_fields []bool, field_idx in return decoded_fields[field_idx] } -@[inline] +@[inline; markused] fn mark_struct_field_decoded(decoded_mask u64, mut decoded_fields []bool, field_idx int) u64 { if field_idx < 64 { return decoded_mask | (u64(1) << u64(field_idx)) @@ -402,7 +404,7 @@ fn (decoder &Decoder) json_key_matches(key_info ValueInfo, key_name string) bool } } -@[inline] +@[inline; markused] fn (decoder &Decoder) is_empty_value(value_info ValueInfo) bool { match value_info.value_kind { .null { @@ -430,6 +432,7 @@ fn (decoder &Decoder) is_empty_value(value_info ValueInfo) bool { return false } +@[markused] fn (mut decoder Decoder) skip_current_value() { if decoder.current_node == unsafe { nil } { return @@ -673,6 +676,23 @@ fn (mut decoder Decoder) decode_value[T](mut val T) ! { return } $else $if T.unaliased_typ is string { decoder.decode_string(mut val)! + } $else $if T.unaliased_typ is time.Time { + value_info := decoder.current_node.value + mut decoded_time := time.Time{} + if value_info.value_kind == .string { + decoded_time.from_json_string(decoder.json[value_info.position + 1.. + value_info.position + value_info.length - 1]) or { + decoder.decode_error('${typeof(val).name}: ${err.msg()}')! + } + } else if value_info.value_kind == .number { + decoded_time.from_json_number(decoder.json[value_info.position..value_info.position + + value_info.length]) or { + decoder.decode_error('${typeof(val).name}: ${err.msg()}')! + } + } else { + decoder.decode_error('Expected string or number, but got ${value_info.value_kind}')! + } + val = T(decoded_time) } $else $if T.unaliased_typ is $sumtype { decoder.decode_sumtype(mut val)! return @@ -1173,6 +1193,7 @@ fn (mut decoder Decoder) decode_enum[T](mut val T) ! { const max_integer_number_digits = 20 +@[markused] fn has_exponent_number_syntax(str string) bool { for c in str { if c == `e` || c == `E` { @@ -1182,6 +1203,7 @@ fn has_exponent_number_syntax(str string) bool { return false } +@[markused] fn scientific_number_to_integer_string(str string) !string { if !has_exponent_number_syntax(str) { // Handle plain decimal numbers with zero fractional part (e.g., "-123.0") @@ -1326,8 +1348,10 @@ fn parse_integer_number[T](str string) !T { return T(strconv.atou32(int_str)!) } $else $if T.unaliased_typ is u64 { return T(strconv.atou64(int_str)!) + } $else $if T is int { + return int(strconv.atoi64(int_str)!) } $else $if T.unaliased_typ is int { - return T(strconv.atoi(int_str)!) + return T(int(strconv.atoi64(int_str)!)) } $else $if T.unaliased_typ is isize { return T(isize(strconv.atoi64(int_str)!)) } $else $if T.unaliased_typ is usize { @@ -1337,6 +1361,12 @@ fn parse_integer_number[T](str string) !T { } } +@[markused] +fn parse_int_number(str string) !int { + int_str := scientific_number_to_integer_string(str)! + return int(strconv.atoi64(int_str)!) +} + fn parse_float_number[T](str string) !T { $if js { $if T.unaliased_typ is f32 { @@ -1372,7 +1402,7 @@ fn (mut decoder Decoder) decode_number[T](val &T) ! { u16 { *val = parse_integer_number[T](str)! } u32 { *val = parse_integer_number[T](str)! } u64 { *val = parse_integer_number[T](str)! } - int { *val = parse_integer_number[T](str)! } + int { *val = parse_int_number(str)! } isize { *val = parse_integer_number[T](str)! } usize { *val = parse_integer_number[T](str)! } f32 { *val = parse_float_number[T](str)! } @@ -1406,6 +1436,8 @@ fn (mut decoder Decoder) decode_number_from_string[T]() !T { return parse_integer_number[T](str)! } $else $if T.unaliased_typ is u64 { return parse_integer_number[T](str)! + } $else $if T is int { + return parse_int_number(str)! } $else $if T.unaliased_typ is int { return parse_integer_number[T](str)! } $else $if T.unaliased_typ is isize { diff --git a/vlib/x/json2/decode_sumtype.v b/vlib/x/json2/decode_sumtype.v index fbc46c590..419e7717d 100644 --- a/vlib/x/json2/decode_sumtype.v +++ b/vlib/x/json2/decode_sumtype.v @@ -18,7 +18,7 @@ fn copy_type[T](_t T) T { fn (mut decoder Decoder) get_decoded_sumtype_workaround[T](initialized_sumtype T) !T { $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { resolved_sumtype := initialized_sumtype - $for v in initialized_sumtype.variants { + $for v in T.variants { if initialized_sumtype is v { $if initialized_sumtype is time.Time { mut val := copy_type(initialized_sumtype) @@ -121,7 +121,7 @@ fn (mut decoder Decoder) check_array_type_valid[T](arr []T, current_node &Node[V fn (mut decoder Decoder) get_array_type_workaround[T](initialized_sumtype T) bool { $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { - $for v in initialized_sumtype.variants { + $for v in T.variants { if initialized_sumtype is v { $if initialized_sumtype is $array { return decoder.check_element_type_valid(initialized_sumtype, @@ -149,7 +149,7 @@ fn (mut decoder Decoder) check_map_empty_valid[T](m T) bool { fn (mut decoder Decoder) get_map_type_workaround[T](initialized_sumtype T) bool { $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { - $for v in initialized_sumtype.variants { + $for v in T.variants { if initialized_sumtype is v { $if initialized_sumtype is $map { val := copy_type(initialized_sumtype) @@ -165,6 +165,7 @@ fn (mut decoder Decoder) get_map_type_workaround[T](initialized_sumtype T) bool return false } +@[markused] fn (decoder &Decoder) get_sumtype_type_field_node(current_node &Node[ValueInfo]) &Node[ValueInfo] { if current_node == unsafe { nil } { return unsafe { nil } @@ -203,6 +204,7 @@ fn (decoder &Decoder) get_sumtype_type_field_node(current_node &Node[ValueInfo]) return unsafe { nil } } +@[markused] fn (decoder &Decoder) sumtype_type_field_matches(type_field_node &Node[ValueInfo], expected string) bool { if type_field_node == unsafe { nil } { return false @@ -231,7 +233,7 @@ fn (mut decoder Decoder) check_struct_type_valid[T](s T, current_node &Node[Valu fn (mut decoder Decoder) get_struct_type_workaround[T](initialized_sumtype T) bool { $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { - $for v in initialized_sumtype.variants { + $for v in T.variants { if initialized_sumtype is v { $if initialized_sumtype is $struct { val := copy_type(initialized_sumtype) @@ -245,7 +247,7 @@ fn (mut decoder Decoder) get_struct_type_workaround[T](initialized_sumtype T) bo fn (mut decoder Decoder) get_time_type_workaround[T](initialized_sumtype T) bool { $if initialized_sumtype is $sumtype || (T is $alias && T.unaliased_typ is $sumtype) { - $for v in initialized_sumtype.variants { + $for v in T.variants { if initialized_sumtype is v { $if initialized_sumtype is time.Time { val := copy_type(initialized_sumtype) @@ -262,7 +264,7 @@ fn (mut decoder Decoder) resolve_sumtype_from_type_field[T](mut val T) !bool { return false } mut has_discriminated_variant := false - $for v in val.variants { + $for v in T.variants { $if v.typ is time.Time { has_discriminated_variant = true val = T(v) @@ -284,6 +286,7 @@ fn (mut decoder Decoder) resolve_sumtype_from_type_field[T](mut val T) !bool { return false } +@[markused] fn (mut decoder Decoder) decode_sumtype_time(mut val time.Time) ! { mut wrapper := SumtypeTimeValue{ typ: '' @@ -299,7 +302,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val match value_info.value_kind { .string { - $for v in val.variants { + $for v in T.variants { $if v.typ is string { val = T(v) return @@ -313,7 +316,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val } } .number { - $for v in val.variants { + $for v in T.variants { $if v.typ is $float { val = T(v) return @@ -330,7 +333,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val } } .boolean { - $for v in val.variants { + $for v in T.variants { $if v.typ is bool { val = T(v) return @@ -341,7 +344,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val } } .null { - $for v in val.variants { + $for v in T.variants { $if v.typ is $option { val = T(v) return @@ -352,7 +355,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val } } .array { - $for v in val.variants { + $for v in T.variants { $if v.typ is $array { val = T(v) @@ -366,7 +369,7 @@ fn (mut decoder Decoder) init_sumtype_by_value_kind[T](mut val T, value_info Val if decoder.resolve_sumtype_from_type_field(mut val)! { return } - $for v in val.variants { + $for v in T.variants { $if v.typ is $map { val = T(v) diff --git a/vlib/x/json2/encode.v b/vlib/x/json2/encode.v index 0a3ed456e..a25b92829 100644 --- a/vlib/x/json2/encode.v +++ b/vlib/x/json2/encode.v @@ -332,6 +332,7 @@ fn (mut encoder Encoder) encode_number[T](val T) { unsafe { encoder.output.push_many(integer_val.str, integer_val.len) } } +@[markused] fn (mut encoder Encoder) encode_null() { unsafe { encoder.output.push_many(null_string.str, null_string.len) } } @@ -436,12 +437,21 @@ fn (mut encoder Encoder) encode_sumtype[T](val T) { $for variant in T.variants { if val is variant { variant_name := sumtype_variant_name(typeof(variant.typ).name) - $if variant.typ is time.Time { - encoder.encode_sumtype_time_variant(val, variant_name) - } $else $if variant.typ is $struct { - encoder.encode_sumtype_struct_variant(val, variant_name) - } $else { - encoder.encode_value(val) + if T.name in ['x.json2.Any', 'json2.Any', 'Any'] { + $if variant.typ is $map { + encoder.encode_value(val) + } $else { + variant_value := val + encoder.encode_value(variant_value) + } + } else { + $if variant.typ is time.Time { + encoder.encode_sumtype_time_variant(val, variant_name) + } $else $if variant.typ is $struct { + encoder.encode_sumtype_struct_variant(val, variant_name) + } $else { + encoder.encode_value(val) + } } } } diff --git a/vlib/x/json2/strict/strict.v b/vlib/x/json2/strict/strict.v index d66e6fbf4..63e6e17bf 100644 --- a/vlib/x/json2/strict/strict.v +++ b/vlib/x/json2/strict/strict.v @@ -36,10 +36,9 @@ pub fn strict_check[T](json_data string) StructCheckResult { $for field in T.fields { $if field.typ is $struct { - field_name := field.name - last_key := arrays.find_last(key_struct, fn [field_name] (k KeyStruct) bool { - return k.key == field_name - }) or { panic('field not found: ' + field.name) } + last_key := find_last_key(key_struct, field.name) or { + panic('field not found: ' + field.name) + } // TODO: get path here from `last_key.key` if last_key.value_type == .map { @@ -71,6 +70,9 @@ fn check[T](val T, tokens []string, mut duplicates []string, mut superfluous []s $for field in T.fields { $if field.typ is $struct { + last_key := find_last_key(key_struct, field.name) or { + panic('field not found: ' + field.name) + } if last_key.value_type == .map { check(val.$(field.name), tokens[last_key.token_pos + 2..], mut duplicates, mut superfluous) @@ -80,7 +82,7 @@ fn check[T](val T, tokens []string, mut duplicates []string, mut superfluous []s } } -fn get_superfluous_keys[T](key_struct []x.json2.strict.KeyStruct) []string { +fn get_superfluous_keys[T](key_struct []KeyStruct) []string { mut superfluous := []string{} struct_keys := get_keys_from_[T]() @@ -95,11 +97,21 @@ fn get_superfluous_keys[T](key_struct []x.json2.strict.KeyStruct) []string { return superfluous } -fn get_duplicates_keys(key_struct []x.json2.strict.KeyStruct) []string { +fn get_duplicates_keys(key_struct []KeyStruct) []string { json_keys := key_struct.map(it.key).sorted() return arrays.uniq_only_repeated(json_keys) } +fn find_last_key(key_struct []KeyStruct, field_name string) ?KeyStruct { + for idx := key_struct.len; idx > 0; idx-- { + item := key_struct[idx - 1] + if item.key == field_name { + return item + } + } + return none +} + fn get_keys_from_[T]() []string { mut struct_keys := []string{} $if T is $struct { @@ -111,7 +123,7 @@ fn get_keys_from_[T]() []string { } // get_keys_from_json . -pub fn get_keys_from_json(tokens []string) []x.json2.strict.KeyStruct { +pub fn get_keys_from_json(tokens []string) []KeyStruct { mut key_structs := []KeyStruct{} mut nested_map_count := 0 diff --git a/vlib/x/json2/types.v b/vlib/x/json2/types.v index 43a04e7ed..25fd2b684 100644 --- a/vlib/x/json2/types.v +++ b/vlib/x/json2/types.v @@ -2,9 +2,14 @@ module json2 import time +@[markused] +const any_time_type_marker = time.Time{} + // Any is a sum type that lists the possible types to be decoded and used. // `Any` priority order for numbers: floats -> signed integers -> unsigned integers // `Any` priority order for strings: string -> time.Time + +@[markused] pub type Any = []Any | bool | f64 @@ -30,6 +35,7 @@ pub struct Null {} pub const null = Null{} // from_json_null implements a custom decoder for json2 +@[markused] pub fn (mut n Null) from_json_null() {} // to_json implements a custom encoder for json2 -- 2.39.5