aboutsummaryrefslogblamecommitdiff
path: root/model/node.go
blob: 1483eafdc05dd289033003eb235a175d652f5bbc (plain) (tree)


















































































































                                                                                        
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
	}
}