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.

165 lines
4.0 KiB

// ------------------------------------------------------------------------
// 🚀 Project active3
// 🔗 Active Thing (activething.com) git.activething.com/go
//
// File name key_stringer.go
// ✍️ Created by DEV
// 📅 Modified 11/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 (
"apack"
"cdcs/cjson"
"errs"
"reflect"
"sync"
"time"
)
type (
keyStringer struct {
sync.RWMutex
stringers map[reflect.Type]rMapEntryFnc
ifaceCheckers []func(p reflect.Type) rMapEntryFnc
}
keyStringerFnc func (s *keyStringer)
)
func newKeyStringer (options...keyStringerFnc) *keyStringer {
s := &keyStringer{
stringers: make(map[reflect.Type]rMapEntryFnc),
}
for _,o := range options {
o(s)
}
return s
}
func (s *keyStringer) packStringifyKey (b *Builder, key any) {
switch v := key.(type) {
case string : b.packString(v,apack.FlagScapeHTML)//
case bool : cjson.WriteBool (b.B,v)
case uint : cjson.WriteUint (b.B,uint64(v))
case uint8 : cjson.WriteUint (b.B,uint64(v))
case uint16 : cjson.WriteUint (b.B,uint64(v))
case uint32 : cjson.WriteUint (b.B,uint64(v))
case uintptr : cjson.WriteUint (b.B,uint64(v))
case uint64 : cjson.WriteUint (b.B,v)
case int : cjson.WriteInt (b.B,int64(v))
case int8 : cjson.WriteInt (b.B,int64(v))
case int16 : cjson.WriteInt (b.B,int64(v))
case int32 : cjson.WriteInt (b.B,int64(v))
case int64 : cjson.WriteInt (b.B,v)
case float64 : cjson.WriteFloat (b.B,v,64)
case float32 : cjson.WriteFloat (b.B,float64(v),32)
case time.Time : cjson.WriteTime (b.B,v,b.f.DateFormat())
case time.Duration : cjson.WriteInt (b.B,int64(v))
case error :
if ec,is := v.(errs.ErrCoder); is {
b.packString(ec.Code(),apack.FlagScapeHTML)
return
}
b.packString(v.Error(),apack.FlagScapeHTML)
default:
me := &rMapEntry{ v: reflect.ValueOf(key) }
fn := g.keyStringer.getOrBuildStringer(me.v.Type())
if fn == nil {
b.SetError(apack.G.ErrInvalidKey.WithMessage("cant convert Key to string"))
return
}
if er := fn(me,me.v); er != nil {
b.SetError(er)
return
}
b.packString(me.k,me.f)
}
}
func (s *keyStringer) getOrBuildStringer(rtype reflect.Type) rMapEntryFnc {
s.RLock()
if fn,hs := s.stringers[rtype]; hs {
s.Unlock()
return fn
}
fn := s.checkInterfaces(rtype)
if fn == nil {
fn = s.defaultStringer
}
s.RUnlock()
if fn != nil {
s.Lock()
s.stringers[rtype]=fn
s.Unlock()
}
return fn
}
func (s *keyStringer) defaultStringer(e *rMapEntry, k reflect.Value) error {
k = k.Elem()
fn := s.stringers[k.Type()]
if fn != nil {
return fn(e,k)
}
if fn = s.checkInterfaces(k.Type()); fn != nil {
return fn(e,k)
}
return apack.G.ErrInvalidKey.WithMessageF("%s", k.String())
}
func (s *keyStringer) RegKeyStringer (rtype reflect.Type, stringerFn rMapEntryFnc) {
if stringerFn == nil {
return
}
s.Lock()
s.stringers[rtype]=stringerFn
s.Unlock()
}
func (s *keyStringer) RegInterfaceChecker (checkfn ... func(p reflect.Type) rMapEntryFnc) {
s.ifaceCheckers = append(s.ifaceCheckers,checkfn ...) }
func (s *keyStringer) checkInterfaces (rtype reflect.Type) rMapEntryFnc {
for _,cf := range s.ifaceCheckers {
if fn := cf(rtype); fn != nil {
return fn
}
}
return nil
}

Powered by TurnKey Linux.