mirror of
https://github.com/vlang/v.git
synced 2025-09-01 08:47:50 -04:00
447 lines
13 KiB
V
447 lines
13 KiB
V
module decoder2
|
|
|
|
import time
|
|
|
|
struct Node {
|
|
key_pos int
|
|
key_len int
|
|
children ?[]Node
|
|
}
|
|
|
|
struct Decoder {
|
|
json_data string
|
|
mut:
|
|
idx int
|
|
}
|
|
|
|
pub enum ValueKind {
|
|
unknown
|
|
array
|
|
object
|
|
string_
|
|
number
|
|
boolean
|
|
}
|
|
|
|
// check_json
|
|
fn check_json(val string) ! {
|
|
if val == '' {
|
|
return error('empty string')
|
|
}
|
|
}
|
|
|
|
// decode
|
|
pub fn decode[T](val string) !T {
|
|
check_json(val)!
|
|
|
|
mut nodes := []Node{}
|
|
|
|
mut decoder := Decoder{
|
|
json_data: val
|
|
}
|
|
|
|
// TODO needs performance improvements
|
|
decoder.fulfill_nodes(mut nodes)
|
|
|
|
mut result := T{}
|
|
|
|
decoder.decode_value(nodes, &result)
|
|
return result
|
|
}
|
|
|
|
// decode_value
|
|
fn (mut decoder Decoder) decode_value[T](nodes []Node, val &T) {
|
|
$if val is $option {
|
|
} $else $if T is string {
|
|
} $else $if T is $sumtype {
|
|
$for v in val.variants {
|
|
if val is v {
|
|
decoder.decode_value(nodes, val)
|
|
}
|
|
}
|
|
} $else $if T is $alias {
|
|
} $else $if T is time.Time {
|
|
} $else $if T is $map {
|
|
} $else $if T is $array {
|
|
} $else $if T is $struct {
|
|
decoder.decode_struct(nodes, val)
|
|
} $else $if T is $enum {
|
|
} $else $if T is $int {
|
|
} $else $if T is $float {
|
|
} $else $if T is bool {
|
|
} $else {
|
|
return error('cannot encode value with ${typeof(val).name} type')
|
|
}
|
|
}
|
|
|
|
fn get_value_kind(value rune) ValueKind {
|
|
mut value_kind := ValueKind.unknown
|
|
|
|
if value == `"` {
|
|
value_kind = .string_
|
|
} else if value == `t` || value == `f` {
|
|
value_kind = .boolean
|
|
} else if value == `{` {
|
|
value_kind = .object
|
|
} else if value == `[` {
|
|
value_kind = .array
|
|
} else if value >= `0` && value <= `9` {
|
|
value_kind = .number
|
|
}
|
|
return value_kind
|
|
}
|
|
|
|
// decode_optional_value_in_actual_node
|
|
fn (mut decoder Decoder) decode_optional_value_in_actual_node[T](node Node, val ?T) T {
|
|
start := (node.key_pos + node.key_len) + 3
|
|
mut end := start
|
|
for {
|
|
if decoder.json_data[end] == `,` || decoder.json_data[end] == `}` {
|
|
break
|
|
}
|
|
|
|
end++
|
|
}
|
|
mut value_kind := get_value_kind(decoder.json_data[start])
|
|
|
|
$if T is string {
|
|
if value_kind == .string_ {
|
|
return decoder.json_data[start + 1..end - 1]
|
|
} else if value_kind == .object {
|
|
} else if value_kind == .array {
|
|
} else {
|
|
return decoder.json_data[start..end]
|
|
}
|
|
return ''
|
|
} $else $if T is $int {
|
|
if value_kind == .string_ {
|
|
return decoder.json_data[start + 1..end - 1].int()
|
|
} else if value_kind == .object {
|
|
} else if value_kind == .array {
|
|
} else {
|
|
return decoder.json_data[start..end].int()
|
|
}
|
|
}
|
|
return T{}
|
|
}
|
|
|
|
// decode_struct
|
|
fn (mut decoder Decoder) decode_struct[T](nodes []Node, value &T) {
|
|
$for field in T.fields {
|
|
for i := 0; i < nodes.len; i++ {
|
|
mut node := nodes[i]
|
|
|
|
if node.key_len == field.name.len {
|
|
if unsafe {
|
|
vmemcmp(decoder.json_data.str + node.key_pos, field.name.str, field.name.len) == 0
|
|
} {
|
|
start := (node.key_pos + node.key_len) + 3
|
|
mut end := start
|
|
for {
|
|
if decoder.json_data[end] == `,` || decoder.json_data[end] == `}` {
|
|
break
|
|
}
|
|
|
|
end++
|
|
}
|
|
|
|
mut value_kind := get_value_kind(decoder.json_data[start])
|
|
$if field.indirections != 0 {
|
|
// REVIEW Needs clone?
|
|
$if field.indirections == 1 {
|
|
// TODO
|
|
// unsafe {
|
|
// value.$(field.name) = &(decoder.json_data[start + 1..end - 1])
|
|
// }
|
|
} $else $if field.indirections == 2 {
|
|
// TODO
|
|
// unsafe {
|
|
// value.$(field.name) = &&(decoder.json_data[start + 1..end - 1])
|
|
// }
|
|
} $else $if field.indirections == 3 {
|
|
// TODO
|
|
// unsafe {
|
|
// value.$(field.name) = &&&(decoder.json_data[start + 1..end - 1])
|
|
// }
|
|
}
|
|
} $else $if field.typ is $option {
|
|
value.$(field.name) = decoder.decode_optional_value_in_actual_node(node,
|
|
value.$(field.name))
|
|
} $else $if field.typ is $sumtype {
|
|
// dump(value.$(field.name))
|
|
|
|
workaround := value.$(field.name)
|
|
// z := value.$(field.name)
|
|
|
|
$for v in workaround.variants {
|
|
$if v.typ is string {
|
|
if value_kind == .string_ {
|
|
// value.$(field.name) = decoder.json_data[start + 1..end - 1]
|
|
} else {
|
|
// value.$(field.name) = decoder.json_data[start..end]
|
|
}
|
|
} $else $if v.typ in [$int, $float] {
|
|
$if v.typ is u32 {
|
|
value.$(field.name) = decoder.json_data[start..end].u32()
|
|
} $else $if v.typ is u32 {
|
|
}
|
|
|
|
$if v.typ is i8 {
|
|
value.$(field.name) = decoder.json_data[start..end].i8()
|
|
} $else $if v.typ is i16 {
|
|
value.$(field.name) = decoder.json_data[start..end].i16()
|
|
} $else $if v.typ is i32 {
|
|
value.$(field.name) = decoder.json_data[start..end].i32()
|
|
} $else $if v.typ is int {
|
|
value.$(field.name) = decoder.json_data[start..end].int()
|
|
} $else $if v.typ is i64 {
|
|
value.$(field.name) = decoder.json_data[start..end].i64()
|
|
} $else $if v.typ is u8 {
|
|
value.$(field.name) = decoder.json_data[start..end].u8()
|
|
} $else $if v.typ is u16 {
|
|
value.$(field.name) = decoder.json_data[start..end].u16()
|
|
} $else $if v.typ is u32 {
|
|
value.$(field.name) = decoder.json_data[start..end].u32()
|
|
} $else $if v.typ is u64 {
|
|
value.$(field.name) = decoder.json_data[start..end].u64()
|
|
} $else $if v.typ is f32 {
|
|
value.$(field.name) = decoder.json_data[start..end].f32()
|
|
} $else $if v.typ is f64 {
|
|
value.$(field.name) = decoder.json_data[start..end].f64()
|
|
}
|
|
} $else $if v.typ is bool {
|
|
if decoder.json_data[start] == `t` {
|
|
value.$(field.name) = true
|
|
} else if decoder.json_data[start] == `f` {
|
|
value.$(field.name) = false
|
|
}
|
|
} $else $if v.typ is time.Time {
|
|
if value_kind == .string_ {
|
|
value.$(field.name) = time.parse(decoder.json_data[start + 1..end - 1]) or {
|
|
time.Time{}
|
|
}
|
|
}
|
|
} $else $if v.typ is $struct {
|
|
if node.children != none {
|
|
// FIXME
|
|
// decoder.decode_value(node.children or {
|
|
// panic('It will never happens')
|
|
// }, value.$(field.name))
|
|
}
|
|
} $else $if v.typ is $array {
|
|
if value_kind == .array {
|
|
// TODO
|
|
}
|
|
} $else $if v.typ is $map {
|
|
if value_kind == .object {
|
|
// TODO
|
|
}
|
|
} $else $if T is $enum {
|
|
} $else {
|
|
eprintln('not supported')
|
|
}
|
|
}
|
|
if value_kind == .string_ {
|
|
// value.$(field.name) = decoder.json_data[start + 1..end - 1]
|
|
} else if decoder.json_data[start] == `t` {
|
|
value.$(field.name) = true
|
|
} else if decoder.json_data[start] == `f` {
|
|
value.$(field.name) = false
|
|
} else if value_kind == .object {
|
|
} else if value_kind == .array {
|
|
} else if value_kind == .number {
|
|
// value.$(field.name) = decoder.json_data[start..end].int()
|
|
} else {
|
|
}
|
|
} $else $if field.typ is string {
|
|
if value_kind == .string_ {
|
|
value.$(field.name) = decoder.json_data[start + 1..end - 1]
|
|
} else {
|
|
value.$(field.name) = decoder.json_data[start..end]
|
|
}
|
|
} $else $if field.typ in [$int, $float] {
|
|
$if field.typ is i8 {
|
|
value.$(field.name) = decoder.json_data[start..end].i8()
|
|
} $else $if field.typ is i16 {
|
|
value.$(field.name) = decoder.json_data[start..end].i16()
|
|
} $else $if field.typ is i32 {
|
|
value.$(field.name) = decoder.json_data[start..end].i32()
|
|
} $else $if field.typ is int {
|
|
value.$(field.name) = decoder.json_data[start..end].int()
|
|
} $else $if field.typ is i64 {
|
|
value.$(field.name) = decoder.json_data[start..end].i64()
|
|
} $else $if field.typ is u8 {
|
|
value.$(field.name) = decoder.json_data[start..end].u8()
|
|
} $else $if field.typ is u16 {
|
|
value.$(field.name) = decoder.json_data[start..end].u16()
|
|
} $else $if field.typ is u32 {
|
|
value.$(field.name) = decoder.json_data[start..end].u32()
|
|
} $else $if field.typ is u64 {
|
|
value.$(field.name) = decoder.json_data[start..end].u64()
|
|
} $else $if field.typ is f32 {
|
|
value.$(field.name) = decoder.json_data[start..end].f32()
|
|
} $else $if field.typ is f64 {
|
|
value.$(field.name) = decoder.json_data[start..end].f64()
|
|
}
|
|
} $else $if field.typ is bool {
|
|
if decoder.json_data[start] == `t` {
|
|
value.$(field.name) = true
|
|
} else if decoder.json_data[start] == `f` {
|
|
value.$(field.name) = false
|
|
}
|
|
} $else $if field.typ is time.Time {
|
|
if value_kind == .string_ {
|
|
value.$(field.name) = time.parse_rfc3339(decoder.json_data[start + 1..end - 1]) or {
|
|
time.Time{}
|
|
}
|
|
}
|
|
} $else $if field.typ is $struct {
|
|
if node.children != none {
|
|
decoder.decode_value(node.children or { panic('It will never happens') },
|
|
value.$(field.name))
|
|
}
|
|
} $else $if field.typ is $array {
|
|
if value_kind == .array {
|
|
// TODO
|
|
}
|
|
} $else $if field.typ is $map {
|
|
if value_kind == .object {
|
|
if node.children != none {
|
|
decoder.decode_map(node.children or {
|
|
panic('It will never happens')
|
|
}, mut value.$(field.name))
|
|
}
|
|
}
|
|
} $else $if field.typ is $enum {
|
|
value.$(field.name) = decoder.json_data[start..end].int()
|
|
} $else $if field.typ is $alias {
|
|
$if field.unaliased_typ is string {
|
|
if value_kind == .string_ {
|
|
value.$(field.name) = decoder.json_data[start + 1..end - 1]
|
|
}
|
|
} $else $if field.unaliased_typ is time.Time {
|
|
} $else $if field.unaliased_typ is bool {
|
|
} $else $if field.unaliased_typ in [$float, $int] {
|
|
$if field.unaliased_typ is i8 {
|
|
value.$(field.name) = decoder.json_data[start..end].i8()
|
|
} $else $if field.unaliased_typ is i16 {
|
|
value.$(field.name) = decoder.json_data[start..end].i16()
|
|
} $else $if field.unaliased_typ is i32 {
|
|
value.$(field.name) = decoder.json_data[start..end].i32()
|
|
} $else $if field.unaliased_typ is int {
|
|
value.$(field.name) = decoder.json_data[start..end].int()
|
|
} $else $if field.unaliased_typ is i64 {
|
|
value.$(field.name) = decoder.json_data[start..end].i64()
|
|
} $else $if field.unaliased_typ is u8 {
|
|
value.$(field.name) = decoder.json_data[start..end].u8()
|
|
} $else $if field.unaliased_typ is u16 {
|
|
value.$(field.name) = decoder.json_data[start..end].u16()
|
|
} $else $if field.unaliased_typ is u32 {
|
|
value.$(field.name) = decoder.json_data[start..end].u32()
|
|
} $else $if field.unaliased_typ is u64 {
|
|
value.$(field.name) = decoder.json_data[start..end].u64()
|
|
} $else $if field.unaliased_typ is f32 {
|
|
value.$(field.name) = decoder.json_data[start..end].f32()
|
|
} $else $if field.unaliased_typ is f64 {
|
|
value.$(field.name) = decoder.json_data[start..end].f64()
|
|
}
|
|
} $else $if field.unaliased_typ is $array {
|
|
// TODO
|
|
} $else $if field.unaliased_typ is $struct {
|
|
} $else $if field.unaliased_typ is $enum {
|
|
// TODO
|
|
} $else $if field.unaliased_typ is $sumtype {
|
|
// TODO
|
|
} $else {
|
|
eprintln('the alias ${field.unaliased_typ} cannot be encoded')
|
|
}
|
|
} $else {
|
|
eprintln('not supported')
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
// }
|
|
}
|
|
}
|
|
|
|
// fn (mut decoder Decoder) decode_map[K, V](nodes []Node, mut val map[K]V) {
|
|
fn (mut decoder Decoder) decode_map[T](nodes []Node, mut val T) {
|
|
for i := 0; i < nodes.len; i++ {
|
|
mut node := nodes[i]
|
|
|
|
start := (node.key_pos + node.key_len) + 3
|
|
mut end := start
|
|
|
|
for {
|
|
if decoder.json_data[end] == `,` || decoder.json_data[end] == `}` {
|
|
break
|
|
}
|
|
|
|
end++
|
|
}
|
|
|
|
mut value_kind := get_value_kind(decoder.json_data[start])
|
|
|
|
if value_kind == .string_ {
|
|
val[decoder.json_data[node.key_pos..node.key_pos + node.key_len]] = decoder.json_data[
|
|
start + 1..end - 1]
|
|
} else {
|
|
val[decoder.json_data[node.key_pos..node.key_pos + node.key_len]] = decoder.json_data[start..end]
|
|
}
|
|
}
|
|
}
|
|
|
|
// fulfill_nodes
|
|
fn (mut decoder Decoder) fulfill_nodes(mut nodes []Node) {
|
|
mut inside_string := false
|
|
mut inside_key := false
|
|
|
|
mut actual_key_len := 0
|
|
for decoder.idx < decoder.json_data.len {
|
|
letter := decoder.json_data[decoder.idx]
|
|
if letter == ` ` && !inside_string {
|
|
} else if letter == `\"` {
|
|
if decoder.json_data[decoder.idx - 1] == `{`
|
|
|| decoder.json_data[decoder.idx - 2] == `,` {
|
|
inside_key = true
|
|
} else if decoder.json_data[decoder.idx + 1] == `:` {
|
|
if decoder.json_data[decoder.idx + 3] == `{` {
|
|
mut children := []Node{}
|
|
key_pos := decoder.idx - actual_key_len
|
|
key_len := actual_key_len
|
|
|
|
decoder.idx += 3
|
|
decoder.fulfill_nodes(mut children)
|
|
|
|
nodes << Node{
|
|
key_pos: key_pos
|
|
key_len: key_len
|
|
children: children
|
|
}
|
|
} else {
|
|
nodes << Node{
|
|
key_pos: decoder.idx - actual_key_len
|
|
key_len: actual_key_len
|
|
}
|
|
}
|
|
|
|
inside_key = false
|
|
}
|
|
inside_string = !inside_string
|
|
decoder.idx++
|
|
continue
|
|
} else if letter == `:` {
|
|
actual_key_len = 0
|
|
} else if letter == `,` || letter == `:` || letter == `{` || letter == `}` || letter == `[`
|
|
|| letter == `]` {
|
|
} else {
|
|
}
|
|
if inside_key {
|
|
actual_key_len++
|
|
}
|
|
decoder.idx++
|
|
}
|
|
}
|