dt_automate/vendor/github.com/Andrew-M-C/go.jsonvalue/marshal.go
2025-02-27 10:48:32 +08:00

326 lines
7.4 KiB
Go

package jsonvalue
import (
"encoding/json"
"fmt"
"math"
"strings"
"github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
)
// MustMarshal is the same as Marshal. If error occurs, an empty byte slice will be returned.
//
// MustMarshal 与 Marshal 相同,但是当错误发生时,什么都不做,直接返回空数据
func (v *V) MustMarshal(opts ...Option) []byte {
ret, err := v.Marshal(opts...)
if err != nil {
return []byte{}
}
return ret
}
// MustMarshalString is the same as MarshalString, If error occurs, an empty byte slice will be returned.
//
// MustMarshalString 与 MarshalString 相同,但是当错误发生时,什么都不做,直接返回空数据
func (v *V) MustMarshalString(opt ...Option) string {
ret, err := v.MarshalString(opt...)
if err != nil {
return ""
}
return ret
}
// Marshal returns marshaled bytes.
//
// Marshal 返回序列化后的 JSON 字节序列。
func (v *V) Marshal(opts ...Option) (b []byte, err error) {
if NotExist == v.valueType {
return nil, ErrValueUninitialized
}
buf := buffer.NewBuffer()
opt := combineOptions(opts)
err = marshalToBuffer(v, nil, buf, opt)
if err != nil {
return nil, err
}
b = buf.Bytes()
return b, nil
}
// MarshalString is same with Marshal, but returns string. It is much more efficient than string(b).
//
// MarshalString 与 Marshal 相同, 不同的是返回 string 类型。它比 string(b) 操作更高效。
func (v *V) MarshalString(opts ...Option) (s string, err error) {
b, err := v.Marshal(opts...)
if err != nil {
return "", err
}
return unsafe.BtoS(b), nil
}
func marshalToBuffer(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) (err error) {
switch v.valueType {
default:
// do nothing
case String:
marshalString(v, buf, opt)
case Boolean:
marshalBoolean(v, buf)
case Number:
err = marshalNumber(v, buf, opt)
case Null:
marshalNull(buf)
case Object:
marshalObject(v, parentInfo, buf, opt)
case Array:
marshalArray(v, parentInfo, buf, opt)
}
return err
}
func marshalString(v *V, buf buffer.Buffer, opt *Opt) {
_ = buf.WriteByte('"')
escapeStringToBuff(v.valueStr, buf, opt)
_ = buf.WriteByte('"')
}
func marshalBoolean(v *V, buf buffer.Buffer) {
_, _ = buf.WriteString(formatBool(v.valueBool))
}
func marshalNumber(v *V, buf buffer.Buffer, opt *Opt) error {
if b := v.srcByte; len(b) > 0 {
_, _ = buf.Write(b)
return nil
}
// else, +Inf or -Inf or NaN
if math.IsInf(v.num.f64, 1) { // +Inf
return marshalInfP(buf, opt)
}
if math.IsInf(v.num.f64, -1) { // -Inf
return marshalInfN(buf, opt)
}
return marshalNaN(buf, opt)
}
func marshalNaN(buf buffer.Buffer, opt *Opt) error {
switch opt.FloatNaNHandleType {
default:
fallthrough
case FloatNaNTreatAsError:
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.NaN())
case FloatNaNConvertToFloat:
if !isValidFloat(opt.FloatNaNToFloat) {
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, opt.FloatNaNToFloat)
}
b, _ := json.Marshal(opt.FloatNaNToFloat)
_, _ = buf.Write(b)
case FloatNaNNull:
_, _ = buf.WriteString("null")
case FloatNaNConvertToString:
if s := opt.FloatNaNToString; s == "" {
_, _ = buf.WriteString(`"NaN"`)
} else {
_ = buf.WriteByte('"')
escapeStringToBuff(s, buf, opt)
_ = buf.WriteByte('"')
}
}
return nil
}
func marshalInfP(buf buffer.Buffer, opt *Opt) error {
switch opt.FloatInfHandleType {
default:
fallthrough
case FloatInfTreatAsError:
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.Inf(1))
case FloatInfConvertToFloat:
if !isValidFloat(opt.FloatInfToFloat) {
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, opt.FloatInfToFloat)
}
b, _ := json.Marshal(opt.FloatInfToFloat)
_, _ = buf.Write(b)
case FloatInfNull:
_, _ = buf.WriteString("null")
case FloatInfConvertToString:
if s := opt.FloatInfPositiveToString; s == "" {
_, _ = buf.WriteString(`"+Inf"`)
} else {
_ = buf.WriteByte('"')
escapeStringToBuff(s, buf, opt)
_ = buf.WriteByte('"')
}
}
return nil
}
func marshalInfN(buf buffer.Buffer, opt *Opt) error {
switch opt.FloatInfHandleType {
default:
fallthrough
case FloatInfTreatAsError:
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.Inf(-1))
case FloatInfConvertToFloat:
if !isValidFloat(opt.FloatInfToFloat) {
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, -opt.FloatInfToFloat)
}
b, _ := json.Marshal(-opt.FloatInfToFloat)
_, _ = buf.Write(b)
case FloatInfNull:
_, _ = buf.WriteString("null")
case FloatInfConvertToString:
_ = buf.WriteByte('"')
if s := opt.FloatInfNegativeToString; s != "" {
escapeStringToBuff(s, buf, opt)
} else if opt.FloatInfPositiveToString != "" {
s = "-" + strings.TrimLeft(opt.FloatInfPositiveToString, "+")
escapeStringToBuff(s, buf, opt)
} else {
_, _ = buf.WriteString(`-Inf`)
}
_ = buf.WriteByte('"')
}
return nil
}
func isValidFloat(f float64) bool {
if math.IsNaN(f) {
return false
}
if math.IsInf(f, 0) {
return false
}
return true
}
func marshalNull(buf buffer.Buffer) {
_, _ = buf.WriteString("null")
}
func marshalObject(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) {
if len(v.children.object) == 0 {
_, _ = buf.WriteString("{}")
return
}
opt.indent.cnt++
_ = buf.WriteByte('{')
if opt.MarshalLessFunc != nil {
sov := newSortObjectV(v, parentInfo, opt)
sov.marshalObjectWithLessFunc(buf, opt)
} else if len(opt.MarshalKeySequence) > 0 {
sssv := newSortStringSliceV(v, opt)
sssv.marshalObjectWithStringSlice(buf, opt)
} else if opt.marshalBySetSequence {
sssv := newSortStringSliceVBySetSeq(v)
sssv.marshalObjectWithStringSlice(buf, opt)
} else {
writeObjectKVInRandomizedSequence(v, buf, opt)
}
opt.indent.cnt--
if opt.indent.enabled {
_ = buf.WriteByte('\n')
writeIndent(buf, opt)
}
_ = buf.WriteByte('}')
}
func writeObjectKVInRandomizedSequence(v *V, buf buffer.Buffer, opt *Opt) {
firstWritten := false
for k, child := range v.children.object {
firstWritten = writeObjectChildren(nil, buf, !firstWritten, k, child.v, opt)
}
}
func writeObjectChildren(
parentInfo *ParentInfo, buf buffer.Buffer, isFirstOne bool, key string, child *V, opt *Opt,
) (written bool) {
if child.IsNull() && opt.OmitNull {
return false
}
if !isFirstOne {
_ = buf.WriteByte(',')
}
if opt.indent.enabled {
_ = buf.WriteByte('\n')
writeIndent(buf, opt)
}
_ = buf.WriteByte('"')
escapeStringToBuff(key, buf, opt)
if opt.indent.enabled {
_, _ = buf.WriteString("\": ")
} else {
_, _ = buf.WriteString("\":")
}
_ = marshalToBuffer(child, parentInfo, buf, opt)
return true
}
func writeIndent(buf buffer.Buffer, opt *Opt) {
_, _ = buf.WriteString(opt.indent.prefix)
for i := 0; i < opt.indent.cnt; i++ {
_, _ = buf.WriteString(opt.indent.indent)
}
}
func marshalArray(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) {
if len(v.children.arr) == 0 {
_, _ = buf.WriteString("[]")
return
}
opt.indent.cnt++
_ = buf.WriteByte('[')
v.RangeArray(func(i int, child *V) bool {
if i > 0 {
_ = buf.WriteByte(',')
}
if opt.indent.enabled {
_ = buf.WriteByte('\n')
writeIndent(buf, opt)
}
if opt.MarshalLessFunc == nil {
_ = marshalToBuffer(child, nil, buf, opt)
} else {
_ = marshalToBuffer(child, newParentInfo(v, parentInfo, intKey(i)), buf, opt)
}
return true
})
opt.indent.cnt--
if opt.indent.enabled {
_ = buf.WriteByte('\n')
writeIndent(buf, opt)
}
_ = buf.WriteByte(']')
}