diff --git a/a/main.go b/a/main.go index f6af466..32235eb 100644 --- a/a/main.go +++ b/a/main.go @@ -2,6 +2,7 @@ package main import ( "apack/pkjson" + "blds" "errs" "errs/eftext" "fmt" @@ -11,7 +12,7 @@ import ( type ( - S = struct { + S struct { A string } ) @@ -27,6 +28,11 @@ func randomInt(min, max int) int { } +func (s S) Build (b blds.Builder) { + b.String("Esto es un campo S") +} + + func main() { @@ -50,6 +56,7 @@ func main() { "catorce": 15.16, "dfate": time.Now(), time.Now(): "ff", + "SSSS" : S{A:"a"}, } diff --git a/base/apack/pkj/active.go b/base/apack/pkj/active.go new file mode 100644 index 0000000..0db80da --- /dev/null +++ b/base/apack/pkj/active.go @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------ +// 🚀 Project active3 +// 🔗 Active Thing (activething.com) git.activething.com/go +// +// File name active.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 "time" + +type ( + + basicTypes interface { + ~bool | ~string | + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | + ~float32 | ~float64 | + time.Time + } + +) + + +var ( + + + g = struct { + stringer keyStringer + }{ + + stringer: keyStringer{}, + } +) + + diff --git a/base/apack/pkj/builder.go b/base/apack/pkj/builder.go new file mode 100644 index 0000000..5c8cc58 --- /dev/null +++ b/base/apack/pkj/builder.go @@ -0,0 +1,255 @@ +// ------------------------------------------------------------------------ +// 🚀 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" +) + +type ( + + Builder struct { + *pstate.State + } + + +) + + + +func (b *Builder) String (value string) {} + +func (b *Builder) Bool (value bool) {} + + +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() { + //nothing siempre es mode value + } + return b +} + +func (b *Builder) Key (key any) blds.ValueBuilder { + if b.preElem() { + if key == nil { + b.SetError(apack.G.ErrInvalidKey.WithMessage("key is null")) + return b + } + g.stringer.packKey(b,key) + } + return b.postElem() +} + +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 packAny (b *Builder, value any) { + + switch tp := value.(type) { + case []bool : packList[bool ](b,tp,0,b.Bool) + case []string : packList[string](b,tp,0,b.String) + } +} + + +func packList [T basicTypes](b *Builder, list []T, flags apack.Flags, fncType func(vl T)) { + b.buildLevel(pstate.ModeList,list == nil, len(list) == 0,func(bl *Builder){ + for i,v := range list { + if i > 0 { + bl.B.WriteByte(',') + } + fncType(v) + if bl.Err != nil { + return + } + } + }) +} + + + + + + + diff --git a/base/apack/pkj/key_stringer.go b/base/apack/pkj/key_stringer.go new file mode 100644 index 0000000..31faed7 --- /dev/null +++ b/base/apack/pkj/key_stringer.go @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------ +// 🚀 Project active3 +// 🔗 Active Thing (activething.com) git.activething.com/go +// +// File name stringer.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 + + + + +type ( + + keyStringer struct {} + +) + + + + +func (s *keyStringer) packKey (b *Builder, value any) {} + diff --git a/base/apack/pkjson/active.go b/base/apack/pkjson/active.go index 4ee7d78..ab4acf5 100644 --- a/base/apack/pkjson/active.go +++ b/base/apack/pkjson/active.go @@ -26,6 +26,7 @@ package pkjson import ( "apack" + "blds" "cdcs/cjson" "encoding" "encoding/json" @@ -60,19 +61,22 @@ var ( g = struct { + buildableType reflect.Type stringifyType reflect.Type jsonMarshalerType reflect.Type textMarshalerType reflect.Type - keyStringer *keyStringer + keyStringer keyStringer packersCache sync.Map }{ - stringifyType: reflect.TypeOf((*stringify)(nil)).Elem(), + buildableType : reflect.TypeOf((*blds.Buildable)(nil)).Elem(), + stringifyType : reflect.TypeOf((*stringify)(nil)).Elem(), jsonMarshalerType: reflect.TypeOf((*json.Marshaler)(nil)).Elem(), textMarshalerType: reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem(), - keyStringer: defaultKeyStringer(), + keyStringer : *defaultKeyStringer(), + packersCache: *defaultPackers(), } ) @@ -83,11 +87,18 @@ var ( func defaultPackers () *sync.Map { mp := &sync.Map{} + mp.Store(reflect.TypeOf(time.Now()),func(b *Builder, v reflect.Value){ + b.Time(v.Interface().(time.Time)) + }) + mp.Store(reflect.TypeOf(time.Duration(0)),func(b *Builder, v reflect.Value){ + b.Duration(v.Interface().(time.Duration)) + }) return mp } + func defaultKeyStringer () *keyStringer { return newKeyStringer(func(s *keyStringer){ diff --git a/base/apack/pkjson/builder.go b/base/apack/pkjson/builder.go index c7a4e42..be0fd71 100644 --- a/base/apack/pkjson/builder.go +++ b/base/apack/pkjson/builder.go @@ -67,27 +67,21 @@ func (b *Builder) Pack (value any) []byte { func (b *Builder) Any (value any) { - b.checkValue() if value == nil { + b.checkValue() _,_ = b.B.Write(cjson.G.NullValue) b.postValue() + return } if bl,is := value.(blds.Buildable); is { - bl.Build(b) - b.postValue() + b.Buildable(bl) return } if jm,is := value.(json.Marshaler); is { - dt,er := jm.MarshalJSON() - if er != nil { - b.SetError(er) - return - } - b.B.W(dt) - b.postValue() + b.Marshaller(jm) return } @@ -229,11 +223,38 @@ func (b *Builder) Time (value time.Time){ func (b *Builder) Duration(value time.Duration){ b.Int64(int64(value)) } + func (b *Builder) Reflect (value reflect.Value){ //todo reflect } +func (b *Builder) Buildable(value blds.Buildable) { + b.checkValue() + if value == nil { + _,_ = b.B.Write(cjson.G.NullValue) + } else { + value.Build(b) + } + b.postValue() +} + + + +func (b *Builder) Marshaller(value json.Marshaler) { + b.checkValue() + if value == nil { + _,_ = b.B.Write(cjson.G.NullValue) + } else { + dt, er := value.MarshalJSON() + if b.SetError(er) { + return + } + b.B.W(dt) + } + b.postValue() +} + func (b *Builder) List (fnc func (listBuilder blds.ListBuilder )){ @@ -416,93 +437,3 @@ func (b *Builder) writeSepIf(cond bool) { - -func packListString (p *Builder, list []string, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - p.packString(v, flags) - if p.Err != nil { - return - } - } - }) -} - - -func packListError (p *Builder, list []error, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - if v == nil { - b.B.WOQ(true,'"',cjson.G.NullValue) - continue - } - p.packString(v.Error(), apack.FlagScapeHTML) - } - }) -} - - -func packListBool (p *Builder, list []bool, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - cjson.WriteBool(p.B,v) - } - }) -} - - -func packListInt [T int | int8 | int16 | int32 | int64 | time.Duration](p *Builder, list []T, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - cjson.WriteInt(p.B,int64(v)) - } - }) -} - - -func packListUInt [T uint | uint8 | uint16 | uint32 | uint64|uintptr](p *Builder, list []T, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - cjson.WriteUint(p.B,uint64(v)) - } - }) -} - - -func packListFloat[T float32 | float64](p *Builder, list []T, flags apack.Flags, bits int) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - cjson.WriteFloat(p.B,float64(v),bits) - } - }) -} - - -func packListDate (p *Builder, list []time.Time, flags apack.Flags) { - p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ - for i,v := range list { - if i > 0 { - p.B.WriteByte(sep) - } - cjson.WriteTime(p.B,v,flags.DateFormat()) - } - }) -} diff --git a/base/apack/pkjson/packer.go b/base/apack/pkjson/packer.go index 1f92991..d3334cd 100644 --- a/base/apack/pkjson/packer.go +++ b/base/apack/pkjson/packer.go @@ -64,5 +64,3 @@ func (p Packer) Pack (value any) rsls.Bytes { - - diff --git a/base/apack/pkjson/packer_list.go b/base/apack/pkjson/packer_list.go new file mode 100644 index 0000000..c2f2379 --- /dev/null +++ b/base/apack/pkjson/packer_list.go @@ -0,0 +1,122 @@ +// ------------------------------------------------------------------------ +// 🚀 Project active3 +// 🔗 Active Thing (activething.com) git.activething.com/go +// +// File name list_packer.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 pkjson + +import ( + "apack" + "apack/pstate" + "cdcs/cjson" + "time" +) + +func packListString (p *Builder, list []string, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + p.packString(v, flags) + if p.Err != nil { + return + } + } + }) +} + + +func packListError (p *Builder, list []error, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + if v == nil { + b.B.WOQ(true,'"',cjson.G.NullValue) + continue + } + p.packString(v.Error(), apack.FlagScapeHTML) + } + }) +} + + +func packListBool (p *Builder, list []bool, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + cjson.WriteBool(p.B,v) + } + }) +} + + +func packListInt [T int | int8 | int16 | int32 | int64 | time.Duration](p *Builder, list []T, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + cjson.WriteInt(p.B,int64(v)) + } + }) +} + + +func packListUInt [T uint | uint8 | uint16 | uint32 | uint64|uintptr](p *Builder, list []T, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + cjson.WriteUint(p.B,uint64(v)) + } + }) +} + + +func packListFloat[T float32 | float64](p *Builder, list []T, flags apack.Flags, bits int) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + cjson.WriteFloat(p.B,float64(v),bits) + } + }) +} + + +func packListDate (p *Builder, list []time.Time, flags apack.Flags) { + p.makeLevel(pstate.ModeList,list == nil, len(list) == 0,func(b *Builder){ + for i,v := range list { + if i > 0 { + p.B.WriteByte(sep) + } + cjson.WriteTime(p.B,v,flags.DateFormat()) + } + }) +} diff --git a/base/apack/pkjson/reflected.go b/base/apack/pkjson/reflected.go index ed34041..bbc7213 100644 --- a/base/apack/pkjson/reflected.go +++ b/base/apack/pkjson/reflected.go @@ -26,7 +26,9 @@ package pkjson import ( "apack" + "blds" "cdcs/cjson" + "encoding/json" "reflect" "sync" ) @@ -67,6 +69,20 @@ func packReflected(rtype reflect.Type) PackReflectedFnc { func makePackReflectedFn(rtype reflect.Type) PackReflectedFnc { + + if rtype.Implements(g.buildableType) { + return func (b *Builder, v reflect.Value) { + b.Buildable(v.Interface().(blds.Buildable)) + } + } + + if rtype.Implements(g.jsonMarshalerType) { + return func (b *Builder, v reflect.Value) { + b.Marshaller(v.Interface().(json.Marshaler)) + } + } + + switch rtype.Kind() { case reflect.Bool : return func(b *Builder, v reflect.Value) { b.Bool(v.Bool()) }