diff options
Diffstat (limited to 'v_windows/v/old/vlib/x/json2/encoder.v')
-rw-r--r-- | v_windows/v/old/vlib/x/json2/encoder.v | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/v_windows/v/old/vlib/x/json2/encoder.v b/v_windows/v/old/vlib/x/json2/encoder.v new file mode 100644 index 0000000..b1ca0e4 --- /dev/null +++ b/v_windows/v/old/vlib/x/json2/encoder.v @@ -0,0 +1,179 @@ +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module json2 + +import strings + +fn write_value(v Any, i int, len int, mut wr strings.Builder) { + str := v.json_str() + if v is string { + wr.write_string('"$str"') + } else { + wr.write_string(str) + } + if i >= len - 1 { + return + } + wr.write_b(`,`) +} + +// str returns the string representation of the `map[string]Any`. +pub fn (flds map[string]Any) str() string { + mut wr := strings.new_builder(200) + wr.write_b(`{`) + mut i := 0 + for k, v in flds { + wr.write_string('"$k":') + write_value(v, i, flds.len, mut wr) + i++ + } + wr.write_b(`}`) + defer { + unsafe { wr.free() } + } + res := wr.str() + return res +} + +// str returns the string representation of the `[]Any`. +pub fn (flds []Any) str() string { + mut wr := strings.new_builder(200) + wr.write_b(`[`) + for i, v in flds { + write_value(v, i, flds.len, mut wr) + } + wr.write_b(`]`) + defer { + unsafe { wr.free() } + } + res := wr.str() + return res +} + +// str returns the string representation of the `Any` type. Use the `json_str` method +// if you want to use the escaped str() version of the `Any` type. +pub fn (f Any) str() string { + if f is string { + return f + } else { + return f.json_str() + } +} + +// json_str returns the JSON string representation of the `Any` type. +pub fn (f Any) json_str() string { + match f { + string { + return json_string(f) + } + int { + return f.str() + } + u64, i64 { + return f.str() + } + f32 { + str_f32 := f.str() + if str_f32.ends_with('.') { + return '${str_f32}0' + } + return str_f32 + } + f64 { + str_f64 := f.str() + if str_f64.ends_with('.') { + return '${str_f64}0' + } + return str_f64 + } + bool { + return f.str() + } + map[string]Any { + return f.str() + } + []Any { + return f.str() + } + Null { + return 'null' + } + } +} + +// char_len_list is a modified version of builtin.utf8_str_len +// that returns an array of character lengths. (e.g "t✔" => [1,2]) +fn char_len_list(s string) []int { + mut l := 1 + mut ls := []int{} + for i := 0; i < s.len; i++ { + c := s[i] + if (c & (1 << 7)) != 0 { + for t := byte(1 << 6); (c & t) != 0; t >>= 1 { + l++ + i++ + } + } + ls << l + l = 1 + } + return ls +} + +const escaped_chars = [r'\b', r'\f', r'\n', r'\r', r'\t'] + +// json_string returns the JSON spec-compliant version of the string. +[manualfree] +fn json_string(s string) string { + // not the best implementation but will revisit it soon + char_lens := char_len_list(s) + mut sb := strings.new_builder(s.len) + mut i := 0 + defer { + unsafe { + char_lens.free() + // freeing string builder on defer after + // returning .str() still isn't working :( + // sb.free() + } + } + for char_len in char_lens { + if char_len == 1 { + chr := s[i] + if chr in important_escapable_chars { + for j := 0; j < important_escapable_chars.len; j++ { + if chr == important_escapable_chars[j] { + sb.write_string(json2.escaped_chars[j]) + break + } + } + } else if chr == `"` || chr == `/` || chr == `\\` { + sb.write_string('\\' + chr.ascii_str()) + } else { + sb.write_b(chr) + } + } else { + slice := s[i..i + char_len] + hex_code := slice.utf32_code().hex() + if hex_code.len < 4 { + // an utf8 codepoint + sb.write_string(slice) + } else if hex_code.len == 4 { + sb.write_string('\\u$hex_code') + } else { + // TODO: still figuring out what + // to do with more than 4 chars + sb.write_b(` `) + } + unsafe { + slice.free() + hex_code.free() + } + } + i += char_len + } + str := sb.str() + unsafe { sb.free() } + return str +} |