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}