json/model/node.go

116 lines
2.2 KiB
Go

package model
import (
"bytes"
"fmt"
"strconv"
)
// Node of JSON tree
type Node struct {
Type NodeType
stringValue string
numberValue float64
objectValue NodeObjectValue
arrayValue NodeArrayValue
booleanValue bool
}
// NewNode creates new node from value
func NewNode(value any) *Node {
n := new(Node)
n.SetValue(value)
return n
}
// Value returns value of node
func (n *Node) Value() any {
switch n.Type {
case StringNode:
return n.stringValue
case NumberNode:
return n.numberValue
case ObjectNode:
return n.objectValue
case ArrayNode:
return n.arrayValue
case BooleanNode:
return n.booleanValue
default:
return nil
}
}
// SetValue to node
func (n *Node) SetValue(value any) {
switch value := value.(type) {
case string:
n.Type = StringNode
n.stringValue = value
case float64:
n.Type = NumberNode
n.numberValue = value
case int:
n.Type = NumberNode
n.numberValue = float64(value)
case NodeObjectValue:
n.Type = ObjectNode
n.objectValue = value
case NodeArrayValue:
n.Type = ArrayNode
n.arrayValue = value
case bool:
n.Type = BooleanNode
n.booleanValue = value
default:
n.Type = NullNode
}
}
// MarshalJSON to []byte
func (n *Node) MarshalJSON() ([]byte, error) {
switch n.Type {
case StringNode:
return []byte(`"` + n.stringValue + `"`), nil
case NumberNode:
return []byte(strconv.FormatFloat(n.numberValue, 'g', -1, 64)), nil
case ObjectNode:
result := make([][]byte, 0, len(n.objectValue))
for k, v := range n.objectValue {
b, err := v.MarshalJSON()
if err != nil {
return nil, err
}
result = append(result, []byte(fmt.Sprintf("\"%s\": %s", k, b)))
}
return bytes.Join(
[][]byte{
[]byte("{"),
bytes.Join(result, []byte(", ")),
[]byte("}"),
}, []byte("")), nil
case ArrayNode:
result := make([][]byte, 0, len(n.arrayValue))
for _, v := range n.arrayValue {
b, err := v.MarshalJSON()
if err != nil {
return nil, err
}
result = append(result, b)
}
return bytes.Join(
[][]byte{
[]byte("["),
bytes.Join(result, []byte(", ")),
[]byte("]"),
}, []byte("")), nil
case BooleanNode:
if n.booleanValue {
return []byte("true"), nil
}
return []byte("false"), nil
default:
return []byte("null"), nil
}
}