You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
active/proteus/pjson/json_packer.go

479 lines
12 KiB

// ------------------------------------------------------------------------
// Project atila
// Active Thing (activething.com) git.activething.com/go
//
// File name value_packer.go
// Created by DEV
// Modified 06/02/2024
//
// Copyright 2024 activething.com
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------
package pjson
import (
"cdecs/cjson"
"crypts"
"encoding/json"
"errs"
"packs"
"reflect"
"time"
)
type (
JSONPacker struct {
state *proteus.State
dirty bool
}
JSONPackerFnc func (packer *JSONPacker)
)
func NewJSONPacker(options ...JSONPackerFnc) *JSONPacker {
pk := &JSONPacker{
state : proteus.NewState(),
}
for _,o := range options {
o(pk)
}
return pk
}
func (p *JSONPacker) Pack (value any, flags proteus.Flags) {
if p.state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(p.state.Error))
}
if p.dirty {
panic(proteus.G.ErrInvalidState)
}
p.dirty = true
p.PackAny(value,flags)
}
func (p *JSONPacker) Packet () []byte {
return p.state.Bytes() }
func (p *JSONPacker) Error () error {
return p.state.Error }
func (p *JSONPacker) Reset () {
p.state.Reset()
p.dirty = false
}
func (p *JSONPacker) Release () {
p.dirty = false
proteus.ReleaseState(p.state)
}
func (p *JSONPacker) PackAny (value any, flags proteus.Flags) {
if p.state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(p.state.Error))
}
if value == nil {
p.state.W(cjson.G.NullValue)
return
}
switch v := value.(type) {
case proteus.Builder:
p.state.SetError(v.Build(p))
case json.Marshaler:
d,e := v.MarshalJSON()
if e != nil {
p.state.SetError(e)
} else {
p.state.W(d)
}
case bool : packBool (p.state,v,flags )
case string : packString(p.state,v,flags )
case int : packInt(p.state,int64(v),flags)
case int8 : packInt(p.state,int64(v),flags)
case int16 : packInt(p.state,int64(v),flags)
case int32 : packInt(p.state,int64(v),flags)
case int64 : packInt(p.state,v,flags )
case uint : packUInt(p.state,uint64(v),flags)
case uint8 : packUInt(p.state,uint64(v),flags)
case uint16 : packUInt(p.state,uint64(v),flags)
case uint32 : packUInt(p.state,uint64(v),flags)
case uint64 : packUInt(p.state,v,flags )
case float32: packFloatString(p.state,float64(v),flags,32)
case float64: packFloatString(p.state,v,flags,64)
case time.Time: packDate (p.state,v,flags)
case reflect.Value: rTypePacker(v.Type())(p.state,v,flags)
case []uint8 :
if flags.Binary() {
packBinary(p.state,v,flags)
return
}
packListUInt[uint8 ](p.state,v,flags)
case []uint : packListUInt [uint ] (p.state,v,flags)
case []uint16 : packListUInt [uint16] (p.state,v,flags)
case []uint32 : packListUInt [uint32] (p.state,v,flags)
case []uint64 : packListUInt [uint64] (p.state,v,flags)
case []int : packListInt [int ] (p.state,v,flags)
case []int8 : packListInt [int8 ] (p.state,v,flags)
case []int16 : packListInt [int16] (p.state,v,flags)
case []int32 : packListInt [int32] (p.state,v,flags)
case []int64 : packListInt [int64] (p.state,v,flags)
case []float32: packListFloat[float32](p.state,v,flags,32)
case []float64: packListFloat[float64](p.state,v,flags,64)
case []bool : packListBool (p.state,v,flags)
case []string : packListString(p.state,v,flags)
case []time.Time: packListDate(p.state,v,flags)
default:
rv := reflect.ValueOf(value)
rTypePacker(rv.Type())(p.state,rv,flags)
}
}
func (p *JSONPacker) PackRaw (value []byte, flags proteus.Flags) { packRaw(p.state,value,flags) }
func (p *JSONPacker) PackBinary (value []byte, flags proteus.Flags) { packBinary(p.state,value,flags) }
func (p *JSONPacker) PackString (value string, flags proteus.Flags) { packString (p.state,value,flags) }
func (p *JSONPacker) PackBool (value bool, flags proteus.Flags) { packBool(p.state,value,flags) }
func (p *JSONPacker) PackInt8 (value int8 , flags proteus.Flags) { packInt(p.state,int64(value),flags) }
func (p *JSONPacker) PackInt16 (value int16, flags proteus.Flags) { packInt(p.state,int64(value),flags) }
func (p *JSONPacker) PackInt32 (value int32, flags proteus.Flags) { packInt(p.state,int64(value),flags) }
func (p *JSONPacker) PackInt64 (value int64, flags proteus.Flags) { packInt(p.state,value,flags)}
func (p *JSONPacker) PackUInt8 (value uint8 , flags proteus.Flags) { packUInt(p.state,uint64(value),flags) }
func (p *JSONPacker) PackUInt16 (value uint16, flags proteus.Flags) { packUInt(p.state,uint64(value),flags) }
func (p *JSONPacker) PackUInt32 (value uint32, flags proteus.Flags) { packUInt(p.state,uint64(value),flags) }
func (p *JSONPacker) PackUInt64 (value uint64, flags proteus.Flags) { packUInt(p.state, value,flags) }
func (p *JSONPacker) PackFloat32 (value float32, flags proteus.Flags) { packFloatString(p.state, float64(value), flags, 32) }
func (p *JSONPacker) PackFloat64 (value float64, flags proteus.Flags) { packFloatString(p.state, value, flags, 64) }
func (p *JSONPacker) PackDate (value time.Time, flags proteus.Flags) { packDate(p.state,value,flags) }
func (p *JSONPacker) PackList (builder func(proteus.ListPackBuilder, proteus.Flags), flags proteus.Flags) {
p.packCompound('[',']',builder==nil,func(pk *JSONPacker, fl proteus.Flags){ builder(pk,fl) },flags)
}
func (p *JSONPacker) PackMap (builder func(proteus.MapPackBuilder, proteus.Flags), flags proteus.Flags) {
p.packCompound('{','}',builder==nil,func(pk *JSONPacker, fl proteus.Flags){ builder(pk,fl) },flags)
}
func (p *JSONPacker) PackObject(builder func(proteus.ObjectPackBuilder, proteus.Flags), flags proteus.Flags) {
p.packCompound('{','}',builder==nil,func(pk *JSONPacker, fl proteus.Flags){ builder(pk,fl) },flags)
}
func (p *JSONPacker) packCompound (opener, closer byte, isnil bool, buildFn func(*JSONPacker, proteus.Flags), flags proteus.Flags) {
if p.state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(p.state.Error))
}
if isnil {
p.state.W(cjson.G.NullValue)
return
}
dn := false
defer func(d *bool) {
if !(*d) {
p.state.SetError(errs.ToError(recover()))
}
}(&dn)
p.state.Open(opener)
buildFn(p,flags)
if p.state.Error != nil {
return
}
p.state.Close(closer)
dn = true
}
func packRaw (state *proteus.State, value []byte, flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
if value == nil {
state.W(cjson.G.NullValue)
return
}
if len(value) == 0 {
state.Write2Byte('"','"')
return
}
state.WOQ(flags.Quote(),'"',value)
}
func packString (state *proteus.State, value string , flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
if len(value) == 0 {
state.Write2Byte('"','"')
return
}
if flags.Encrypted() {
packEncrypted(state, []byte(value), flags|proteus.FlagBinary64)
return
}
if flags.Binary() {
packBinary(state,[]byte(value),flags)
return
}
cjson.WriteString(state.ABuffer,value,flags.EscapeHTML())
}
func packEncrypted (state *proteus.State, value []byte, flags proteus.Flags) {
r := state.Encrypter.Encrypt(value)
if !r.Ok() {
state.SetError(r.Fail())
return
}
if !flags.Binary() {
flags|= proteus.FlagBinary64
}
packBinary(state,value,flags)
}
func packBinary (state *proteus.State, value []byte , flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
if flags.Bin64() {
state.SetError(cjson.WriteBase64(state.ABuffer,value))
return
}
if flags.Bin32() {
state.SetError(cjson.WriteBase32(state.ABuffer,value))
return
}
state.SetError(proteus.G.ErrUnsupportedType)
}
func packBool (state *proteus.State, value bool , flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
cjson.WriteBool(state.ABuffer,value,flags.Quote())
}
func packInt (state *proteus.State, value int64 , flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
cjson.WriteInt(state.ABuffer,value,flags.Quote())
}
func packUInt (state *proteus.State, value uint64 , flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
cjson.WriteUint(state.ABuffer,value,flags.Quote())
}
func packFloat (state *proteus.State, value float64, flags proteus.Flags) {
packFloatString(state, value, flags, 64) }
func packFloatString (state *proteus.State, f float64, flags proteus.Flags, bits int) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
cjson.WriteFloat(state.ABuffer,f,bits,flags.Quote())
}
func packDate(state *proteus.State, value time.Time, flags proteus.Flags) {
if state.Error != nil {
panic(proteus.G.ErrInvalidState.WrapWithCause(state.Error))
}
cjson.WriteDate(state.ABuffer,value,flags.DateFormat(),true)
}
func packListString (state *proteus.State, list []string, flags proteus.Flags) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packString(state,v,flags)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func packListBool (state *proteus.State, list []bool, flags proteus.Flags) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packBool(state,v,flags)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func packListInt [T int | int8 | int16 | int32 | int64](state *proteus.State, list []T, flags proteus.Flags) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packInt(state,int64(v),flags)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func packListUInt [T uint | uint8 | uint16 | uint32 | uint64](state *proteus.State, list []T, flags proteus.Flags) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packUInt(state,uint64(v),flags)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func packListFloat[T float32 | float64](state *proteus.State, list []T, flags proteus.Flags, bits int) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packFloatString(state,float64(v),flags,bits)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func packListDate (state *proteus.State, list []time.Time, flags proteus.Flags) {
if !checkList(state,list == nil, len(list) ==0) {
return
}
state.WriteByte('[')
for i,v := range list {
if i > 0 {
state.WriteByte(',')
}
packDate(state,v,flags)
if state.Error != nil {
return
}
}
state.WriteByte(']')
}
func checkList (state *proteus.State, isNull, isEmpty bool) bool {
if isNull {
state.Write2Byte('"','"')
return false
}
if isEmpty {
state.Write2Byte('[',']')
return false
}
return true
}
func WithEncrypter(encrypter crypts.Encrypter) JSONPackerFnc {
return func(p *JSONPacker) {
if encrypter == nil {
encrypter = crypts.EncrypterNop{}
}
p.state.Encrypter = encrypter
}
}

Powered by TurnKey Linux.