From b3e0926601941011f2e7178ba0ae2baa80a68b35 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 22 Dec 2020 07:24:41 +0100 Subject: [PATCH] json: decode/encode time.Time --- vlib/json/json_test.v | 59 +++++++++++++++++++++++++--------------- vlib/math/big/big.v | 13 +++++++++ vlib/math/big/big_test.v | 4 +++ vlib/v/gen/json.v | 19 ++++++++++--- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/vlib/json/json_test.v b/vlib/json/json_test.v index cc042e6ebe..24e10e899f 100644 --- a/vlib/json/json_test.v +++ b/vlib/json/json_test.v @@ -1,4 +1,5 @@ import json +import time enum JobTitle { manager @@ -30,20 +31,23 @@ fn test_simple() { } fn bar(payload string) ?Bar { // ?T doesn't work currently - result := json.decode(T, payload)? + result := json.decode(T, payload) ? return result } + struct Bar { x string } + fn test_generic() { result := bar('{"x":"test"}') or { Bar{} } assert result.x == 'test' } struct User2 { - age int - nums []int + age int + nums []int + reg_date time.Time } struct User { @@ -57,13 +61,9 @@ struct User { fn test_parse_user() { s := '{"age": 10, "nums": [1,2,3], "type": 1, "lastName": "Johnson", "IsRegistered": true, "pet_animals": {"name": "Bob", "animal": "Dog"}}' - u2 := json.decode(User2, s) or { - exit(1) - } + u2 := json.decode(User2, s) or { exit(1) } println(u2) - u := json.decode(User, s) or { - exit(1) - } + u := json.decode(User, s) or { exit(1) } println(u) assert u.age == 10 assert u.last_name == 'Johnson' @@ -76,6 +76,23 @@ fn test_parse_user() { assert u.pets == '{"name":"Bob","animal":"Dog"}' } +fn test_encode_decode_time() { + user := User2{ + age: 25 + reg_date: time.new_time(year: 2020, month: 12, day: 22, hour: 7, minute: 23) + } + s := json.encode(user) + println(s) + assert s.contains('"reg_date":1608621780') + user2 := json.decode(User2, s) or { + assert false + return + } + assert user2.reg_date.str() == '2020-12-22 07:23:00' + println(user2) + println(user2.reg_date) +} + fn (mut u User) foo() string { return json.encode(u) } @@ -144,10 +161,10 @@ fn test_struct_in_struct() { fn test_encode_map() { expected := '{"one":1,"two":2,"three":3,"four":4}' numbers := { - 'one': 1 - 'two': 2 + 'one': 1 + 'two': 2 'three': 3 - 'four': 4 + 'four': 4 } out := json.encode(numbers) println(out) @@ -156,10 +173,10 @@ fn test_encode_map() { fn test_parse_map() { expected := { - 'one': 1 - 'two': 2 + 'one': 1 + 'two': 2 'three': 3 - 'four': 4 + 'four': 4 } out := json.decode(map[string]int, '{"one":1,"two":2,"three":3,"four":4}') or { assert false @@ -258,7 +275,7 @@ fn test_nested_type() { } } -struct Foo { +struct Foo { pub: name string data T @@ -268,9 +285,7 @@ fn test_generic_struct() { foo_int := Foo{'bar', 12} foo_enc := json.encode(foo_int) assert foo_enc == '{"name":"bar","data":12}' - foo_dec := json.decode(Foo, foo_enc) or { - exit(1) - } + foo_dec := json.decode(Foo, foo_enc) or { exit(1) } assert foo_dec.name == 'bar' assert foo_dec.data == 12 } @@ -321,7 +336,7 @@ fn test_encode_alias_struct() { } struct List { - id int + id int items []string } @@ -331,7 +346,7 @@ fn test_list() { return } assert list.id == 1 - assert list.items == ["1", "2"] + assert list.items == ['1', '2'] } fn test_list_no_id() { @@ -340,7 +355,7 @@ fn test_list_no_id() { return } assert list.id == 0 - assert list.items == ["1", "2"] + assert list.items == ['1', '2'] } fn test_list_no_items() { diff --git a/vlib/math/big/big.v b/vlib/math/big/big.v index 67cbc38aa9..d6c3f6334a 100644 --- a/vlib/math/big/big.v +++ b/vlib/math/big/big.v @@ -6,6 +6,7 @@ module big #include "bn.h" [typedef] struct C.bn { +mut: array [32]u32 } @@ -105,6 +106,18 @@ pub fn from_string(input string) Number { return n } +pub fn from_string2(input string) Number { + mut n := Number{} + C.bignum_init(&n) + if input.len == 0 { + return from_int(0) + } + for i, c in input { + n.array[i] = u32(c - `0`) + } + return n +} + pub fn (n Number) int() int { r := C.bignum_to_int(&n) return r diff --git a/vlib/math/big/big_test.v b/vlib/math/big/big_test.v index da550160d1..5b24961ee6 100644 --- a/vlib/math/big/big_test.v +++ b/vlib/math/big/big_test.v @@ -78,6 +78,10 @@ fn test_mod() { } fn test_from_str() { + x := big.from_string2('23') + println('kek') + println(x.str()) + exit(0) assert big.from_string('').hexstr() == '0' assert big.from_string('1').hexstr() == '1' assert big.from_string('0').hexstr() == '0' diff --git a/vlib/v/gen/json.v b/vlib/v/gen/json.v index c4725d85f8..f4271b2bf8 100644 --- a/vlib/v/gen/json.v +++ b/vlib/v/gen/json.v @@ -126,6 +126,7 @@ fn (mut g Gen) gen_struct_enc_dec(type_info table.TypeInfo, styp string, mut enc } field_type := g.typ(field.typ) field_sym := g.table.get_type_symbol(field.typ) + // First generate decoding if field.attrs.contains('raw') { dec.writeln('\tres.${c_name(field.name)} = tos4(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));') } else { @@ -137,6 +138,10 @@ fn (mut g Gen) gen_struct_enc_dec(type_info table.TypeInfo, styp string, mut enc dec.writeln('\tres.${c_name(field.name)} = $dec_name (js_get(root, "$name"));') } else if field_sym.kind == .enum_ { dec.writeln('\tres.${c_name(field.name)} = json__decode_u64(js_get(root, "$name"));') + } else if field_sym.name == 'time.Time' { + // time struct requires special treatment + // it has to be decoded from a unix timestamp number + dec.writeln('\tres.${c_name(field.name)} = time__unix(json__decode_u64(js_get(root, "$name")));') } else if field_sym.kind == .alias { alias := field_sym.info as table.Alias parent_type := g.typ(alias.parent_type) @@ -162,6 +167,7 @@ fn (mut g Gen) gen_struct_enc_dec(type_info table.TypeInfo, styp string, mut enc dec.writeln('\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;') } } + // Encoding mut enc_name := js_enc_name(field_type) if !is_js_prim(field_type) { if field_sym.kind == .alias { @@ -172,7 +178,13 @@ fn (mut g Gen) gen_struct_enc_dec(type_info table.TypeInfo, styp string, mut enc if field_sym.kind == .enum_ { enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}));') } else { - enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));') + if field_sym.name == 'time.Time' { + // time struct requires special treatment + // it has to be encoded as a unix timestamp number + enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}.v_unix));') + } else { + enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));') + } } } } @@ -189,9 +201,8 @@ fn js_dec_name(typ string) string { } fn is_js_prim(typ string) bool { - return typ == 'int' || typ == 'string' || typ == 'bool' || typ == 'f32' || typ == 'f64' || - typ == 'i8' || typ == 'i16' || typ == 'i64' || typ == 'u16' || typ == 'u32' || typ == 'u64' || - typ == 'byte' + return typ in + ['int', 'string', 'bool', 'f32', 'f64', 'i8', 'i16', 'i64', 'u16', 'u32', 'u64', 'byte'] } fn (mut g Gen) decode_array(value_type table.Type) string {