aboutsummaryrefslogtreecommitdiff
path: root/model/node.go
diff options
context:
space:
mode:
Diffstat (limited to 'model/node.go')
-rw-r--r--model/node.go115
1 files changed, 115 insertions, 0 deletions
diff --git a/model/node.go b/model/node.go
new file mode 100644
index 0000000..1483eaf
--- /dev/null
+++ b/model/node.go
@@ -0,0 +1,115 @@
+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
+ }
+}