From 51dc2ab480073355e0e7ef1ce8269075ed9a0bab Mon Sep 17 00:00:00 2001 From: DEV Date: Wed, 24 Jan 2024 01:02:47 +0100 Subject: [PATCH] redefiniendo el builder --- go.work | 1 + packets/go.mod | 7 + packets/gogo.go | 64 ++++++ packets/list_packer.go | 64 ++++++ packets/map_packer.go | 65 +++++++ packets/node.go | 61 ++++++ packets/node_kind.go | 40 ++++ packets/object_packer.go | 66 +++++++ packets/packer.go | 63 ++++++ packets/packer_state.go | 153 +++++++++++++++ packets/pjson/gogo.go | 78 ++++++++ packets/pjson/json_char_atts.go | 41 ++++ packets/pjson/list_packer.go | 59 ++++++ packets/pjson/map_packer.go | 63 ++++++ packets/pjson/object_packer.go | 61 ++++++ packets/pjson/options.go | 33 ++++ packets/pjson/options_flags.go | 61 ++++++ packets/pjson/packer.go | 332 ++++++++++++++++++++++++++++++++ 18 files changed, 1312 insertions(+) create mode 100644 packets/go.mod create mode 100644 packets/gogo.go create mode 100644 packets/list_packer.go create mode 100644 packets/map_packer.go create mode 100644 packets/node.go create mode 100644 packets/node_kind.go create mode 100644 packets/object_packer.go create mode 100644 packets/packer.go create mode 100644 packets/packer_state.go create mode 100644 packets/pjson/gogo.go create mode 100644 packets/pjson/json_char_atts.go create mode 100644 packets/pjson/list_packer.go create mode 100644 packets/pjson/map_packer.go create mode 100644 packets/pjson/object_packer.go create mode 100644 packets/pjson/options.go create mode 100644 packets/pjson/options_flags.go create mode 100644 packets/pjson/packer.go diff --git a/go.work b/go.work index c58fe33..2e965a0 100644 --- a/go.work +++ b/go.work @@ -10,5 +10,6 @@ use ( ./core/opts ./core/syncs ./packs + ./packets ) diff --git a/packets/go.mod b/packets/go.mod new file mode 100644 index 0000000..b38dd79 --- /dev/null +++ b/packets/go.mod @@ -0,0 +1,7 @@ +module activething.com/go/gogo/packets + + +go 1.20 + + + diff --git a/packets/gogo.go b/packets/gogo.go new file mode 100644 index 0000000..1e915a0 --- /dev/null +++ b/packets/gogo.go @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 23/01/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 packets + +import ( + "activething.com/go/gogo/core/errs" + "activething.com/go/gogo/core/syncs" +) + +var ( + + G = struct { + + poolsSem uint32 + statePool *syncs.Pool[State] + nodePool *syncs.Pool[Node] + + ErrInvalidNode errs.ErrCode + ErrInvalidElement errs.ErrCode + ErrInvalidKey errs.ErrCode + ErrDuplicatedKey errs.ErrCode + ErrKeyRequired errs.ErrCode + ErrValueRequired errs.ErrCode + ErrInvalidList errs.ErrCode + ErrRedundantPack errs.ErrCode + ErrInvalidValue errs.ErrCode + }{ + ErrInvalidNode : errs.ErrCode("packs.invalid-StateNode"), + ErrInvalidElement: errs.ErrCode("packs.invalid-element"), + ErrInvalidKey : errs.ErrCode("packs.invalid-key"), + ErrDuplicatedKey : errs.ErrCode("packs:duplicated-key"), + ErrKeyRequired : errs.ErrCode("packs:key-required"), + ErrValueRequired : errs.ErrCode("packs:value-required"), + ErrInvalidList : errs.ErrCode("packs:invalid-list"), + ErrRedundantPack : errs.ErrCode("packs:redundant-pack"), + ErrInvalidValue : errs.ErrCode("packs:invalid-value"), + } +) + + + + + diff --git a/packets/list_packer.go b/packets/list_packer.go new file mode 100644 index 0000000..4fdb4f0 --- /dev/null +++ b/packets/list_packer.go @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name list_Itemer.go +// Created by DEV +// Modified 23/01/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 packets + +import "time" + +type ( + + ListPacker interface { + + Item (value any) + + ItemRaw (value []byte) + + ItemBinary (value []byte) + ItemString (value string) + + ItemBool (value bool) + + ItemInt8 (value int8) + ItemInt16 (value int16) + ItemInt32 (value int32) + ItemInt64 (value int64) + + ItemUInt8 (value uint8) + ItemUInt16 (value uint16) + ItemUInt32 (value uint32) + ItemUInt64 (value uint64) + + ItemFloat32 (value float32) + ItemFloat64 (value float64) + + ItemDate (value time.Time) + + ItemList (builder func(packer ListPacker)) + ItemMap (builder func(packer MapPacker )) + ItemObject(builder func(packer ObjectPacker)) + + } + +) + + diff --git a/packets/map_packer.go b/packets/map_packer.go new file mode 100644 index 0000000..b5ecac9 --- /dev/null +++ b/packets/map_packer.go @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name map_packer.go +// Created by DEV +// Modified 23/01/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 packets + +import "time" + +type ( + + MapPacker interface { + + KeyValue (key any, value any) + + KeyValueRaw (value []byte) + + KeyValueBinary (key any, value []byte) + KeyValueString (key any, value string) + + KeyValueBool (key any, value bool) + + KeyValueInt8 (key any, value int8) + KeyValueInt16 (key any, value int16) + KeyValueInt32 (key any, value int32) + KeyValueInt64 (key any, value int64) + + KeyValueUInt8 (key any, value uint8) + KeyValueUInt16 (key any, value uint16) + KeyValueUInt32 (key any, value uint32) + KeyValueUInt64 (key any, value uint64) + + KeyValueFloat32 (key any, value float32) + KeyValueFloat64 (key any, value float64) + + KeyValueDate (key any, value time.Time) + + KeyValueList (builder func(packer ListPacker)) + KeyValueMap (builder func(packer MapPacker )) + KeyValueObject(builder func(packer ObjectPacker)) + + } + +) + + + diff --git a/packets/node.go b/packets/node.go new file mode 100644 index 0000000..a8dd555 --- /dev/null +++ b/packets/node.go @@ -0,0 +1,61 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packer_node.go +// Created by DEV +// Modified 23/01/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 packets + +import "activething.com/go/gogo/core/slices" + +type ( + + Node struct { + Parent *Node + Start int + Count int + Level int + Kind NodeKind + keys slices.String + } +) + +func (n *Node) Init(parent *Node, kind NodeKind, start int) *Node { + n.Parent = parent + if parent != nil { + n.Level = parent.Level + 1 + } else { + n.Level = 0 + } + n.Level = 0 + n.Count = 0 + n.Start = start + n.Kind = kind + return n +} + +func (n *Node) Reset() *Node { + n.Parent = nil + n.keys = n.keys[:0] + return n +} + + + diff --git a/packets/node_kind.go b/packets/node_kind.go new file mode 100644 index 0000000..eda5215 --- /dev/null +++ b/packets/node_kind.go @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name node_kind.go +// Created by DEV +// Modified 23/01/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 packets + + + +const ( + + NodeKindValue NodeKind = iota + NodeKindList + NodeKindMap + NodeKindObject +) + +type NodeKind uint8 + + + + diff --git a/packets/object_packer.go b/packets/object_packer.go new file mode 100644 index 0000000..daae623 --- /dev/null +++ b/packets/object_packer.go @@ -0,0 +1,66 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name object_packer.go +// Created by DEV +// Modified 23/01/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 packets + +import "time" + +type ( + + ObjectPacker interface { + + Field (key any, value any) + + FieldRaw (value []byte) + + FieldBinary (key any, value []byte) + FieldString (key any, value string) + + FieldBool (key any, value bool) + + FieldInt8 (key any, value int8) + FieldInt16 (key any, value int16) + FieldInt32 (key any, value int32) + FieldInt64 (key any, value int64) + + FieldUInt8 (key any, value uint8) + FieldUInt16 (key any, value uint16) + FieldUInt32 (key any, value uint32) + FieldUInt64 (key any, value uint64) + + FieldFloat32 (key any, value float32) + FieldFloat64 (key any, value float64) + + FieldDate (key any, value time.Time) + + FieldList (builder func(packer ListPacker)) + FieldMap (builder func(packer MapPacker )) + FieldObject(builder func(packer ObjectPacker)) + + } + +) + + + + diff --git a/packets/packer.go b/packets/packer.go new file mode 100644 index 0000000..35091db --- /dev/null +++ b/packets/packer.go @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packer.go +// Created by DEV +// Modified 23/01/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 packets + +import "time" + +type ( + + Packer interface { + + Pack (value any) + + PackRaw (value []byte) + PackBinary (value []byte) + PackString (value string) + + PackBool (value bool) + + PackInt8 (value int8) + PackInt16 (value int16) + PackInt32 (value int32) + PackInt64 (value int64) + + PackUInt8 (value uint8) + PackUInt16 (value uint16) + PackUInt32 (value uint32) + PackUInt64 (value uint64) + + PackFloat32 (value float32) + PackFloat64 (value float64) + + PackDate (value time.Time) + + + PackList (builder func(packer Packer)) + PackMap (builder func(packer MapPacker )) + PackObject(builder func(packer ObjectPacker)) + + } +) + + diff --git a/packets/packer_state.go b/packets/packer_state.go new file mode 100644 index 0000000..4388a4c --- /dev/null +++ b/packets/packer_state.go @@ -0,0 +1,153 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packer_state.go +// Created by DEV +// Modified 23/01/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 packets + +import ( + "activething.com/go/gogo/core/bins" + "activething.com/go/gogo/core/slices" + "activething.com/go/gogo/core/syncs" + "sync/atomic" +) + + +type ( + + + State struct { + /*Embedded*/*bins.Buffer + Node *Node + Temp [64]byte + Seen map[any]struct{} + Error error + } + +) + + +func NewState() *State { + if atomic.CompareAndSwapUint32(&G.poolsSem,0,1) { + G.nodePool = syncs.NewPool[Node]( + syncs.PoolWithNew[Node](func()*Node { + return &Node{ + Kind: NodeKindValue, + keys: make(slices.String, 0, 10), + } + }), + ) + G.statePool = syncs.NewPool[State]( + syncs.PoolWithNew[State](func() *State { + return &State{ + Node : G.nodePool.Get().Init(nil, NodeKindValue, 0), + Buffer: bins.NewBuffer(), + Seen: make(map[any]struct{}), + } + }), + ) + } + return G.statePool.Get() +} + + +func ReleaseState (state *State) { + if state == nil { + state.Buffer.Reset() + state.Node.Reset() + state.Error = nil + if atomic.LoadUint32(&G.poolsSem) == 1 { + G.statePool.Put(state) + } + } + +} + + + + +func (s *State) SetError(err error) bool { + if s.Error != nil { + return true + } + if err == nil { + return false + } + s.Error = err + s.Reset() + s.Node.Reset() + return true +} + +func (s *State) SetKey(key string) bool { + if s.Error != nil { + return false + } + + if s.Node.keys.Has(key) { + return !s.SetError(G.ErrDuplicatedKey) + } + s.Node.keys = s.Node.keys.Append(key) + return true +} + +func (s *State) SetValue() bool { + if s.Error != nil { + return false + } + s.Node.Count++ + return true +} + +func (s *State) Open(kind NodeKind) bool { + if s.Error != nil { + return false + } + if s.Node.Kind == NodeKindValue { + if s.Node.Count > 0 { + return !s.SetError(G.ErrInvalidNode) + } + s.Node.Init(s.Node.Parent, kind, s.Len()) + } else { + s.Node = G.nodePool.Get().Init(s.Node, kind, s.Len()) + } + return true +} + +func (s *State) Close() bool { + if s.Error != nil { + return false + } + if s.Node.Kind == NodeKindValue { + return !s.SetError(G.ErrInvalidNode) + } + + if s.Node.Parent != nil { + p := s.Node + s.Node = s.Node.Parent + G.nodePool.Put(p.Reset()) + } + s.Node.Count++ + return true +} + + + diff --git a/packets/pjson/gogo.go b/packets/pjson/gogo.go new file mode 100644 index 0000000..84b842f --- /dev/null +++ b/packets/pjson/gogo.go @@ -0,0 +1,78 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 23/01/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 "unicode/utf8" + +var ( + G = struct { + hex string + jsonChars [utf8.RuneSelf]jsonCharAtt + + sep byte + nullValue []byte + zeroValue []byte + trueValue []byte + falseValue []byte + mapEmpty []byte + listEmpty []byte + objectEmpty []byte + floatNaN []byte + floatInfPos []byte + floatInfNeg []byte + }{ + + hex: "0123456789abcdef", + jsonChars: initJSONChars(), + + sep: ',', + nullValue: []byte{'n', 'u', 'l', 'l'}, + zeroValue: []byte{'0'}, + trueValue: []byte{'"','t', 'r', 'u', 'e','"'}, + falseValue: []byte{'"','f', 'a', 'l', 's', 'e','"'}, + mapEmpty: []byte{'{', '}'}, + objectEmpty: []byte{'{', '}'}, + listEmpty: []byte{'[', ']'}, + floatNaN: []byte{'"', 'N', 'a', 'N', '"'}, + floatInfPos: []byte{'"', 'I', 'n', 'f', '"'}, + floatInfNeg: []byte{'"', '-', 'I', 'n', 'f', '"'}, + } +) + +func initJSONChars() [utf8.RuneSelf]jsonCharAtt { + var tb = [utf8.RuneSelf]jsonCharAtt{ + '"': jsonCharAttAllUnsafe, + '&': jsonCharAttHtmlUnsafe, + '<': jsonCharAttHtmlUnsafe, + '>': jsonCharAttHtmlUnsafe, + '\\': jsonCharAttAllUnsafe, + } + for i := 0; i <= 31; i++ { + tb[i] = jsonCharAttAllUnsafe + } + return tb +} + + + diff --git a/packets/pjson/json_char_atts.go b/packets/pjson/json_char_atts.go new file mode 100644 index 0000000..b034c41 --- /dev/null +++ b/packets/pjson/json_char_atts.go @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name json_char_atts.go +// Created by DEV +// Modified 18/01/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 + +const ( + jsonCharAttUnsafe jsonCharAtt = 1 << iota + jsonCharAttHtmlUnsafe + + jsonCharAttAllUnsafe = jsonCharAttUnsafe | jsonCharAttHtmlUnsafe +) + +type jsonCharAtt uint8 + +func (a jsonCharAtt) isUnsafe() bool { + return a&jsonCharAttUnsafe != 0 +} + +func (a jsonCharAtt) isHtmlUnsafe() bool { + return a&jsonCharAttHtmlUnsafe != 0 +} diff --git a/packets/pjson/list_packer.go b/packets/pjson/list_packer.go new file mode 100644 index 0000000..ee1128b --- /dev/null +++ b/packets/pjson/list_packer.go @@ -0,0 +1,59 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name list_packer.go +// Created by DEV +// Modified 23/01/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 ( + "activething.com/go/gogo/packets" + "time" +) + +func (p *Packer) Item (value any) { p.addSep().Pack(value) } + +func (p *Packer) ItemRaw (value []byte) { p.addSep().PackRaw(value) } + +func (p *Packer) ItemBinary (value []byte) { p.addSep().PackBinary(value) } +func (p *Packer) ItemString (value string) { p.addSep().PackString(value) } + +func (p *Packer) ItemBool (value bool) { p.addSep().PackBool(value) } + +func (p *Packer) ItemInt8 (value int8) { p.addSep().PackInt64(int64(value)) } +func (p *Packer) ItemInt16 (value int16) { p.addSep().PackInt64(int64(value)) } +func (p *Packer) ItemInt32 (value int32) { p.addSep().PackInt64(int64(value)) } +func (p *Packer) ItemInt64 (value int64) { p.addSep().PackInt64(value) } + +func (p *Packer) ItemUInt8 (value uint8) { p.addSep().PackUInt64(uint64(value)) } +func (p *Packer) ItemUInt16 (value uint16) { p.addSep().PackUInt64(uint64(value)) } +func (p *Packer) ItemUInt32 (value uint32) { p.addSep().PackUInt64(uint64(value)) } +func (p *Packer) ItemUInt64 (value uint64) { p.addSep().PackUInt64(value) } + +func (p *Packer) ItemFloat32 (value float32) { p.addSep().PackFloat64(float64(value))} +func (p *Packer) ItemFloat64 (value float64) { p.addSep().PackFloat64(value) } + +func (p *Packer) ItemDate (value time.Time) { p.addSep().PackDate(value) } + +func (p *Packer) ItemList (builder func(packer packets.ListPacker)) { p.addSep().ItemList (builder) } +func (p *Packer) ItemMap (builder func(packer packets.MapPacker )) { p.addSep().ItemMap (builder) } +func (p *Packer) ItemObject(builder func(packer packets.ObjectPacker)) { p.addSep().ItemObject(builder) } + + diff --git a/packets/pjson/map_packer.go b/packets/pjson/map_packer.go new file mode 100644 index 0000000..56b4bbd --- /dev/null +++ b/packets/pjson/map_packer.go @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name map_packer.go +// Created by DEV +// Modified 23/01/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 ( + "activething.com/go/gogo/packets" + "time" +) + +func (p *Packer) KeyValue ( key any, value any) {} + +func (p *Packer) KeyValueRaw (value []byte) {} + +func (p *Packer) KeyValueBinary ( key any, value []byte) {} +func (p *Packer) KeyValueString ( key any, value string) {} + +func (p *Packer) KeyValueBool ( key any, value bool) {} +func (p *Packer) KeyValueRune ( key any, value rune) {} + +func (p *Packer) KeyValueInt8 ( key any, value int8) {} +func (p *Packer) KeyValueInt16 ( key any, value int16) {} +func (p *Packer) KeyValueInt32 ( key any, value int32) {} +func (p *Packer) KeyValueInt64 ( key any, value int64) {} + +func (p *Packer) KeyValueUInt8 ( key any, value uint8) {} +func (p *Packer) KeyValueUInt16 ( key any, value uint16) {} +func (p *Packer) KeyValueUInt32 ( key any, value uint32) {} +func (p *Packer) KeyValueUInt64 ( key any, value uint64) {} + +func (p *Packer) KeyValueFloat32 ( key any, value float32) {} +func (p *Packer) KeyValueFloat64 ( key any, value float64) {} + + +func (p *Packer) KeyValueDate ( key any, value time.Time) {} + + +func (p *Packer) KeyValueList (builder func(packer packets.ListPacker)) {} +func (p *Packer) KeyValueMap (builder func(packer packets.MapPacker )) {} +func (p *Packer) KeyValueObject(builder func(packer packets.ObjectPacker)) {} + + + diff --git a/packets/pjson/object_packer.go b/packets/pjson/object_packer.go new file mode 100644 index 0000000..d746ddf --- /dev/null +++ b/packets/pjson/object_packer.go @@ -0,0 +1,61 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name object_packer.go +// Created by DEV +// Modified 23/01/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 ( + "activething.com/go/gogo/packets" + "time" +) + +func (p *Packer) Field ( key any, value any) {} + +func (p *Packer) FieldRaw (value []byte) {} + +func (p *Packer) FieldBinary ( key any, value []byte) {} +func (p *Packer) FieldString ( key any, value string) {} + +func (p *Packer) FieldBool ( key any, value bool) {} +func (p *Packer) FieldRune ( key any, value rune) {} + +func (p *Packer) FieldInt8 ( key any, value int8) {} +func (p *Packer) FieldInt16 ( key any, value int16) {} +func (p *Packer) FieldInt32 ( key any, value int32) {} +func (p *Packer) FieldInt64 ( key any, value int64) {} + +func (p *Packer) FieldUInt8 ( key any, value uint8) {} +func (p *Packer) FieldUInt16 ( key any, value uint16) {} +func (p *Packer) FieldUInt32 ( key any, value uint32) {} +func (p *Packer) FieldUInt64 ( key any, value uint64) {} + +func (p *Packer) FieldFloat32 ( key any, value float32) {} +func (p *Packer) FieldFloat64 ( key any, value float64) {} + + +func (p *Packer) FieldDate ( key any, value time.Time) {} + + +func (p *Packer) FieldList (builder func(packer packets.ListPacker)) {} +func (p *Packer) FieldMap (builder func(packer packets.MapPacker )) {} +func (p *Packer) FieldObject(builder func(packer packets.ObjectPacker)) {} + diff --git a/packets/pjson/options.go b/packets/pjson/options.go new file mode 100644 index 0000000..437af01 --- /dev/null +++ b/packets/pjson/options.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name options.go +// Created by DEV +// Modified 23/01/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 + + +type ( + + Options struct { + Flags /*embedded*/ + dateLayout string + } +) \ No newline at end of file diff --git a/packets/pjson/options_flags.go b/packets/pjson/options_flags.go new file mode 100644 index 0000000..bd263bc --- /dev/null +++ b/packets/pjson/options_flags.go @@ -0,0 +1,61 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name flags.go +// Created by DEV +// Modified 23/01/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 + + +const ( + + JSONFlagQuote Flags = 1 << iota + JSONFlagEscapeHTML + JSONFlagIgnoreKeys + JSONFlagQuoteNumbers + JSONFlagIgnoreDefaults + +) + +type Flags uint8 + + + + +func (o Flags) Quote() bool { + return o&JSONFlagQuote != 0 +} + +func (o Flags) QuoteNumbers() bool { + return o&JSONFlagQuoteNumbers != 0 +} + +func (o Flags) EscapeHTML() bool { + return o&JSONFlagEscapeHTML != 0 +} + +func (o Flags) IgnoreKeys() bool { + return o&JSONFlagIgnoreKeys != 0 +} + +func (o Flags) IgnoreDefaults() bool { + return o&JSONFlagIgnoreDefaults != 0 +} + diff --git a/packets/pjson/packer.go b/packets/pjson/packer.go new file mode 100644 index 0000000..58f1960 --- /dev/null +++ b/packets/pjson/packer.go @@ -0,0 +1,332 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packer.go +// Created by DEV +// Modified 23/01/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 ( + "activething.com/go/gogo/core/bins" + "activething.com/go/gogo/core/errs" + "activething.com/go/gogo/packets" + "encoding/base64" + "math" + "strconv" + "time" + "unicode/utf8" +) + +type ( + + Packer struct { + options Options + + state *packets.State + } + + +) + + + +func (p *Packer) Pack (value any) { + if !p.state.SetValue() { + panic(p.state.Error) + } +} + + + +func (p *Packer) PackRaw (value []byte) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if value == nil { + p.state.Write(G.nullValue) + return + } + p.state.Write(value) +} + + +func (p *Packer) PackBinary (value []byte) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if value == nil { + p.state.Write(G.nullValue) + return + } + if len(value) == 0 { + p.state.Write2Byte('"','"') + return + } + p.state.WriteByte('"') + ln := base64.StdEncoding.EncodedLen(len(value)) + if ln <= len(p.state.Temp) { + dst := p.state.Temp[:ln] + base64.StdEncoding.Encode(dst, value) + p.state.Write(dst) + } else if ln <= 1024 { + dst := make([]byte, ln) + base64.StdEncoding.Encode(dst, value) + p.state.Write(dst) + } else { + enc := base64.NewEncoder(base64.StdEncoding, p.state) + enc.Write(value) + enc.Close() + } + p.state.WriteByte('"') +} + +func (p *Packer) PackString (value string) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if len(value) == 0 { + p.state.Write2Byte('"','"') + } else { + p.string(value,p.options.EscapeHTML()) + } +} + +func (p *Packer) PackBool (value bool) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } + if value { + p.state.Write(G.trueValue) + } else { + p.state.Write(G.falseValue) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } +} + +func (p *Packer) PackInt8 (value int8) {} +func (p *Packer) PackInt16 (value int16) {} +func (p *Packer) PackInt32 (value int32) {} +func (p *Packer) PackInt64 (value int64) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } + if value == 0 { + p.state.WriteByte('0') + } else { + p.state.WriteIntStr(value, 10) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } +} + +func (p *Packer) PackUInt8 (value uint8) {} +func (p *Packer) PackUInt16 (value uint16) {} +func (p *Packer) PackUInt32 (value uint32) {} +func (p *Packer) PackUInt64 (value uint64) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } + if value == 0 { + p.state.WriteByte('0') + } else { + p.state.WriteUIntStr(value, 10) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } +} + +func (p *Packer) PackFloat32 (value float32) {} +func (p *Packer) PackFloat64 (value float64) { + if !p.state.SetValue() { + panic(p.state.Error) + } + if math.IsInf(value,0) || math.IsNaN(value) { + p.state.SetError(packets.G.ErrInvalidValue) + return + } + + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } + switch { + case value == 0 : p.state.Write(G.zeroValue) + case math.IsNaN(value) : p.state.Write(G.floatNaN) + case math.IsInf(value, 1) : p.state.Write(G.floatInfPos) + case math.IsInf(value, -1) : p.state.Write(G.floatInfNeg) + default: + fm := byte('f') + if ab := math.Abs(value); ab != 0 { + if ab < 1e-6 || ab >= 1e21 { + fm = 'e' + } + } + b := p.state.Temp[:0] + + b = strconv.AppendFloat(b, value, fm, -1, 64) + if fm == 'e' { + // clean up e-09 to e-9 + n := len(b) + if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { + b[n-2] = b[n-1] + b = b[:n-1] + } + } + p.state.Write(b) + } + if p.options.QuoteNumbers() { + p.state.WriteByte('"') + } +} + +func (p *Packer) PackDate (value time.Time) { + if !p.state.SetValue() { + panic(p.state.Error) + } + p.state.WriteByte('"') + p.state.AppendWith(bins.AppendFnc(func(d []byte) []byte { + return value.AppendFormat(d,p.options.dateLayout) + })) + p.state.WriteByte('"') +} + + +func (p *Packer) PackList (builder func(packer packets.ListPacker)) { + p.packCompound(packets.NodeKindList,'[',']',func(pk *Packer) { builder (pk) }) +} + +func (p *Packer) PackMap (builder func(packer packets.MapPacker )) { + p.packCompound(packets.NodeKindMap,'{','}',func(pk *Packer) { builder (pk) }) +} + +func (p *Packer) PackObject(builder func(packer packets.ObjectPacker)) { + p.packCompound(packets.NodeKindObject,'{','}',func(pk *Packer) { builder (pk) }) +} + + + + +func (p *Packer) packCompound(kind packets.NodeKind, opening, closing byte, buildFnc func(*Packer)) { + if !p.state.SetValue() { + panic(p.state.Error) + } + + dn := false + defer func(d *bool) { + if !(*d) { + p.state.SetError(errs.ToError(recover())) + } + }(&dn) + + if p.state.Open(kind) { + p.addSep() + p.state.WriteByte(opening) + + buildFnc(p) + + if p.state.Error == nil { + if p.state.Close() { + p.state.WriteByte(closing) + } + } + } + dn = true +} + + + + + + +func (p *Packer) string(s string, scapeHTML bool) { + p.state.WriteByte('"') + start := 0 + for i := 0; i < len(s); { + if b := s[i]; b < utf8.RuneSelf { + if !G.jsonChars[b].isHtmlUnsafe() || (!scapeHTML && !G.jsonChars[b].isUnsafe()) { + i++ + continue + } + + if start < i { + p.state.WriteString(s[start:i]) + } + p.state.WriteByte('\\') + switch b { + case '\\', '"': p.state.WriteByte(b) + case '\n': p.state.WriteByte('n') + case '\r': p.state.WriteByte('r') + case '\t': p.state.WriteByte('t') + default: + p.state.WriteString(`u00`) + p.state.Write2Byte(G.hex[b>>4], G.hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + p.state.WriteString(s[start:i]) + } + p.state.WriteString(`\ufffd`) + i += size + start = i + continue + } + + if c == '\u2028' || c == '\u2029' { + if start < i { + p.state.WriteString(s[start:i]) + } + p.state.WriteString(`\u202`) + p.state.WriteByte(G.hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(s) { + p.state.WriteString(s[start:]) + } + p.state.WriteByte('"') +} + + +func (p *Packer) addSep () *Packer { + if p.state.Node.Count > 0 { + p.state.WriteByte(',') + } + return p +} \ No newline at end of file