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.
382 lines
12 KiB
382 lines
12 KiB
// ------------------------------------------------------------------------
|
|
// 🚀 Project active3
|
|
// 🔗 Active Thing (activething.com) git.activething.com/go
|
|
//
|
|
// File name packer.go
|
|
// ✍️ Created by DEV
|
|
// 📅 Modified 30/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 pkjson
|
|
|
|
import (
|
|
"apacks"
|
|
"apacks/pkstate"
|
|
"blds"
|
|
"cdcs/cjson"
|
|
"core/tups"
|
|
"encoding/json"
|
|
"reflect"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type (
|
|
|
|
rpackers struct {
|
|
mux sync.RWMutex
|
|
fncs map[reflect.Type]rPackFnc
|
|
ifcs []func(rtype reflect.Type) rPackFnc
|
|
}
|
|
|
|
|
|
rpackersFnc func(p *rpackers)
|
|
|
|
rPackFnc func(b *Builder, v reflect.Value)
|
|
)
|
|
|
|
|
|
func newRPackers (options ...rpackersFnc) *rpackers {
|
|
ib := reflect.TypeOf((*blds.Buildable)(nil)).Elem()
|
|
ij := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
|
ie := reflect.TypeOf((*error)(nil)).Elem()
|
|
|
|
ifcs := []func(rt reflect.Type) rPackFnc {
|
|
// Buildable
|
|
func(t reflect.Type) rPackFnc {
|
|
if t.Implements(ib) {
|
|
return func(b *Builder, v reflect.Value) {
|
|
b.Buildable(v.Interface().(blds.Buildable))
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
// jsonMarshaler
|
|
func(t reflect.Type) rPackFnc {
|
|
if t.Implements(ij) {
|
|
return func(b *Builder, v reflect.Value) {
|
|
b.Marshaller(v.Interface().(json.Marshaler))
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
// error
|
|
func(t reflect.Type) rPackFnc {
|
|
if t.Implements(ie) {
|
|
return func(b *Builder, v reflect.Value) {
|
|
b.Error(v.Interface().(error))
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
fncs := map[reflect.Type]rPackFnc {
|
|
reflect.TypeOf("") : func(b *Builder, v reflect.Value) { b.String(v.String())},
|
|
reflect.TypeOf(false) : func(b *Builder, v reflect.Value) { b.Bool (v.Bool())},
|
|
|
|
reflect.TypeOf(int (0)) : func(b *Builder, v reflect.Value) { b.Int64(v.Int()) },
|
|
reflect.TypeOf(int8 (0)) : func(b *Builder, v reflect.Value) { b.Int64(v.Int()) },
|
|
reflect.TypeOf(int16 (0)) : func(b *Builder, v reflect.Value) { b.Int64(v.Int()) },
|
|
reflect.TypeOf(int32 (0)) : func(b *Builder, v reflect.Value) { b.Int64(v.Int()) },
|
|
reflect.TypeOf(int64 (0)) : func(b *Builder, v reflect.Value) { b.Int64(v.Int()) },
|
|
|
|
reflect.TypeOf(uint (0)) : func(b *Builder, v reflect.Value) { b.Uint64(v.Uint()) },
|
|
reflect.TypeOf(uint8 (0)) : func(b *Builder, v reflect.Value) { b.Uint64(v.Uint()) },
|
|
reflect.TypeOf(uint16(0)) : func(b *Builder, v reflect.Value) { b.Uint64(v.Uint()) },
|
|
reflect.TypeOf(uint32(0)) : func(b *Builder, v reflect.Value) { b.Uint64(v.Uint()) },
|
|
reflect.TypeOf(uint64(0)) : func(b *Builder, v reflect.Value) { b.Uint64(v.Uint()) },
|
|
|
|
reflect.TypeOf(float32(0)) : func(b *Builder, v reflect.Value) { b.float(v.Float(),32)},
|
|
reflect.TypeOf(float64(0)) : func(b *Builder, v reflect.Value) { b.float(v.Float(),64)},
|
|
|
|
reflect.TypeOf(time.Time{}) : func(b *Builder, v reflect.Value) { b.Time(v.Interface().(time.Time)) },
|
|
reflect.TypeOf(time.Duration(0)): func(b *Builder, v reflect.Value) { b.Duration(v.Interface().(time.Duration))},
|
|
|
|
|
|
reflect.TypeOf([]string(nil)) : func(b *Builder, v reflect.Value) { packListG[string ] (b,v.Interface().([]string ), b.String)},
|
|
reflect.TypeOf([]bool (nil)) : func(b *Builder, v reflect.Value) { packListG[bool ] (b,v.Interface().([]bool ), b.Bool) },
|
|
|
|
reflect.TypeOf([]int (nil)) : func(b *Builder, v reflect.Value) { packListG[int ] (b,v.Interface().([]int ), b.Int) },
|
|
reflect.TypeOf([]int8 (nil)) : func(b *Builder, v reflect.Value) { packListG[int8 ] (b,v.Interface().([]int8 ), b.Int8) },
|
|
reflect.TypeOf([]int16 (nil)) : func(b *Builder, v reflect.Value) { packListG[int16 ] (b,v.Interface().([]int16 ), b.Int16) },
|
|
reflect.TypeOf([]int32 (nil)) : func(b *Builder, v reflect.Value) { packListG[int32 ] (b,v.Interface().([]int32 ), b.Int32) },
|
|
reflect.TypeOf([]int64 (nil)) : func(b *Builder, v reflect.Value) { packListG[int64 ] (b,v.Interface().([]int64 ), b.Int64) },
|
|
|
|
reflect.TypeOf([]uint (nil)) : func(b *Builder, v reflect.Value) { packListG[uint ] (b,v.Interface().([]uint ), b.Uint) },
|
|
reflect.TypeOf([]uint8 (nil)) : func(b *Builder, v reflect.Value) { packListG[uint8 ] (b,v.Interface().([]uint8 ), b.Uint8) },
|
|
reflect.TypeOf([]uint16(nil)) : func(b *Builder, v reflect.Value) { packListG[uint16 ] (b,v.Interface().([]uint16 ), b.Uint16)},
|
|
reflect.TypeOf([]uint32(nil)) : func(b *Builder, v reflect.Value) { packListG[uint32 ] (b,v.Interface().([]uint32 ), b.Uint32)},
|
|
reflect.TypeOf([]uint64(nil)) : func(b *Builder, v reflect.Value) { packListG[uint64 ] (b,v.Interface().([]uint64 ), b.Uint64)},
|
|
reflect.TypeOf([]uintptr(nil)): func(b *Builder, v reflect.Value) { packListG[uintptr] (b,v.Interface().([]uintptr), b.Uintptr)},
|
|
|
|
reflect.TypeOf([]float32(nil)): func(b *Builder, v reflect.Value) { packListG[float32] (b,v.Interface().([]float32), b.Float32)},
|
|
reflect.TypeOf([]float64(nil)): func(b *Builder, v reflect.Value) { packListG[float64] (b,v.Interface().([]float64), b.Float64)},
|
|
|
|
reflect.TypeOf([]time.Time (nil)): func(b *Builder, v reflect.Value) { packListG[time.Time ] (b,v.Interface().([]time.Time) , b.Time)},
|
|
reflect.TypeOf([]time.Duration(nil)): func(b *Builder, v reflect.Value) { packListG[time.Duration] (b,v.Interface().([]time.Duration), b.Duration)},
|
|
reflect.TypeOf([]error(nil)) : func(b *Builder, v reflect.Value) {
|
|
var l []error
|
|
if !v.IsNil() {
|
|
l = v.Interface().([]error)
|
|
}
|
|
b.buildLevel(pkstate.ModeList, l == nil, len(l) == 0, func(bl *Builder) {
|
|
for _, e := range l {
|
|
bl.Item()
|
|
if bl.Err == nil {
|
|
bl.Error(e)
|
|
}
|
|
if bl.Err != nil {
|
|
return
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
|
|
reflect.TypeOf(map[string]string(nil)) : func(b *Builder, v reflect.Value) { packMapG[string ] (b,v.Interface().(map[string]string ), b.String)},
|
|
reflect.TypeOf(map[string]bool (nil)) : func(b *Builder, v reflect.Value) { packMapG[bool ] (b,v.Interface().(map[string]bool ), b.Bool) },
|
|
|
|
reflect.TypeOf(map[string]int (nil)) : func(b *Builder, v reflect.Value) { packMapG[int ] (b,v.Interface().(map[string]int ), b.Int) },
|
|
reflect.TypeOf(map[string]int8 (nil)) : func(b *Builder, v reflect.Value) { packMapG[int8 ] (b,v.Interface().(map[string]int8 ), b.Int8) },
|
|
reflect.TypeOf(map[string]int16 (nil)) : func(b *Builder, v reflect.Value) { packMapG[int16 ] (b,v.Interface().(map[string]int16 ), b.Int16) },
|
|
reflect.TypeOf(map[string]int32 (nil)) : func(b *Builder, v reflect.Value) { packMapG[int32 ] (b,v.Interface().(map[string]int32 ), b.Int32) },
|
|
reflect.TypeOf(map[string]int64 (nil)) : func(b *Builder, v reflect.Value) { packMapG[int64 ] (b,v.Interface().(map[string]int64 ), b.Int64) },
|
|
|
|
reflect.TypeOf(map[string]uint (nil)) : func(b *Builder, v reflect.Value) { packMapG[uint ] (b,v.Interface().(map[string]uint ), b.Uint) },
|
|
reflect.TypeOf(map[string]uint8 (nil)) : func(b *Builder, v reflect.Value) { packMapG[uint8 ] (b,v.Interface().(map[string]uint8 ), b.Uint8) },
|
|
reflect.TypeOf(map[string]uint16(nil)) : func(b *Builder, v reflect.Value) { packMapG[uint16 ] (b,v.Interface().(map[string]uint16 ), b.Uint16)},
|
|
reflect.TypeOf(map[string]uint32(nil)) : func(b *Builder, v reflect.Value) { packMapG[uint32 ] (b,v.Interface().(map[string]uint32 ), b.Uint32)},
|
|
reflect.TypeOf(map[string]uint64(nil)) : func(b *Builder, v reflect.Value) { packMapG[uint64 ] (b,v.Interface().(map[string]uint64 ), b.Uint64)},
|
|
reflect.TypeOf(map[string]uintptr(nil)): func(b *Builder, v reflect.Value) { packMapG[uintptr] (b,v.Interface().(map[string]uintptr), b.Uintptr)},
|
|
|
|
reflect.TypeOf(map[string]float32(nil)): func(b *Builder, v reflect.Value) { packMapG[float32] (b,v.Interface().(map[string]float32), b.Float32)},
|
|
reflect.TypeOf(map[string]float64(nil)): func(b *Builder, v reflect.Value) { packMapG[float64] (b,v.Interface().(map[string]float64), b.Float64)},
|
|
|
|
reflect.TypeOf(map[string]time.Time (nil)) : func(b *Builder, v reflect.Value) { packMapG[time.Time ] (b,v.Interface().(map[string]time.Time) , b.Time)},
|
|
reflect.TypeOf(map[string]time.Duration(nil)): func(b *Builder, v reflect.Value) { packMapG[time.Duration] (b,v.Interface().(map[string]time.Duration), b.Duration)},
|
|
reflect.TypeOf(map[string]error(nil)) : func(b *Builder, v reflect.Value) {
|
|
var l map[string]error
|
|
if !v.IsNil() {
|
|
l = v.Interface().(map[string]error)
|
|
}
|
|
b.buildLevel(pkstate.ModeMap, l == nil, len(l) == 0, func(bl *Builder) {
|
|
for k,v := range l {
|
|
bl.Field(k)
|
|
if bl.Err == nil {
|
|
bl.Error(v)
|
|
}
|
|
if bl.Err != nil {
|
|
return
|
|
}
|
|
}
|
|
})
|
|
},
|
|
}
|
|
|
|
p := &rpackers{
|
|
fncs: fncs,
|
|
ifcs: ifcs,
|
|
}
|
|
for _,o := range options {
|
|
o(p)
|
|
}
|
|
return p
|
|
}
|
|
|
|
|
|
func (p *rpackers) getRPacker (rtype reflect.Type) rPackFnc {
|
|
p.mux.RLock()
|
|
fn, hs := p.fncs[rtype]
|
|
if hs {
|
|
p.mux.RUnlock()
|
|
return fn
|
|
|
|
}
|
|
for _,i := range p.ifcs {
|
|
if fn = i(rtype); fn != nil {
|
|
break
|
|
}
|
|
}
|
|
p.mux.RUnlock()
|
|
|
|
if fn == nil {
|
|
fn = p.buildRPacker(rtype)
|
|
}
|
|
p.mux.Lock()
|
|
p.fncs[rtype]=fn
|
|
p.mux.Unlock()
|
|
|
|
return fn
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *rpackers) buildRPacker (rtype reflect.Type) rPackFnc {
|
|
|
|
switch rtype.Kind() {
|
|
|
|
case reflect.Pointer:
|
|
eleFn := p.getRPacker(rtype.Elem())
|
|
return func(b *Builder, v reflect.Value) {
|
|
if v.IsNil() {
|
|
if !b.preValue() {
|
|
return
|
|
}
|
|
b.B.W(cjson.G.NullValue)
|
|
b.postValue()
|
|
return
|
|
}
|
|
|
|
b.Level++
|
|
if b.Level > maxCyclesAfter {
|
|
if fn,ok := b.CheckCycle(v.Interface()); ok {
|
|
defer fn()
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
eleFn(b,v.Elem())
|
|
b.Level--
|
|
}
|
|
|
|
case reflect.Interface:
|
|
return func(b *Builder, v reflect.Value) {
|
|
if v.IsNil() {
|
|
if !b.preValue() {
|
|
return
|
|
}
|
|
b.B.W(cjson.G.NullValue)
|
|
b.postValue()
|
|
return
|
|
}
|
|
p.getRPacker(v.Elem().Type())(b,v.Elem())
|
|
}
|
|
|
|
case reflect.Slice,
|
|
reflect.Array :
|
|
|
|
eleFn := p.getRPacker(rtype.Elem())
|
|
return func(b *Builder, v reflect.Value) {
|
|
if v.IsNil() {
|
|
if b.preValue() {
|
|
b.B.W(cjson.G.NullValue)
|
|
}
|
|
b.postValue()
|
|
return
|
|
}
|
|
|
|
if b.Level > maxCyclesAfter {
|
|
c := struct {
|
|
p any
|
|
l int
|
|
}{
|
|
p: v.UnsafePointer(),
|
|
l: v.Len(),
|
|
}
|
|
if fn,ok := b.CheckCycle(c); ok {
|
|
defer fn()
|
|
} else {
|
|
b.SetError(apack.G.ErrRedundantPack)
|
|
return
|
|
}
|
|
}
|
|
|
|
b.buildLevel(pkstate.ModeList, false, v.Len() == 0, func(bl *Builder){
|
|
for i:=0; i<v.Len();i++ {
|
|
bl.Item()
|
|
eleFn(bl,v.Index(i))
|
|
if bl.Err != nil {
|
|
return
|
|
}
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
case reflect.Map :
|
|
kfn := g.stringer.getRStringer(rtype.Key())
|
|
if kfn == nil {
|
|
return func(b *Builder, _ reflect.Value) {
|
|
b.SetError(apack.G.ErrInvalidKey)
|
|
}
|
|
}
|
|
vfn := p.getRPacker(rtype.Elem())
|
|
|
|
return func(b *Builder, v reflect.Value) {
|
|
if b.Level > maxCyclesAfter {
|
|
if fn,ok := b.CheckCycle(v.UnsafePointer()); ok {
|
|
defer fn()
|
|
} else {
|
|
b.SetError(apack.G.ErrRedundantPack)
|
|
return
|
|
}
|
|
}
|
|
|
|
mi := v.MapRange()
|
|
ls := make([]tups.GTuple[string,reflect.Value],v.Len())
|
|
for i:=0; mi.Next(); i++ {
|
|
rs := kfn(mi.Key())
|
|
if !rs.Ok() {
|
|
b.SetError(apack.G.ErrInvalidKey.WithCause(rs.Fail()))
|
|
return
|
|
}
|
|
ls[i]=tups.GTuple[string,reflect.Value]{
|
|
A : rs.Value(),
|
|
B : mi.Value(),
|
|
}
|
|
}
|
|
sort.Slice(ls,func(i,j int) bool {
|
|
return ls[i].A < ls[j].A
|
|
})
|
|
|
|
b.buildLevel(pkstate.ModeMap,v.IsNil(),v.Len() == 0,func(bl *Builder){
|
|
for i:=0; i<len(ls); i++ {
|
|
bl.Field(ls[i].A)
|
|
if b.Err == nil {
|
|
vfn(bl,ls[i].B)
|
|
}
|
|
if b.Err != nil {
|
|
return
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
|
|
case reflect.Struct :
|
|
return (*newRObject(rtype)).pack
|
|
|
|
default:
|
|
|
|
return func(b *Builder, v reflect.Value) {
|
|
b.SetError(apack.G.ErrInvalidValue) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|