599 lines
16 KiB
Go
599 lines
16 KiB
Go
// Package jsonvalue is for JSON parsing and setting. It is used in situations those
|
||
// Go structures cannot achieve, or "map[string]any" could not do properly.
|
||
//
|
||
// As a quick start:
|
||
//
|
||
// v := jsonvalue.NewObject()
|
||
// v.SetString("Hello, JSON").At("someObject", "someObject", "someObject", "message") // automatically create sub objects
|
||
// fmt.Println(v.MustMarshalString()) // marshal to string type. Use MustMarshal if you want []byte instead.
|
||
// // Output:
|
||
// // {"someObject":{"someObject":{"someObject":{"message":"Hello, JSON!"}}}
|
||
//
|
||
// If you want to parse raw JSON data, use Unmarshal()
|
||
//
|
||
// raw := []byte(`{"message":"hello, world"}`)
|
||
// v, err := jsonvalue.Unmarshal(raw)
|
||
// s, _ := v.GetString("message")
|
||
// fmt.Println(s)
|
||
// // Output:
|
||
// // hello, world
|
||
//
|
||
// jsonvalue 包用于 JSON 的解析(反序列化)和编码(序列化)。通常情况下我们用 struct 来处理
|
||
// 结构化的 JSON,但是有时候使用 struct 不方便或者是功能不足的时候,go 一般而言使用的是
|
||
// "map[string]any",但是后者也有很多不方便的地方。本包即是用于替代这些不方便的情况的。
|
||
//
|
||
// 快速上手:
|
||
//
|
||
// v := jsonvalue.NewObject()
|
||
// v.SetString("Hello, JSON").At("someObject", "someObject", "someObject", "message") // 自动创建子成员
|
||
// fmt.Println(v.MustMarshalString()) // 序列化为 string 类型,如果你要 []byte 类型,则使用 MustMarshal 函数。
|
||
// // 输出:
|
||
// // {"someObject":{"someObject":{"someObject":{"message":"Hello, JSON!"}}}
|
||
//
|
||
// 如果要反序列化原始的 JSON 文本,则使用 Unmarshal():
|
||
//
|
||
// raw := []byte(`{"message":"hello, world"}`)
|
||
// v, err := jsonvalue.Unmarshal(raw)
|
||
// s, _ := v.GetString("message")
|
||
// fmt.Println(s)
|
||
// // 输出:
|
||
// // hello, world
|
||
package jsonvalue
|
||
|
||
import (
|
||
"bytes"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
|
||
)
|
||
|
||
// ValueType identifying JSON value type
|
||
type ValueType int
|
||
|
||
const (
|
||
// NotExist type tells that this JSON value is not exist or legal
|
||
NotExist ValueType = iota
|
||
// String JSON string type
|
||
String
|
||
// Number JSON number type
|
||
Number
|
||
// Object JSON object type
|
||
Object
|
||
// Array JSON array type
|
||
Array
|
||
// Boolean JSON boolean type
|
||
Boolean
|
||
// Null JSON null type
|
||
Null
|
||
// Unknown unknown JSON type
|
||
Unknown
|
||
)
|
||
|
||
var typeStr = [Unknown + 1]string{
|
||
"illegal",
|
||
"string",
|
||
"number",
|
||
"object",
|
||
"array",
|
||
"boolean",
|
||
"null",
|
||
"unknown",
|
||
}
|
||
|
||
// String show the type name of JSON
|
||
func (t ValueType) String() string {
|
||
if t > Unknown {
|
||
t = NotExist
|
||
} else if t < 0 {
|
||
t = NotExist
|
||
}
|
||
return typeStr[int(t)]
|
||
}
|
||
|
||
// ValueType returns the type of this JSON value.
|
||
func (v *V) ValueType() ValueType {
|
||
return v.valueType
|
||
}
|
||
|
||
// V is the main type of jsonvalue, representing a JSON value.
|
||
//
|
||
// V 是 jsonvalue 的主类型,表示一个 JSON 值。
|
||
type V struct {
|
||
valueType ValueType
|
||
|
||
srcByte []byte
|
||
|
||
num num
|
||
valueStr string
|
||
valueBool bool
|
||
children children
|
||
}
|
||
|
||
type num struct {
|
||
negative bool
|
||
floated bool
|
||
i64 int64
|
||
u64 uint64
|
||
f64 float64
|
||
}
|
||
|
||
type childWithProperty struct {
|
||
id uint32
|
||
v *V
|
||
}
|
||
|
||
type children struct {
|
||
incrID uint32
|
||
arr []*V
|
||
object map[string]childWithProperty
|
||
|
||
// As official json package supports caseless key accessing, I decide to do it as well
|
||
lowerCaseKeys map[string]map[string]struct{}
|
||
}
|
||
|
||
func (c *children) deepCopy() children {
|
||
res := children{
|
||
incrID: c.incrID,
|
||
}
|
||
|
||
// if length or arr > 0, this must be an array type
|
||
if len(c.arr) > 0 {
|
||
for _, v := range c.arr {
|
||
res.arr = append(res.arr, v.deepCopy())
|
||
}
|
||
return res
|
||
}
|
||
|
||
// if this is an object?
|
||
if c.object != nil {
|
||
res.object = make(map[string]childWithProperty, len(c.object))
|
||
for key, item := range c.object {
|
||
res.object[key] = childWithProperty{
|
||
id: item.id,
|
||
v: item.v.deepCopy(),
|
||
}
|
||
}
|
||
}
|
||
|
||
// no need to copy lowerCaseKeys because it could be rebuild after calling
|
||
// Caseless() next time
|
||
|
||
return res
|
||
}
|
||
|
||
func addCaselessKey(v *V, k string) {
|
||
if v.children.lowerCaseKeys == nil {
|
||
return
|
||
}
|
||
lowerK := strings.ToLower(k)
|
||
keys, exist := v.children.lowerCaseKeys[lowerK]
|
||
if !exist {
|
||
keys = make(map[string]struct{})
|
||
v.children.lowerCaseKeys[lowerK] = keys
|
||
}
|
||
keys[k] = struct{}{}
|
||
}
|
||
|
||
func delCaselessKey(v *V, k string) {
|
||
if v.children.lowerCaseKeys == nil {
|
||
return
|
||
}
|
||
lowerK := strings.ToLower(k)
|
||
keys, exist := v.children.lowerCaseKeys[lowerK]
|
||
if !exist {
|
||
return
|
||
}
|
||
|
||
delete(keys, k)
|
||
|
||
if len(keys) == 0 {
|
||
delete(v.children.lowerCaseKeys, lowerK)
|
||
}
|
||
}
|
||
|
||
// MustUnmarshalString just like UnmarshalString(). If error occurs, a JSON value
|
||
// with "NotExist" type would be returned, which could do nothing and return nothing
|
||
// in later use. It is useful to shorten codes.
|
||
//
|
||
// MustUnmarshalString 的逻辑与 UnmarshalString() 相同,不过如果错误的话,会返回一个类型未
|
||
// "NotExist" 的 JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。
|
||
// 但起码不会导致程序 panic,便于使用短代码实现一些默认逻辑。
|
||
func MustUnmarshalString(s string) *V {
|
||
v, _ := UnmarshalString(s)
|
||
return v
|
||
}
|
||
|
||
// UnmarshalString is equivalent to Unmarshal([]byte(b)), but more efficient.
|
||
//
|
||
// UnmarshalString 等效于 Unmarshal([]byte(b)),但效率更高。
|
||
func UnmarshalString(s string) (*V, error) {
|
||
// reference: https://stackoverflow.com/questions/41591097/slice-bounds-out-of-range-when-using-unsafe-pointer
|
||
// sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||
// bh := reflect.SliceHeader{
|
||
// Data: sh.Data,
|
||
// Len: sh.Len,
|
||
// Cap: sh.Len,
|
||
// }
|
||
// b := *(*[]byte)(unsafe.Pointer(&bh))
|
||
b := []byte(s)
|
||
return UnmarshalNoCopy(b)
|
||
}
|
||
|
||
// MustUnmarshal just like Unmarshal(). If error occurs, a JSON value with "NotExist"
|
||
// type would be returned, which could do nothing and return nothing in later use. It
|
||
// is useful to shorten codes.
|
||
//
|
||
// MustUnmarshal 的逻辑与 Unmarshal() 相同,不过如果错误的话,会返回一个类型未 "NotExist" 的
|
||
// JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。但起码不会导致程序
|
||
// panic,便于使用短代码实现一些默认逻辑。
|
||
func MustUnmarshal(b []byte) *V {
|
||
v, _ := Unmarshal(b)
|
||
return v
|
||
}
|
||
|
||
// Unmarshal parse raw bytes(encoded in UTF-8 or pure AscII) and returns a *V instance.
|
||
//
|
||
// Unmarshal 解析原始的字节类型数据(以 UTF-8 或纯 AscII 编码),并返回一个 *V 对象。
|
||
func Unmarshal(b []byte) (ret *V, err error) {
|
||
le := len(b)
|
||
if le == 0 {
|
||
return nil, ErrNilParameter
|
||
}
|
||
|
||
trueB := make([]byte, len(b))
|
||
copy(trueB, b)
|
||
it := iter(trueB)
|
||
p := newPool(len(b))
|
||
ret, err = unmarshalWithIter(p, it, 0)
|
||
p.release()
|
||
return
|
||
}
|
||
|
||
// MustUnmarshalNoCopy just like UnmarshalNoCopy(). If error occurs, a JSON value
|
||
// with "NotExist" type would be returned, which could do nothing and return nothing
|
||
// in later use. It is useful to shorten codes.
|
||
//
|
||
// MustUnmarshalNoCopy 的逻辑与 UnmarshalNoCopy() 相同,不过如果错误的话,会返回一个类型未
|
||
// "NotExist" 的 JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。
|
||
// 但起码不会导致程序 panic,便于使用短代码实现一些默认逻辑。
|
||
func MustUnmarshalNoCopy(b []byte) *V {
|
||
v, _ := UnmarshalNoCopy(b)
|
||
return v
|
||
}
|
||
|
||
// UnmarshalNoCopy is same as Unmarshal, but it does not copy another []byte instance
|
||
// for saving CPU time. But pay attention that the input []byte may be used as buffer
|
||
// by jsonvalue and mey be modified.
|
||
//
|
||
// UnmarshalNoCopy 与 Unmarshal 相同,但是这个函数在解析过程中不会重新复制一个 []byte,对于大
|
||
// json 的解析而言能够大大节省时间。但请注意传入的 []byte 变量可能会被 jsonvalue 用作缓冲区,并进行修改
|
||
func UnmarshalNoCopy(b []byte) (ret *V, err error) {
|
||
le := len(b)
|
||
if le == 0 {
|
||
return &V{}, ErrNilParameter
|
||
}
|
||
p := newPool(len(b))
|
||
ret, err = unmarshalWithIter(p, iter(b), 0)
|
||
p.release()
|
||
return
|
||
}
|
||
|
||
// ==== type access ====
|
||
|
||
// IsObject tells whether value is an object
|
||
//
|
||
// IsObject 判断当前值是不是一个对象类型
|
||
func (v *V) IsObject() bool {
|
||
return v.valueType == Object
|
||
}
|
||
|
||
// IsArray tells whether value is an array
|
||
//
|
||
// IsArray 判断当前值是不是一个数组类型
|
||
func (v *V) IsArray() bool {
|
||
return v.valueType == Array
|
||
}
|
||
|
||
// IsString tells whether value is a string
|
||
//
|
||
// IsString 判断当前值是不是一个字符串类型
|
||
func (v *V) IsString() bool {
|
||
return v.valueType == String
|
||
}
|
||
|
||
// IsNumber tells whether value is a number
|
||
//
|
||
// IsNumber 判断当前值是不是一个数字类型
|
||
func (v *V) IsNumber() bool {
|
||
return v.valueType == Number
|
||
}
|
||
|
||
// IsFloat tells whether value is a float point number. If there is no decimal point
|
||
// in original text, it returns false while IsNumber returns true.
|
||
//
|
||
// IsFloat 判断当前值是不是一个浮点数类型。如果给定的数不包含小数点,那么即便是数字类型,该函数也会返回 false.
|
||
func (v *V) IsFloat() bool {
|
||
if v.valueType != Number {
|
||
return false
|
||
}
|
||
return v.num.floated
|
||
}
|
||
|
||
// IsInteger tells whether value is a fix point integer
|
||
//
|
||
// IsNumber 判断当前值是不是一个定点数整型
|
||
func (v *V) IsInteger() bool {
|
||
if v.valueType != Number {
|
||
return false
|
||
}
|
||
return !(v.num.floated)
|
||
}
|
||
|
||
// IsNegative tells whether value is a negative number
|
||
//
|
||
// IsNegative 判断当前值是不是一个负数
|
||
func (v *V) IsNegative() bool {
|
||
if v.valueType != Number {
|
||
return false
|
||
}
|
||
return v.num.negative
|
||
}
|
||
|
||
// IsPositive tells whether value is a positive number
|
||
//
|
||
// IsPositive 判断当前值是不是一个正数
|
||
func (v *V) IsPositive() bool {
|
||
if v.valueType != Number {
|
||
return false
|
||
}
|
||
return !(v.num.negative)
|
||
}
|
||
|
||
// GreaterThanInt64Max return true when ALL conditions below are met:
|
||
// 1. It is a number value.
|
||
// 2. It is a positive integer.
|
||
// 3. Its value is greater than 0x7fffffffffffffff.
|
||
//
|
||
// GreaterThanInt64Max 判断当前值是否超出 int64 可表示的范围。当以下条件均成立时,返回 true,
|
||
// 否则返回 false:
|
||
// 1. 是一个数字类型值.
|
||
// 2. 是一个正整型数字.
|
||
// 3. 该正整数的值大于 0x7fffffffffffffff.
|
||
func (v *V) GreaterThanInt64Max() bool {
|
||
if v.valueType != Number {
|
||
return false
|
||
}
|
||
if v.num.negative {
|
||
return false
|
||
}
|
||
return v.num.u64 > 0x7fffffffffffffff
|
||
}
|
||
|
||
// IsBoolean tells whether value is a boolean
|
||
//
|
||
// IsBoolean 判断当前值是不是一个布尔类型
|
||
func (v *V) IsBoolean() bool {
|
||
return v.valueType == Boolean
|
||
}
|
||
|
||
// IsNull tells whether value is a null
|
||
//
|
||
// IsBoolean 判断当前值是不是一个空类型
|
||
func (v *V) IsNull() bool {
|
||
return v.valueType == Null
|
||
}
|
||
|
||
// Bool returns represented bool value. If value is not boolean, returns false.
|
||
//
|
||
// Bool 返回布尔类型值。如果当前值不是布尔类型,则判断是否为 string,不是 string 返回 false;
|
||
// 是 string 的话则返回字面值是否等于 true
|
||
func (v *V) Bool() bool {
|
||
if v.valueType == Boolean {
|
||
return v.valueBool
|
||
}
|
||
b, _ := getBoolAndErrorFromValue(v)
|
||
return b.valueBool
|
||
}
|
||
|
||
// Int returns represented int value. If value is not a number, returns zero.
|
||
//
|
||
// Int 返回 int 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Int() int {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Int()
|
||
}
|
||
return int(v.num.i64)
|
||
}
|
||
|
||
// Uint returns represented uint value. If value is not a number, returns zero.
|
||
//
|
||
// Uint 返回 uint 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Uint() uint {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Uint()
|
||
}
|
||
return uint(v.num.u64)
|
||
}
|
||
|
||
// Int64 returns represented int64 value. If value is not a number, returns zero.
|
||
//
|
||
// Int64 返回 int64 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Int64() int64 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Int64()
|
||
}
|
||
return int64(v.num.i64)
|
||
}
|
||
|
||
// Uint64 returns represented uint64 value. If value is not a number, returns zero.
|
||
//
|
||
// Uint64 返回 uint64 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Uint64() uint64 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Uint64()
|
||
}
|
||
return uint64(v.num.u64)
|
||
}
|
||
|
||
// Int32 returns represented int32 value. If value is not a number, returns zero.
|
||
//
|
||
// Int32 返回 int32 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Int32() int32 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Int32()
|
||
}
|
||
return int32(v.num.i64)
|
||
}
|
||
|
||
// Uint32 returns represented uint32 value. If value is not a number, returns zero.
|
||
//
|
||
// Uint32 返回 uint32 类型值。如果当前值不是数字类型,则返回 0。
|
||
func (v *V) Uint32() uint32 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Uint32()
|
||
}
|
||
return uint32(v.num.u64)
|
||
}
|
||
|
||
// Float64 returns represented float64 value. If value is not a number, returns zero.
|
||
//
|
||
// Float64 返回 float64 类型值。如果当前值不是数字类型,则返回 0.0。
|
||
func (v *V) Float64() float64 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Float64()
|
||
}
|
||
return v.num.f64
|
||
}
|
||
|
||
// Float32 returns represented float32 value. If value is not a number, returns zero.
|
||
//
|
||
// Float32 返回 float32 类型值。如果当前值不是数字类型,则返回 0.0。
|
||
func (v *V) Float32() float32 {
|
||
if v.valueType != Number {
|
||
return getNumberFromNotNumberValue(v).Float32()
|
||
}
|
||
return float32(v.num.f64)
|
||
}
|
||
|
||
// Bytes returns represented binary data which is encoded as Base64 string. []byte{}
|
||
// would be returned if value is
|
||
// not a string type or base64 decode failed.
|
||
//
|
||
// Bytes 返回以 Base64 编码在 string 类型中的二进制数据。如果当前值不是字符串类型,或者是 base64
|
||
// 编码失败,则返回 []byte{}。
|
||
func (v *V) Bytes() []byte {
|
||
if v.valueType != String {
|
||
return []byte{}
|
||
}
|
||
b, err := internal.b64.DecodeString(v.valueStr)
|
||
if err != nil {
|
||
return []byte{}
|
||
}
|
||
return b
|
||
}
|
||
|
||
func (v *V) deepCopy() *V {
|
||
if v == nil {
|
||
return &V{}
|
||
}
|
||
|
||
switch v.valueType {
|
||
default:
|
||
// fallthrough
|
||
// case NotExist, Unknown:
|
||
return &V{}
|
||
case String:
|
||
return NewString(v.String())
|
||
case Number:
|
||
res := new(globalPool{}, Number)
|
||
res.num = v.num
|
||
res.srcByte = v.srcByte
|
||
return res
|
||
case Object:
|
||
res := new(globalPool{}, Object)
|
||
res.children = v.children.deepCopy()
|
||
return res
|
||
case Array:
|
||
res := new(globalPool{}, Array)
|
||
res.children = v.children.deepCopy()
|
||
return res
|
||
case Boolean:
|
||
return NewBool(v.Bool())
|
||
case Null:
|
||
return NewNull()
|
||
}
|
||
}
|
||
|
||
type deepCopier interface {
|
||
deepCopy() *V
|
||
}
|
||
|
||
// String returns represented string value or the description for the jsonvalue.V
|
||
// instance if it is not a string.
|
||
//
|
||
// String 返回 string 类型值。如果当前值不是字符串类型,则返回当前 *V 类型的描述说明。
|
||
func (v *V) String() string {
|
||
if v == nil {
|
||
return "nil"
|
||
}
|
||
switch v.valueType {
|
||
default:
|
||
return ""
|
||
case Null:
|
||
return "null"
|
||
case Number:
|
||
if len(v.srcByte) > 0 {
|
||
return unsafe.BtoS(v.srcByte)
|
||
}
|
||
return strconv.FormatFloat(v.num.f64, 'g', -1, 64)
|
||
case String:
|
||
return v.valueStr
|
||
case Boolean:
|
||
return formatBool(v.valueBool)
|
||
case Object:
|
||
return packObjChildren(v)
|
||
case Array:
|
||
return packArrChildren(v)
|
||
}
|
||
}
|
||
|
||
func packObjChildren(v *V) string {
|
||
buf := bytes.Buffer{}
|
||
bufObjChildren(v, &buf)
|
||
return buf.String()
|
||
}
|
||
|
||
func bufObjChildren(v *V, buf *bytes.Buffer) {
|
||
buf.WriteByte('{')
|
||
i := 0
|
||
for k, v := range v.children.object {
|
||
if i > 0 {
|
||
buf.WriteString(", ")
|
||
}
|
||
buf.WriteString(k)
|
||
buf.WriteString(": ")
|
||
buf.WriteString(v.v.String())
|
||
i++
|
||
}
|
||
buf.WriteByte('}')
|
||
}
|
||
|
||
func packArrChildren(v *V) string {
|
||
buf := bytes.Buffer{}
|
||
bufArrChildren(v, &buf)
|
||
return buf.String()
|
||
}
|
||
|
||
func bufArrChildren(v *V, buf *bytes.Buffer) {
|
||
buf.WriteByte('[')
|
||
v.RangeArray(func(i int, v *V) bool {
|
||
if i > 0 {
|
||
buf.WriteString(", ")
|
||
}
|
||
buf.WriteString(v.String())
|
||
return true
|
||
})
|
||
buf.WriteByte(']')
|
||
}
|