encode.gno
1.86 Kb ยท 117 lines
1package json
2
3import (
4 "bytes"
5 "errors"
6 "strconv"
7
8 "gno.land/p/demo/ufmt"
9)
10
11// Marshal returns the JSON encoding of a Node.
12func Marshal(node *Node) ([]byte, error) {
13 var (
14 buf bytes.Buffer
15 sVal string
16 bVal bool
17 nVal float64
18 oVal []byte
19 err error
20 )
21
22 if node == nil {
23 return nil, errors.New("node is nil")
24 }
25
26 if !node.modified && !node.ready() {
27 return nil, errors.New("node is not ready")
28 }
29
30 if !node.modified && node.ready() {
31 buf.Write(node.source())
32 }
33
34 if node.modified {
35 switch node.nodeType {
36 case Null:
37 buf.Write(nullLiteral)
38
39 case Number:
40 nVal, err = node.GetNumeric()
41 if err != nil {
42 return nil, err
43 }
44
45 num := strconv.FormatFloat(nVal, 'f', -1, 64)
46 buf.WriteString(num)
47
48 case String:
49 sVal, err = node.GetString()
50 if err != nil {
51 return nil, err
52 }
53
54 quoted := ufmt.Sprintf("%s", strconv.Quote(sVal))
55 buf.WriteString(quoted)
56
57 case Boolean:
58 bVal, err = node.GetBool()
59 if err != nil {
60 return nil, err
61 }
62
63 bStr := ufmt.Sprintf("%t", bVal)
64 buf.WriteString(bStr)
65
66 case Array:
67 buf.WriteByte(bracketOpen)
68
69 for i := 0; i < len(node.next); i++ {
70 if i != 0 {
71 buf.WriteByte(comma)
72 }
73
74 elem, ok := node.next[strconv.Itoa(i)]
75 if !ok {
76 return nil, ufmt.Errorf("array element %d is not found", i)
77 }
78
79 oVal, err = Marshal(elem)
80 if err != nil {
81 return nil, err
82 }
83
84 buf.Write(oVal)
85 }
86
87 buf.WriteByte(bracketClose)
88
89 case Object:
90 buf.WriteByte(curlyOpen)
91
92 bVal = false
93 for k, v := range node.next {
94 if bVal {
95 buf.WriteByte(comma)
96 } else {
97 bVal = true
98 }
99
100 key := ufmt.Sprintf("%s", strconv.Quote(k))
101 buf.WriteString(key)
102 buf.WriteByte(colon)
103
104 oVal, err = Marshal(v)
105 if err != nil {
106 return nil, err
107 }
108
109 buf.Write(oVal)
110 }
111
112 buf.WriteByte(curlyClose)
113 }
114 }
115
116 return buf.Bytes(), nil
117}