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.

573 lines
11 KiB

// ------------------------------------------------------------------------
// 🚀 Project active3
// 🔗 Active Thing (activething.com) git.activething.com/go
//
// File name builder.go
// ✍️ Created by DEV
// 📅 Modified 28/05/2024
//
// 🔒 Copyright 2024 activething.com
//
// 📜 LICENSE --------------------------------------------------------------
// 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 pkj
import (
"apack"
"apack/pstate"
"blds"
"cdcs/cjson"
"encoding/json"
"reflect"
"rsls"
"time"
)
type (
Builder struct {
*pstate.State
e *json.Encoder
f apack.Flags
}
)
func NewBuilder () *Builder {
return &Builder{
State : pstate.AcquireState(),
}
}
func (b *Builder) Pack (value any) rsls.Bytes {
b.Any(value)
if b.Err != nil {
return rsls.MakeBytesError(b.Err)
}
return rsls.MakeBytesSuccess(b.B.Bytes())
}
func (b *Builder) Any (value any) {
if value == nil {
if !b.preValue() {
return
}
b.B.W(cjson.G.NullValue)
b.postValue()
return
}
if bl,is := value.(blds.Buildable); is {
b.Buildable(bl)
return
}
if ms,is := value.(json.Marshaler); is {
b.Marshaller(ms)
return
}
switch v := value.(type) {
case string:
b.String(v)
case int8:
b.Int64(int64(v))
case int16:
b.Int64(int64(v))
case int32:
b.Int64(int64(v))
case int64:
b.Int64(v)
case uint8:
b.Uint64(uint64(v))
case uint16:
b.Uint64(uint64(v))
case uint32:
b.Uint64(uint64(v))
case uintptr:
b.Uint64(uint64(v))
case uint64:
b.Uint64(v)
case float32:
b.float(float64(v), 32)
case float64:
b.float(v, 64)
case bool:
b.Bool(v)
case time.Time:
b.Time(v)
case time.Duration:
b.Int64(int64(v))
case error:
b.Error(v)
case []bool:
packListG[bool](b, v, b.Bool)
case []string:
packListG[string](b, v, b.String)
case []int:
packListG[int](b, v, b.Int)
case []int8:
packListG[int8](b, v, b.Int8)
case []int16:
packListG[int16](b, v, b.Int16)
case []int32:
packListG[int32](b, v, b.Int32)
case []int64:
packListG[int64](b, v, b.Int64)
case []uint:
packListG[uint](b, v, b.Uint)
case []uint8:
packListG[uint8](b, v, b.Uint8)
case []uint16:
packListG[uint16](b, v, b.Uint16)
case []uint32:
packListG[uint32](b, v, b.Uint32)
case []uint64:
packListG[uint64](b, v, b.Uint64)
case []uintptr:
packListG[uintptr](b, v, b.Uintptr)
case []time.Time:
packListG[time.Time](b, v, b.Time)
case []time.Duration:
packListG[time.Duration](b, v, b.Duration)
case []error:
b.buildLevel(pstate.ModeList, v == nil, len(v) == 0, func(bl *Builder) {
for _, e := range v {
bl.Item()
if bl.Err == nil {
bl.Error(e)
}
if bl.Err != nil {
return
}
}
})
case map[string]bool:
packMapG[bool](b, v, b.Bool)
case map[string]string:
packMapG[string](b, v, b.String)
case map[string]int:
packMapG[int](b, v, b.Int)
case map[string]int8:
packMapG[int8](b, v, b.Int8)
case map[string]int16:
packMapG[int16](b, v, b.Int16)
case map[string]int32:
packMapG[int32](b, v, b.Int32)
case map[string]int64:
packMapG[int64](b, v, b.Int64)
case map[string]uint:
packMapG[uint](b, v, b.Uint)
case map[string]uint8:
packMapG[uint8](b, v, b.Uint8)
case map[string]uint16:
packMapG[uint16](b, v, b.Uint16)
case map[string]uint32:
packMapG[uint32](b, v, b.Uint32)
case map[string]uint64:
packMapG[uint64](b, v, b.Uint64)
case map[string]uintptr:
packMapG[uintptr](b, v, b.Uintptr)
case map[string]time.Time:
packMapG[time.Time](b, v, b.Time)
case map[string]time.Duration:
packMapG[time.Duration](b, v, b.Duration)
case map[string]error:
b.buildLevel(pstate.ModeMap, v == nil, len(v) == 0, func(bl *Builder) {
for k, v := range v {
bl.Field(k)
if bl.Err == nil {
bl.Error(v)
}
if b.Err != nil {
return
}
}
})
case reflect.Value:
g.rpackers.getRPacker(v.Type())(b,v)
default:
rv := reflect.ValueOf(value)
g.rpackers.getRPacker(rv.Type())(b,rv)
}
}
func (b *Builder) Raw (value []byte) {
if !b.preValue() {
return
}
if value == nil {
b.B.W(cjson.G.NullValue)
} else if len(value) == 0 {
b.B.W(cjson.G.EmptyValue)
} else {
b.B.W(value)
}
b.postValue()
}
func (b *Builder) Binary(value []byte) {
if !b.preValue() {
return
}
b.writeBinary(value,b.f)
b.postValue()
}
func (b *Builder) String (value string) {
if !b.preValue() {
return
}
b.writeString(value,b.f)
b.postValue()
}
func (b *Builder) Bool (value bool) {
if !b.preValue() { return }
cjson.WriteBool(b.B,value)
b.postValue()
}
func (b *Builder) Int (value int ){ b.Int64(int64(value)) }
func (b *Builder) Int8 (value int8 ){ b.Int64(int64(value)) }
func (b *Builder) Int16 (value int16 ){ b.Int64(int64(value)) }
func (b *Builder) Int32 (value int32 ){ b.Int64(int64(value)) }
func (b *Builder) Int64 (value int64 ){
if !b.preValue() {
return
}
cjson.WriteInt(b.B,value)
b.postValue()
}
func (b *Builder) Uint (value uint ){ b.Uint64(uint64(value)) }
func (b *Builder) Uint8 (value uint8 ){ b.Uint64(uint64(value)) }
func (b *Builder) Uint16 (value uint16 ){ b.Uint64(uint64(value)) }
func (b *Builder) Uint32 (value uint32 ){ b.Uint64(uint64(value)) }
func (b *Builder) Uintptr (value uintptr){ b.Uint64(uint64(value)) }
func (b *Builder) Uint64 (value uint64 ){
if !b.preValue() {
return
}
cjson.WriteUint(b.B,value)
b.postValue()
}
func (b *Builder) Float32 (value float32){
b.float(float64(value),32) }
func (b *Builder) Float64 (value float64){
b.float(value,64) }
func (b *Builder) float (value float64, bits int) {
if !b.preValue() {
return
}
cjson.WriteFloat(b.B,value,bits)
b.postValue()
}
func (b *Builder) Time (value time.Time) {
if !b.preValue() {
return
}
cjson.WriteTime(b.B,value,b.f.DateFormat())
b.postValue()
}
func (b *Builder) Duration (value time.Duration) { b.Int64(int64(value)) }
func (b *Builder) Error (value error) {
if !b.preValue() {
return
}
if value == nil {
b.B.W(cjson.G.NullValue)
} else {
b.writeString(value.Error(), b.f|apack.FlagScapeHTML)
}
b.postValue()
}
func (b *Builder) Buildable (value blds.Buildable) {
if !b.preValue() {
return
}
if value == nil {
} else {
value.Build(b)
}
b.postValue()
}
func (b *Builder) Marshaller (value json.Marshaler) {
if !b.preValue() {
return
}
if value == nil {
b.B.W(cjson.G.NullValue)
} else {
dt, er := value.MarshalJSON()
if b.SetError(er) {
return
}
b.B.W(dt)
}
b.postValue()
}
func (b *Builder) writeString (value string, flags apack.Flags) {
if len(value) == 0 {
b.B.W(cjson.G.EmptyValue)
return
}
if flags.Encrypted() {
b.writeEncrypted([]byte(value),flags)
return
}
if flags.Binary() {
b.writeBinary([]byte(value),flags)
return
}
cjson.WriteString(b.B,value,flags.EscapeHTML())
}
func (b *Builder) writeEncrypted(value []byte, flags apack.Flags) {
if b.Encrypter == nil {
b.SetError(apack.G.ErrInvalidEncrypter)
return
}
rs := b.Encrypter.Encrypt(value)
if !rs.Ok() {
b.SetError(rs.Fail())
return
}
b.writeBinary(rs.Value(),flags)
}
func (b *Builder) writeBinary (value []byte, flags apack.Flags) {
if flags.Bin32() {
b.SetError(cjson.WriteBase32(b.B,value))
return
}
b.SetError(cjson.WriteBase64(b.B,value))
}
func (b *Builder) List (fnc func(builder blds.ListBuilder)) {
b.buildLevel(pstate.ModeList,fnc==nil,false,func(bl *Builder){
fnc(b) }) }
func (b *Builder) Map (fnc func(builder blds.MapBuilder)) {
b.buildLevel(pstate.ModeMap,fnc == nil, false, func(bl *Builder){
fnc(b) }) }
func (b *Builder) Object (fnc func(builder blds.ObjectBuilder)) {
b.buildLevel(pstate.ModeObject,fnc == nil, false, func(bl *Builder){
fnc(b) }) }
func (b *Builder) Item () blds.ValueBuilder {
if b.preElem() {
b.Current.IsValue = true
}
return b
}
func (b *Builder) Key (key any) blds.ValueBuilder {
if key == nil {
b.SetError(apack.G.ErrInvalidKey.WithMessage("key is null"))
return b
}
rs := g.stringer.getStringer(key)
if !rs.Ok() {
b.SetError(apack.G.ErrInvalidKey.WithCause(rs.Fail()))
return b
}
return b.Field(rs.Value())
}
func (b *Builder) Field (name string) blds.ValueBuilder {
if len(name) == 0 {
b.SetError(apack.G.ErrInvalidKey.WithMessage("key is empty"))
return b
}
if b.preElem() {
b.writeString(name,apack.FlagScapeHTML)
}
return b.postElem()
}
func (b *Builder) buildLevel (mode pstate.Mode, isNil, isEmpty bool, buildFnc func(builder *Builder)) {
if !b.preValue() {
return
}
if isNil {
b.B.W(cjson.G.NullValue)
b.postValue()
return
}
if isEmpty {
if mode == pstate.ModeList {
b.B.Write2Byte('[',']')
} else {
b.B.Write2Byte('{','}')
}
b.postValue()
return
}
b.Open(mode)
be := byte('}')
if mode == pstate.ModeList {
b.B.WriteByte('[')
be = ']'
} else {
b.B.WriteByte('{')
}
buildFnc(b)
if b.Err != nil {
return
}
b.B.WriteByte(be)
b.Close(mode)
b.postValue()
}
func (b *Builder) preValue () bool {
if b.Err != nil {
panic(apack.G.ErrInvalidState.WithCause(b.Err))
}
if !b.Current.IsValue {
_ = b.SetError(apack.G.ErrStateInvalidElem)
return false
}
return true
}
func (b *Builder) postValue () {
if b.Err != nil {
return
}
b.Current.IsValue = false
b.Current.Count++
if b.Current.Mode == pstate.ModeValue {
b.Current.Mode = pstate.ModeNone
}
}
func (b *Builder) preElem () bool {
if b.Err != nil {
panic(apack.G.ErrInvalidState.WithCause(b.Err))
}
if b.Current.IsValue {
_ = b.SetError(apack.G.ErrStateInvalidElem)
return false
}
if b.Current.Count > 0 {
b.B.WriteByte(',')
}
return true
}
func (b *Builder) postElem () *Builder {
if b.Err == nil {
b.Current.IsValue = true
b.B.WriteByte(':')
}
return b
}
func (b *Builder) encode (value any) error {
if b.e == nil {
b.e = json.NewEncoder(b.B)
}
return b.e.Encode(value)
}
func packListG[T basicTypes](b *Builder, list []T, fncType func(vl T)) {
b.buildLevel(pstate.ModeList,list == nil, len(list) == 0,func(bl *Builder){
for _,v := range list {
b.Item()
if b.Err == nil {
fncType(v)
}
if bl.Err != nil {
return
}
}
})
}
func packMapG[T basicTypes](b *Builder, m map[string]T, fncType func(vl T)) {
b.buildLevel(pstate.ModeMap, m == nil, len(m) == 0, func(bl *Builder){
for k,v := range m {
// Usamos b.Field y no b.Key porque sabemos que no es necesario
// hacerle un stringify y el objeto como el map la codificación
// json es la misma
b.Field(k)
if b.Err == nil {
fncType(v)
}
if b.Err != nil {
return
}
}
})
}

Powered by TurnKey Linux.