diff --git a/app/main.go b/app/main.go index 5abd6f5..6dcc9de 100644 --- a/app/main.go +++ b/app/main.go @@ -1,7 +1,7 @@ package main import ( - "errors" + "bins/bfers" "errs" "errs/stack" "fmt" @@ -43,6 +43,10 @@ func (c MiCustomErr) Message() string { return "esto es un custom werro" } +func (c MiCustomErr) Code() string { + return "custom-code" +} + /* func fm (b *bytes.Buffer, e error, l int) { @@ -65,24 +69,7 @@ func (c MiCustomErr) Unwrap () error { func main() { - e := errs.ErrCode("Mi-Error") - i := errs.NewErrInfo(e, - errs.ErrInfoWithMessage("Esto es un mensage"), - errs.ErrInfoWithCause(MiCustomErr{}), - errs.ErrInfoWithStackTrace(2), - ) - ne := i.WrapWithCause(errors.New("UnNuevoErrrorrrr")) - - - e1 := errors.New("UnError") - e2 := errs.WrapWithCause(errors.New("sinvalude"),errs.WrapWithInfo(errors.New("ElOtro error"),errs.ErrInfoWithMessage("OtroError"))) - e3 := errs.NewErrMulti(e1,e2) - - - e4 := &MiCustomErr{} - e5 := &MiCustomErr{} - //me := errs.NewErrTrace(errs.NewErrMulti(e3,e4,e5,ne).WrapWithInfo(errs.ErrInfoWithMessage("Es0")),0) - me := errs.NewErrMulti(e3,e4,e5,ne).WrapWithInfo(errs.ErrInfoWithMessage("Es0")) + me := bfers.G.ErrTooLarge diff --git a/core/bins/buffer_pool_ops.go b/core/atypes/numbers.go similarity index 66% rename from core/bins/buffer_pool_ops.go rename to core/atypes/numbers.go index 07ae357..a0b133a 100644 --- a/core/bins/buffer_pool_ops.go +++ b/core/atypes/numbers.go @@ -2,7 +2,7 @@ // Project atila // Active Thing (activething.com) git.activething.com/go // -// File name buffer_pool_opts.go +// File name generics.go // Created by DEV // Modified 17/01/2024 // @@ -21,30 +21,31 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package atypes -import ( - "opts" - "sync/atomic" -) +type ( -func applyBufferPoolOptions (b *BufferPool, options ...BufferPoolFnc) *BufferPool { - for _,o := range options { - o(b) + Unsigned interface { + uint | uint8 | uint16 | uint32 | uint64 } - return b -} - -func WithMaxPercentile(percentile float32) opts.GOptionFnc[BufferPool] { - return func(b *BufferPool) { - b.percentile = percentile + UnsignedAll interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 } -} + Signed interface { + int | int8 | int16 | int32 | int64 + } -func CallsThreshold(threshold uint64) opts.GOptionFnc[BufferPool] { - return func(b *BufferPool) { - atomic.StoreUint64(&b.threshold, threshold) + SignedAll interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 } -} + + Integer interface{ Signed | Unsigned } + + Float interface{ float32 | float64 } + + Complex interface{ complex64 | complex128 } + + Number interface{ Integer | Float | Complex } +) diff --git a/core/atypes/slices/strings.go b/core/atypes/slices/strings.go new file mode 100644 index 0000000..5c849cc --- /dev/null +++ b/core/atypes/slices/strings.go @@ -0,0 +1,58 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name string.go +// Created by DEV +// Modified 16/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 slices + + + +type Strings []string + + + + +func MakeStrings(size, capacity int) Strings { + return make(Strings, size, capacity) +} + +func (s Strings) Reset() Strings { + if s != nil { + return s[:0] + } + return s +} + +func (s Strings) Has(value string) bool { + if len(s) == 0 { + return false + } + for _, k := range s { + if k == value { + return true + } + } + return false +} + +func (s Strings) Append(value string) Strings { + return append(s, value) +} diff --git a/core/bits/active.go b/core/bits/active.go new file mode 100644 index 0000000..ae00dce --- /dev/null +++ b/core/bits/active.go @@ -0,0 +1,44 @@ +/* + * + * --------------------------------------------------------- + * Project $PROJECT_NAME + * Active Thing (activething.com) git.activething.com/go + * + * File name $FILE_NAME + * Created by ${USER} + * Modified ${DAY}/${MONTH}/${YEAR} + * + * Copyright ${YEAR} 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 bits + +import "errs" + +var ( + + G = struct { + + ErrUnsupportedFlagType Err + }{ + + ErrUnsupportedFlagType : Err{errs.ErrCode ("unsupported-bit-flag-type") }, + } +) + + diff --git a/core/bits/bflags_16.go b/core/bits/bflags_16.go new file mode 100644 index 0000000..d1c756b --- /dev/null +++ b/core/bits/bflags_16.go @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bflag_16.go +// Created by DEV +// Modified 15/02/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 bits + +import ( + "math/bits" +) + + +type BFlags16 uint16 + + + +func (f BFlags16) Has ( flag BFlags16) bool { + return f&flag != 0 } + + +func (f BFlags16) Add ( flag BFlags16) BFlags16 { + return f|flag } + + +func (f BFlags16) AddWithMask ( flag BFlags16, mask BFlags16) BFlags16 { + return (f&mask) | flag } + + +func (f BFlags16) Del ( flag BFlags16) BFlags16 { + return f&^flag } + + +func (f BFlags16) Invert () BFlags16 { + return ^f } + + +func (f BFlags16) Count() int { + return bits.OnesCount16(uint16(f)) } + + + +func (f BFlags16) Extract() []BFlags16 { + if f == 0 { + return []BFlags16{} + } + l := make([]BFlags16,0,16) + c := BFlags16(1) + for i:=1; i<= 7; i++ { + if c&f == c { + l = append(l,c) + } + c <<= 1 + } + return l +} + + +func (f BFlags16) FlagsToNames (namer func(flags BFlags16) string) []string { + if f == 0 { + return []string{} + } + l := make([]string,0,16) + c := BFlags16(1) + for i:=1; i<= 7; i++ { + if c&f == c { + l = append(l,namer(c)) + } + c <<= 1 + } + return l +} + + +func (f BFlags16) NamesToFlags (names []string, flagger func(name string) BFlags16) BFlags16 { + for _,s := range names { + f|=flagger(s) + } + return f +} \ No newline at end of file diff --git a/core/bits/err.go b/core/bits/err.go new file mode 100644 index 0000000..6c80842 --- /dev/null +++ b/core/bits/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err_bits.go +// Created by DEV +// Modified 20/04/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 bits + +import "errs" + +type ( + + Err struct { errs.ErrCode } +) + + diff --git a/core/bits/g_bflags.go b/core/bits/g_bflags.go new file mode 100644 index 0000000..dcc5de0 --- /dev/null +++ b/core/bits/g_bflags.go @@ -0,0 +1,106 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bflag.go +// Created by DEV +// Modified 15/02/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 bits + +import ( + "atypes" + "encoding/binary" + "math/bits" +) + + + + +func Has [T atypes.UnsignedAll](source T, flag T) bool { + return source&flag != 0 } + + +func Add [T atypes.UnsignedAll](source T, flag T) T { + return source|flag } + + +func AddWithMask [T atypes.UnsignedAll](source T, flag T, mask T) T { + return (source&mask) | flag } + + +func Del [T atypes.UnsignedAll](source T, flag T) T { + return source&^flag } + + +func Invert [T atypes.UnsignedAll](source T) T { + return ^source } + + +func Count[T atypes.UnsignedAll](source T) int { + switch binary.Size(source) { + case 1 : return bits.OnesCount8 (uint8(source)) + case 2 : return bits.OnesCount16(uint16(source)) + case 4 : return bits.OnesCount32(uint32(source)) + case 8 : return bits.OnesCount64(uint64(source)) + default: + panic(G.ErrUnsupportedFlagType) + } +} + + + +func Extract[T atypes.UnsignedAll](source T) []T { + if source == 0 { + return []T{} + } + l := make([]T,0,16) + c := T(1) + for i:=1; i<= 7; i++ { + if c&source == c { + l = append(l,c) + } + c <<= 1 + } + return l +} + + +func FlagsToNames [T atypes.UnsignedAll](source T, namer func(flags T) string) []string { + if source == 0 { + return []string{} + } + l := make([]string,0,16) + c := T(1) + for i:=1; i<= 7; i++ { + if c&source == c { + l = append(l,namer(c)) + } + c <<= 1 + } + return l +} + + +func NamesToFlags [T atypes.UnsignedAll](names []string, flagger func(name string) T) T { + var f T + for _,s := range names { + f|=flagger(s) + } + return f +} \ No newline at end of file diff --git a/core/bits/go.mod b/core/bits/go.mod new file mode 100644 index 0000000..5fb1807 --- /dev/null +++ b/core/bits/go.mod @@ -0,0 +1,3 @@ +module bits + +go 1.22 diff --git a/core/bins/active.go b/core/btes/bfers/active.go similarity index 68% rename from core/bins/active.go rename to core/btes/bfers/active.go index a3d6f2b..a4c436d 100644 --- a/core/bins/active.go +++ b/core/btes/bfers/active.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers import "errs" @@ -40,32 +40,27 @@ const ( var ( G = struct { - ErrOutOfRange errs.ErrCode - ErrWriteCount errs.ErrCode - ErrTooShort errs.ErrCode - ErrTooLarge errs.ErrCode - ErrNegativeRead errs.ErrCode - ErrUnreadInvalid errs.ErrCode - - - + ErrOutOfRange Err + ErrWriteCount Err + ErrTooShort Err + ErrTooLarge Err + ErrNegativeRead Err + ErrUnreadInvalid Err }{ - ErrOutOfRange: errs.ErrCode("core:bins.out-of-range"), - ErrWriteCount: errs.ErrCode("core:bins.write-count"), - ErrTooShort: errs.ErrCode("core:bins.too-short"), - ErrTooLarge: errs.ErrCode("core:bins.too-large"), - ErrNegativeRead: errs.ErrCode("core:bins.negative-read"), - ErrUnreadInvalid: errs.ErrCode("core:bins.unread-invalid"), - - + ErrOutOfRange: Err{errs.ErrCode("out-of-range")}, + ErrWriteCount: Err{errs.ErrCode("write-count")}, + ErrTooShort: Err{errs.ErrCode("too-short")}, + ErrTooLarge: Err{errs.ErrCode("too-large")}, + ErrNegativeRead: Err{errs.ErrCode("negative-read")}, + ErrUnreadInvalid: Err{errs.ErrCode("unread-invalid")}, } g = struct { - bufferPool *BufferPool + bufferPool *Pool }{ - bufferPool: NewBufferPool(), + bufferPool: NewPool(), } ) diff --git a/core/bins/appender.go b/core/btes/bfers/appender.go similarity index 98% rename from core/bins/appender.go rename to core/btes/bfers/appender.go index e2ab311..6707391 100644 --- a/core/bins/appender.go +++ b/core/btes/bfers/appender.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers type ( diff --git a/core/bins/buffer.go b/core/btes/bfers/buffer.go similarity index 99% rename from core/bins/buffer.go rename to core/btes/bfers/buffer.go index 90d0e5f..fcd6baf 100644 --- a/core/bins/buffer.go +++ b/core/btes/bfers/buffer.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers import ( "bins/chars" @@ -45,7 +45,7 @@ type ( data []byte off int ini [64]byte - lastOp bufferOp + lastOp operation } ) @@ -175,7 +175,7 @@ func (b *Buffer) ReadRune() (run rune, size int, err error) { } r, n := utf8.DecodeRune(b.data[b.off:]) b.off += n - b.lastOp = bufferOp(n) + b.lastOp = operation(n) return r, n, nil } diff --git a/core/btes/bfers/err.go b/core/btes/bfers/err.go new file mode 100644 index 0000000..b102b67 --- /dev/null +++ b/core/btes/bfers/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err_btes.go +// Created by DEV +// Modified 20/04/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 bfers + +import "errs" + +type ( + + Err struct { errs.ErrCode } +) + + diff --git a/core/bins/buffer_op.go b/core/btes/bfers/operation.go similarity index 83% rename from core/bins/buffer_op.go rename to core/btes/bfers/operation.go index b06057c..c189ae8 100644 --- a/core/bins/buffer_op.go +++ b/core/btes/bfers/operation.go @@ -21,16 +21,16 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers const ( - opRead bufferOp = -1 // Any other read operation. - opInvalid bufferOp = 0 // Non-read operation. - opRune bufferOp = 1 // Decode rune of size 1. + opRead operation = -1 // Any other read operation. + opInvalid operation = 0 // Non-read operation. + opRune operation = 1 // Decode rune of size 1. ) -type bufferOp int8 +type operation int8 diff --git a/core/bins/buffer_pool.go b/core/btes/bfers/pool.go similarity index 76% rename from core/bins/buffer_pool.go rename to core/btes/bfers/pool.go index 12b769e..071c3c3 100644 --- a/core/bins/buffer_pool.go +++ b/core/btes/bfers/pool.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers import ( "sort" @@ -34,7 +34,7 @@ import ( type ( - BufferPool struct { + Pool struct { syncs.PoolStatsInfo inner sync.Pool @@ -49,31 +49,31 @@ type ( percentile float32 } - BufferPoolFnc func (*BufferPool) + PoolFnc func (*Pool) ) -func NewBufferPool(options ...BufferPoolFnc) *BufferPool { - return applyBufferPoolOptions(&BufferPool{percentile: poolPercentile}, options...) } +func NewPool(options ...PoolFnc) *Pool { + return applyBufferPoolOptions(&Pool{percentile: poolPercentile}, options...) } -func (p *BufferPool) MaxSize() uint64 { +func (p *Pool) MaxSize() uint64 { return atomic.LoadUint64(&p.maxSize) } -func (p *BufferPool) DefSize() uint64 { +func (p *Pool) DefSize() uint64 { return atomic.LoadUint64(&p.defSize) } -func (p *BufferPool) MaxPercentile() float32 { +func (p *Pool) MaxPercentile() float32 { return p.percentile } -func (p *BufferPool) CallsThreshold() uint64 { +func (p *Pool) CallsThreshold() uint64 { return atomic.LoadUint64(&p.threshold) } -func (p *BufferPool) Get() *Buffer { +func (p *Pool) Get() *Buffer { b := p.inner.Get() p.AddAcquired() if b == nil { @@ -84,7 +84,7 @@ func (p *BufferPool) Get() *Buffer { } -func (p *BufferPool) Put(buffer *Buffer) { +func (p *Pool) Put(buffer *Buffer) { if buffer == nil { return } @@ -100,7 +100,7 @@ func (p *BufferPool) Put(buffer *Buffer) { } -func (p *BufferPool) calibrate() { +func (p *Pool) calibrate() { if atomic.CompareAndSwapUint64(&p.calibra, 0, 1) { return } @@ -151,3 +151,23 @@ func index(n int) int { } return i } + + + + +func applyBufferPoolOptions (b *Pool, options ...PoolFnc) *Pool { + for _,o := range options { + o(b) + } + return b +} + + +func WithMaxPercentile(percentile float32) PoolFnc { + return func(b *Pool) { + b.percentile = percentile } } + + +func CallsThreshold(threshold uint64) PoolFnc { + return func(b *Pool) { + atomic.StoreUint64(&b.threshold, threshold) } } diff --git a/core/bins/buffer_writer_binary.go b/core/btes/bfers/writer_binary.go similarity index 99% rename from core/bins/buffer_writer_binary.go rename to core/btes/bfers/writer_binary.go index adc0d89..9ca7731 100644 --- a/core/bins/buffer_writer_binary.go +++ b/core/btes/bfers/writer_binary.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers import ( "encoding/binary" diff --git a/core/bins/buffer_writer_string.go b/core/btes/bfers/writer_string.go similarity index 99% rename from core/bins/buffer_writer_string.go rename to core/btes/bfers/writer_string.go index 0a55246..4513a87 100644 --- a/core/bins/buffer_writer_string.go +++ b/core/btes/bfers/writer_string.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package bins +package bfers import ( "strconv" diff --git a/core/btes/bfields/active.go b/core/btes/bfields/active.go new file mode 100644 index 0000000..8e51676 --- /dev/null +++ b/core/btes/bfields/active.go @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 19/02/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 bfields + +import "errs" + +const( + + notFound = -1 +) + +var ( + + G = struct { + ErrInvalidName Err + ErrDuplicated Err + ErrFixed Err + ErrReadOnly Err + + }{ + ErrInvalidName: Err{ errs.ErrCode("invalid-name")}, + ErrDuplicated : Err{ errs.ErrCode("duplicated-field")}, + ErrFixed : Err{ errs.ErrCode("bfields-fixed")}, + ErrReadOnly : Err{ errs.ErrCode("bfields-read-only")}, + } +) + + + + + + diff --git a/core/btes/bfields/att.go b/core/btes/bfields/att.go new file mode 100644 index 0000000..63b6fb1 --- /dev/null +++ b/core/btes/bfields/att.go @@ -0,0 +1,53 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bfields_att.go +// Created by DEV +// Modified 19/02/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 bfields + + +const( + + AttReadOnly Att = 1 << iota + AttFixed + AttMultiple + +) + +type ( + + + Att uint8 + +) + + + +func (a Att) IsReadOnly() bool { + return a&AttReadOnly != 0 } + + +func (a Att) IsFixed() bool { + return a&AttFixed != 0 } + + +func (a Att) IsMultiple() bool { + return a&AttMultiple != 0 } diff --git a/core/btes/bfields/bfield.go b/core/btes/bfields/bfield.go new file mode 100644 index 0000000..bdb309a --- /dev/null +++ b/core/btes/bfields/bfield.go @@ -0,0 +1,109 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bfield.go +// Created by DEV +// Modified 19/02/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 bfields + +import "strconv" + +type ( + + BField struct { + name []byte + value []byte + } + +) + + +func NewBField (name, value []byte) (*BField,error) { + if len(name) == 0 { + return nil,G.ErrInvalidName + } + return &BField { + name: append(make([]byte,0,len(name)),name...), + value: append(make([]byte,0,len(value)),value...), + },nil +} + + + +func (f BField) Name () []byte { + return f.name } + + +func (f BField) Value() []byte { + return f.value } + + +func (f BField) String () string { + r := make([]byte,len(f.name)+len(f.value)+1) + copy(r,f.name) + r[len(f.name)]=':' + copy(r[len(f.name)+1:],f.value) + return string(r) +} + + + +func (f *BField) SetValue(val []byte) { + ln := len(val) + cp := cap(f.value) + if ln <= cp { + copy(f.value, val) + f.value = f.value[:ln] + return + } + nv := make([]byte, ln) + copy(f.value, nv) +} + + +func (f *BField) SetByte(val byte) { + f.value = append(f.value[:0], val) } + + +func (f *BField) SetBool(val bool) { + f.value = strconv.AppendBool(f.value[:0], val) } + + +func (f *BField) SetRune(val rune) { + f.value = strconv.AppendQuoteRune(f.value[:0], val) } + + +func (f *BField) SetString(val string) { + f.SetValue([]byte(val)) } + + + +func (f *BField) SetInt(val int64, bse int) { + f.value = strconv.AppendInt(f.value[:0], val, bse) } + + +func (f *BField) SetUInt(val uint64, bse int) { + f.value = strconv.AppendUint(f.value[:0], val, bse) } + + +func (f *BField) SetFloat(val float64, fmt byte, prc, sze int) { + f.value = strconv.AppendFloat(f.value[:0], val, fmt, prc, sze) } + + diff --git a/core/btes/bfields/bfields.go b/core/btes/bfields/bfields.go new file mode 100644 index 0000000..4f7f241 --- /dev/null +++ b/core/btes/bfields/bfields.go @@ -0,0 +1,197 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bfield_list.go +// Created by DEV +// Modified 19/02/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 bfields + +import ( + + "bytes" +) + +type ( + + BFields struct { + Att + fields []BField + } + + BFieldsFnc func (bfls *BFields) error + + BFieldsWalkFnc func(index int, field *BField) bool +) + + + +func NewBFields (options ...BFieldsFnc) (*BFields,error) { + fs := &BFields{} + for _,o := range options { + if er := o(fs); er != nil { + return nil,er + } + } + if fs.IsReadOnly() { + //todo + } + return fs,nil +} + + +func (f BFields) Get(nme []byte) *BField { + if ix := findField(f.fields, 0, nme); ix != notFound { + f.get(ix) + } + return nil +} + + +func (f BFields) get(index int) *BField { + if f.IsReadOnly() { + vl := f.fields[index] + return &vl + } + return &f.fields[index] +} + + +func (f *BFields) Add(nme, val []byte) error { + if f.IsFixed() { + return G.ErrFixed + } + if ix := findField(f.fields, 0, nme); ix != notFound { + if !f.IsMultiple() { + return G.ErrDuplicated + } + } + fl, er := NewBField(nme, val) + if er != nil { + return er + } + f.fields = append(f.fields, *fl) + return nil +} + +func (f *BFields) Del(nme []byte) error { + if f.IsFixed() { + return G.ErrFixed + } + if f.IsReadOnly() { + return G.ErrReadOnly + } + fm := 0 + ix := -1 + ln := len(f.fields) + for { + if ix = findField(f.fields, fm, nme); ix == notFound { + break + } + f.fields[ix] = f.fields[ln-1] + f.fields = f.fields[:ln-1] + ln -= 1 + if !f.IsMultiple() || ix == ln-1 { + break + } + fm = ix + } + return nil +} + +func (f *BFields) Upsert(nme, val []byte) error { + if len(nme) == 0 { + return nil + } + if f.IsReadOnly() { + return G.ErrReadOnly + } + if ix := findField(f.fields, 0, nme); ix != -1 { + f.fields[ix].SetValue(val) + return nil + } + if f.IsFixed() { + return G.ErrFixed + } + fl, er := NewBField(nme, val) + if er != nil { + return er + } + f.fields = append(f.fields, *fl) + return nil +} + + + +func (f BFields) Len() int { + return len(f.fields) } + + +func (f BFields) Has(nme []byte) bool { + return findField(f.fields, 0, nme) != notFound } + + +func (f BFields) Count(nme []byte) int { + rs := 0 + for _, fl := range f.fields { + if bytes.Equal(fl.name, nme) { + rs++ + } + } + return rs +} + + +func (f BFields) Walk(walker BFieldsWalkFnc) { + for ln, ix := len(f.fields), 0; ix < ln; ix++ { + if !walker(ix, f.get(ix)) { + return + } + } +} + + + +func findField(list []BField, from int, name []byte) int { + for ln, ix := len(list), from; ix < ln; ix++ { + if bytes.Equal(list[ix].name, name) { + return ix + } + } + return notFound +} + + + + + + +func WithField(nme, val []byte) BFieldsFnc { + return func(f *BFields) error { return f.Add(nme, val) }} + + +func WithAtts(atts Att) BFieldsFnc { + return func(f *BFields) error { + f.Att = atts + return nil + } +} + + + diff --git a/core/btes/bfields/err.go b/core/btes/bfields/err.go new file mode 100644 index 0000000..5ed6ad0 --- /dev/null +++ b/core/btes/bfields/err.go @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err.go +// Created by DEV +// Modified 20/04/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 bfields + +import "errs" + +type ( + + Err struct { errs.ErrCode } + +) diff --git a/core/bins/chars/active.go b/core/btes/chars/active.go similarity index 100% rename from core/bins/chars/active.go rename to core/btes/chars/active.go diff --git a/core/bins/chars/ascii_char_atts.go b/core/btes/chars/ascii_char_atts.go similarity index 100% rename from core/bins/chars/ascii_char_atts.go rename to core/btes/chars/ascii_char_atts.go diff --git a/core/bins/chars/att.go b/core/btes/chars/att.go similarity index 100% rename from core/bins/chars/att.go rename to core/btes/chars/att.go diff --git a/core/bins/chars/char_atts.go b/core/btes/chars/char_atts.go similarity index 100% rename from core/bins/chars/char_atts.go rename to core/btes/chars/char_atts.go diff --git a/core/bins/go.mod b/core/btes/go.mod similarity index 100% rename from core/bins/go.mod rename to core/btes/go.mod diff --git a/core/crypts/active.go b/core/crypts/active.go new file mode 100644 index 0000000..22a1ceb --- /dev/null +++ b/core/crypts/active.go @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 16/02/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 crypts + +import "errs" + +var ( + + G = struct { + ErrNotImplemented Err + }{ + ErrNotImplemented: Err { errs.ErrCode("crypter-not-implemented")} , + } +) \ No newline at end of file diff --git a/core/crypts/crypter.go b/core/crypts/crypter.go new file mode 100644 index 0000000..768b461 --- /dev/null +++ b/core/crypts/crypter.go @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name crypter.go +// Created by DEV +// Modified 16/02/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 crypts + + +type ( + + Crypter interface { + Encrypter + Decrypter + } +) + + diff --git a/core/crypts/decrypter.go b/core/crypts/decrypter.go new file mode 100644 index 0000000..93e0b2e --- /dev/null +++ b/core/crypts/decrypter.go @@ -0,0 +1,43 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name decrypter.go +// Created by DEV +// Modified 16/02/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 crypts + +import "rsts" + +type ( + + Decrypter interface { + Decrypt (data []byte) rsts.Bytes + } + + + DecrypterNop struct {} + +) + + + +func (_ DecrypterNop) Decrypt (_ []byte) rsts.Bytes { + return rsts.MakeBytesError(G.ErrNotImplemented) } + diff --git a/core/crypts/encrypter.go b/core/crypts/encrypter.go new file mode 100644 index 0000000..b954654 --- /dev/null +++ b/core/crypts/encrypter.go @@ -0,0 +1,45 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name encrypter.go +// Created by DEV +// Modified 16/02/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 crypts + +import ( + + "rsts" +) + +type ( + + + Encrypter interface { + Encrypt (data []byte) rsts.Bytes + } + + + + EncrypterNop struct {} +) + + +func (_ EncrypterNop) Encrypt (_ []byte) rsts.Bytes { + return rsts.MakeBytesError(G.ErrNotImplemented) } \ No newline at end of file diff --git a/core/crypts/err.go b/core/crypts/err.go new file mode 100644 index 0000000..cfc6ca7 --- /dev/null +++ b/core/crypts/err.go @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err.go +// Created by DEV +// Modified 20/04/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 crypts + +import "errs" + +type Err struct { errs.ErrCode } + + diff --git a/core/crypts/go.mod b/core/crypts/go.mod new file mode 100644 index 0000000..5a530a3 --- /dev/null +++ b/core/crypts/go.mod @@ -0,0 +1,4 @@ +module crypts + + +go 1.20 diff --git a/core/errs/active.go b/core/errs/active.go index 858c1da..72c6ffb 100644 --- a/core/errs/active.go +++ b/core/errs/active.go @@ -73,7 +73,7 @@ var ( -func ToErr (err any) error { +func ToError(err any) error { if err == nil { return nil } @@ -85,6 +85,8 @@ func ToErr (err any) error { } + + func ToFormat (err error, formatter ErrorFormatter) string { if formatter != nil { return string(formatter.FormatError(err)) @@ -108,7 +110,7 @@ func PanicRecoveredError (rec any) error { if rec == nil { return nil } - return *NewErrPanic(ToErr(rec)) + return *NewErrPanic(ToError(rec)) } diff --git a/core/errs/err_cause.go b/core/errs/err_cause.go index ee97595..bbdf4a1 100644 --- a/core/errs/err_cause.go +++ b/core/errs/err_cause.go @@ -65,11 +65,12 @@ func (e ErrCause) WrapWithTrace(offset int) error { -func (e ErrCause) String () string { - return string(G.Formatter.FormatError(e)) } +func (e ErrCause) String () string { + return string(G.Formatter.FormatError(e)) } + func (e ErrCause) BuildFormat(builder fmtr.Builder) { builder.Build(e,nil) } diff --git a/core/errs/err_info.go b/core/errs/err_info.go index a88224d..3ed4bed 100644 --- a/core/errs/err_info.go +++ b/core/errs/err_info.go @@ -35,7 +35,11 @@ type ( error message string info string + desc string + help string + link string date time.Time + metas map[string]string } diff --git a/core/errs/fmtr/active.go b/core/errs/fmtr/active.go index 3dd54fd..3f10221 100644 --- a/core/errs/fmtr/active.go +++ b/core/errs/fmtr/active.go @@ -133,23 +133,6 @@ func AddCollector (collector FieldCollector) { func defaultCollectors () FieldCollectors { return []FieldCollector{ - CollectFieldFnc(func (b FieldBuilder, e error ) bool { - if ms,is := e.(interface { Code() string }); is { - b.AddFieldString(FieldNameCode, ms.Code()) - return true - } - return false - }), - - - CollectFieldFnc(func (b FieldBuilder, e error ) bool { - if ms,is := e.(interface { Code() string }); is { - b.AddFieldString(FieldNameCode, ms.Code()) - return true - } - return false - }), - CollectFieldFnc(func (b FieldBuilder, e error ) bool { if ms,is := e.(interface { Message() string }); is { diff --git a/core/errs/fmtr/ftext/active.go b/core/errs/fmtr/ftext/active.go index bd4ba25..436633f 100644 --- a/core/errs/fmtr/ftext/active.go +++ b/core/errs/fmtr/ftext/active.go @@ -62,7 +62,8 @@ func DefaultFormatter () *TextFormatter { c.Main.Set(0, func (b *TextBuilder){ b.AddTextAnsi("# ERROR #####################################################\n",ansi.Code(0).SetFgColor(ansi.ColorHRed).SetStyle(ansi.StyleBold)) }, - nil) + func (b *TextBuilder){ + b.AddTextAnsi("#############################################################\n",ansi.Code(0).SetFgColor(ansi.ColorHRed).SetStyle(ansi.StyleBold)) },) c.Head.Set(ansi.Code(0).SetFgColor(ansi.ColorHRed),nil,nil) diff --git a/core/errs/fmtr/ftext/builder.go b/core/errs/fmtr/ftext/builder.go index 56adb94..ed6f648 100644 --- a/core/errs/fmtr/ftext/builder.go +++ b/core/errs/fmtr/ftext/builder.go @@ -155,6 +155,16 @@ func (s *TextBuilder) Build(err error, fbuilder fmtr.BuildFieldFnc) { s.f.sections.Head.end(s) } } + + if s.f.AddCode() { + if ec,is := err.(interface { Code() string}); is { + cd := ec.Code() + if cd != err.Error() { + s.writeField(fmtr.FieldNameCode, cd, false) + } + } + } + if fbuilder != nil { if s.level == 0 { s.f.sections.Fields.begin(s) @@ -195,11 +205,14 @@ func (s *TextBuilder) format (err error) { } if s.f.AddCause() { - s.f.sections.Causes.begin(s) - if fe = s.addCause(err); fe != nil { - s.f.onCauseError(s,err,fe) + cl := getCauses(err) + if len(cl) > 0 { + s.f.sections.Causes.begin(s) + if fe = s.addCauses(cl); fe != nil { + s.f.onCauseError(s, err, fe) + } + s.f.sections.Causes.end(s) } - s.f.sections.Causes.end(s) } if s.f.AddTrace() { @@ -273,14 +286,16 @@ func (s *TextBuilder) addError(err error) (fe error) { -func (s *TextBuilder) addCause(err error) (fe error) { - ls := getCauses(err) - for _,ce := range ls { +func (s *TextBuilder) addCauses (causes []error) (fe error) { + if len(causes) == 0 { + return + } + for _,ce := range causes { s.incLevel() s.f.sections.Cause.begin(s) if fe := s.addError(ce); fe == nil { - fe = s.addCause(ce) + fe = s.addCauses(getCauses(ce)) } if fe != nil { s.f.onCauseError(s,ce,fe) @@ -297,8 +312,6 @@ func (s *TextBuilder) addCause(err error) (fe error) { } - - func getCauses (err error) []error { if err == nil { return nil @@ -355,6 +368,7 @@ func (s *TextBuilder) addTrace (err error) (fe error) { + func (s *TextBuilder) setAnsi(ansiC ansi.Code) { if ansiC != 0 { s.ansiC = ansiC diff --git a/core/errs/fmtr/ftext/option.go b/core/errs/fmtr/ftext/option.go index 8d2b947..e72ab0b 100644 --- a/core/errs/fmtr/ftext/option.go +++ b/core/errs/fmtr/ftext/option.go @@ -28,6 +28,7 @@ const ( AddWrapped Option = 1 << iota AddType + AddCode AddFields AddCause AddTrace @@ -35,42 +36,45 @@ const ( UseIndent NotShowEmpty - optionsDefault = AddWrapped | AddType | ShowAnsi | UseIndent | AddFields | AddCause | AddTrace | NotShowEmpty + optionsDefault = AddWrapped | AddCode | AddType | ShowAnsi | UseIndent | AddFields | AddCause | AddTrace | NotShowEmpty ) type ( - Option uint8 + Option uint16 ) -func (s Option) SetDefaults () Option { +func (o Option) SetDefaults () Option { return optionsDefault } -func (s Option) AddWrapped() bool { - return s&AddWrapped !=0 } +func (o Option) AddWrapped() bool { + return o&AddWrapped !=0 } -func (s Option) AddType() bool { - return s&AddType !=0 } +func (o Option) AddType() bool { + return o&AddType !=0 } -func (s Option) ShowAnsi () bool { - return s&ShowAnsi !=0 } +func (o Option) AddCode() bool { + return o&AddCode != 0 } -func (s Option) UseIndent() bool { - return s&UseIndent !=0 } +func (o Option) ShowAnsi () bool { + return o&ShowAnsi !=0 } -func (s Option) AddFields() bool { - return s&AddFields !=0 } +func (o Option) UseIndent() bool { + return o&UseIndent !=0 } -func (s Option) AddCause() bool { - return s&AddCause !=0 } +func (o Option) AddFields() bool { + return o&AddFields !=0 } -func (s Option) AddTrace() bool { - return s&AddTrace !=0 } +func (o Option) AddCause() bool { + return o&AddCause !=0 } -func (s Option) NotShowEmpty() bool { - return s&NotShowEmpty !=0 } +func (o Option) AddTrace() bool { + return o&AddTrace !=0 } + +func (o Option) NotShowEmpty() bool { + return o&NotShowEmpty !=0 } diff --git a/core/packs/active.go b/core/packs/active.go new file mode 100644 index 0000000..2433139 --- /dev/null +++ b/core/packs/active.go @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------ +// 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 packs + +import ( + "errs" + "syncs" +) + +const( + + TagKey = "pack" +) + +const ( + caseMask = ^byte(0x20) // Mask to ignore case in ASCII. + kelvin = '\u212a' + smallLongEss = '\u017f' +) + + +var ( + + G = struct { + + ErrInvalidState Err + ErrInvalidNode Err + ErrInvalidKey Err + ErrDuplicatedKey Err + ErrKeyRequired Err + ErrValueRequired Err + ErrInvalidList Err + ErrRedundantPack Err + ErrInvalidValue Err + ErrUnsupportedType Err + }{ + ErrInvalidState : Err{errs.ErrCode("invalid-state")}, + ErrInvalidNode : Err{errs.ErrCode("invalid-node")}, + ErrInvalidKey : Err{errs.ErrCode("invalid-key")}, + ErrDuplicatedKey : Err{errs.ErrCode("duplicated-key")}, + ErrKeyRequired : Err{errs.ErrCode("key-required")}, + ErrValueRequired : Err{errs.ErrCode("value-required")}, + ErrInvalidList : Err{errs.ErrCode("invalid-list")}, + ErrRedundantPack : Err{errs.ErrCode("redundant-pack")}, + ErrInvalidValue : Err{errs.ErrCode("invalid-value")}, + ErrUnsupportedType: Err{errs.ErrCode("unsupported-type")}, + } + + g = struct { + poolsSem uint32 + statePool *syncs.Pool[State] + } {} + +) + + + + + diff --git a/core/packs/builder.go b/core/packs/builder.go new file mode 100644 index 0000000..c5e899b --- /dev/null +++ b/core/packs/builder.go @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packabler.go +// Created by DEV +// Modified 24/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 packs + + + +type ( + + Builder interface { + + Build (packer Packer) error + } + + + BuildFnc func (packer Packer) error + +) + + + +func (f BuildFnc) Build (packer Packer) error { + return f(packer) } + diff --git a/core/packs/err.go b/core/packs/err.go new file mode 100644 index 0000000..d8b1b3b --- /dev/null +++ b/core/packs/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err.go +// Created by DEV +// Modified 20/04/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 packs + +import "errs" + +type ( + + Err struct { errs.ErrCode } +) + + diff --git a/core/packs/flags.go b/core/packs/flags.go new file mode 100644 index 0000000..11799e1 --- /dev/null +++ b/core/packs/flags.go @@ -0,0 +1,241 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name f.go +// Created by DEV +// Modified 29/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 packs + +import ( + "bits" + "reflect" + "strings" + "time" + "unicode" +) + +const ( + + FlagOmit Flags = 1 << iota + FlagOmitEmpty + FlagQuote + FlagScapeHTML + FlagString + FlagEncrypted + + FlagBinary64 Flags = 0b0000100000000000 + FlagBinary32 Flags = 0b0000010000000000 + flagMaskBin Flags = 0b0000110000000000 + + FlagDateRFC822 Flags = 0b0001000000000000 + FlagDateUnix Flags = 0b0010000000000000 + FlagDateANSIC Flags = 0b0100000000000000 + FlagDateRFC850 Flags = 0b1000000000000000 + flagMaskDate Flags = 0b1111000000000000 + +) + + +type Flags bits.BFlags16 + + +func (f Flags) Omit () bool { + return f&FlagOmit != 0 } + + +func (f Flags) OmitEmpty () bool { + return f&FlagOmitEmpty != 0 } + + +func (f Flags) Quote () bool { + return f&FlagQuote != 0 } + + +func (f Flags) EscapeHTML () bool { + return f&FlagScapeHTML != 0 } + + +func (f Flags) String () bool { + return f&FlagString != 0 } + + +func (f Flags) Encrypted() bool { + return f&FlagEncrypted != 0 } + + +func (f Flags) Binary () bool { + return f&(FlagBinary64|FlagBinary32) != 0 } + + +func (f Flags) Bin64 () bool { + return f&FlagBinary64 != 0 } + + +func (f Flags) Bin32 () bool { + return f&FlagBinary32 != 0 } + + + + +func (f Flags) SetDate (flagDate Flags) Flags { + return (f&flagMaskDate) | flagDate } + + +func (f Flags) SetBinary (flagBinary Flags) Flags { + return (f&flagMaskBin) | flagBinary } + + + + +func (f Flags) Names () string { + var ls []string + if f&FlagOmit != 0 { ls = append(ls,"omit")} + if f&FlagOmitEmpty != 0 { ls = append(ls,"omitempty")} + if f&FlagQuote != 0 { ls = append(ls,"quote")} + if f&FlagScapeHTML != 0 { ls = append(ls,"html")} + if f&FlagString != 0 { ls = append(ls,"string")} + + if f&flagMaskBin != 0 { + ls = append(ls,f.binName()) + } + if f&flagMaskDate != 0 { + ls = append(ls,f.dateName()) + } + + if len(ls) > 0 { + return strings.Join(ls,",") + } + return "" +} + + +func (f Flags) binName () string { + switch f & flagMaskBin { + case FlagBinary64 : return "b64" + case FlagBinary32 : return "b32" + } + return "" +} + + +func (f Flags) dateName() string { + switch f & flagMaskDate { + case FlagDateUnix : return "unix" + case FlagDateRFC822: return "rfc822" + case FlagDateANSIC : return "ansic" + case FlagDateRFC850: return "rfc8550" + default: return "rfc822z" + } +} + + +func (f Flags) DateFormat () string { + switch f & flagMaskDate { + case FlagDateUnix : return time.UnixDate + case FlagDateRFC822: return time.RFC822 + case FlagDateANSIC : return time.ANSIC + case FlagDateRFC850: return time.RFC850 + default: return time.RFC822Z + } +} + + +func FlagByName (flag string) (f Flags) { + switch strings.ToLower(flag) { + + case "-","omit" : return FlagOmit + case "o","omitempty": return FlagOmitEmpty + case "q","quote" : return FlagQuote + case "h","html" : return FlagScapeHTML + case "s","string" : return FlagString + case "e","encrypted": return FlagEncrypted + + // formato binario + case "b64","bin64" : return FlagBinary64 + case "b32","bin32" : return FlagBinary32 + + // formatos de fechas + case "unix" : return FlagDateUnix + case "rfc822" : return FlagDateRFC822 + case "ansic" : return FlagDateANSIC + case "rfc850" : return FlagDateRFC850 + case "rfc822z": return 0 + + default: return 0 + } +} + + + + + +func FlagsWithNames(flags ... string) Flags { + var f Flags + for _,n := range flags { + f |= FlagByName(n) + } + return f +} + + + +func FlagsWithString(flags string, onOption func(string) Flags) Flags { + + var f Flags + if len(flags) == 0 { + return f + } + nf := f + for flags != "" { + var op string + op,flags,_ = strings.Cut(flags,",") + nf |= onOption(op) + } + return nf +} + +func FlagsFromPackTag (raw reflect.StructTag) (string,Flags,bool) { + return FlagsFromTag(raw,TagKey,FlagByName) } + + + +func FlagsFromTag(raw reflect.StructTag, tag string, onOption func(string) Flags) (string,Flags,bool) { + st,ok := raw.Lookup(tag) + if !ok { + return "",0,false + } + nm,op,_ := strings.Cut(st,",") + return nm,FlagsWithString(op,onOption),true +} + + +func CheckTag(tag string) bool { + if tag == "" { + return false + } + for _, c := range tag { + switch { + case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c): + case !unicode.IsLetter(c) && !unicode.IsDigit(c): + return false + } + } + return true +} \ No newline at end of file diff --git a/core/packs/fold.go b/core/packs/fold.go new file mode 100644 index 0000000..a270311 --- /dev/null +++ b/core/packs/fold.go @@ -0,0 +1,122 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name fold.go +// Created by DEV +// Modified 08/02/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 packs + +import ( + "bins/chars" + "bytes" + "unicode/utf8" +) + +// GetFoldFunc returns one of four different case folding equivalence +// functions, from most general (and slow) to fastest: +// +// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 +// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') +// 3) asciiEqualFold, no special, but includes non-letters (including _) +// 4) simpleLetterEqualFold, no specials, no non-letters. +// +// The letters S and K are special because they map to 3 runes, not just 2: +// - S maps to s and to U+017F 'ſ' Latin small letter long s +// - k maps to K and to U+212A 'K' Kelvin sign +// +// See https://play.golang.org/p/tTxjOc0OGo +// +// The returned function is specialized for matching against s and +// should only be given s. It's not curried for performance reasons. + + +type FoldFnc func(s, t []byte) bool + + +func GetFoldFunc(s []byte) FoldFnc { + nonLetter := false + special := false // special letter + for _, b := range s { + if b >= utf8.RuneSelf { + return bytes.EqualFold + } + upper := b & caseMask + if upper < 'A' || upper > 'Z' { + nonLetter = true + } else if upper == 'K' || upper == 'S' { + // See above for why these letters are special. + special = true + } + } + if special { + return equalFoldRight + } + if nonLetter { + return chars.G.ASCII.EqualFold + } + return chars.G.ASCII.SimpleLetterEqualFold +} + + +// equalFoldRight is a specialization of bytes.EqualFold when s is +// known to be all ASCII (including punctuation), but contains an 's', +// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. +// See comments on GetFoldFunc. +func equalFoldRight(s, t []byte) bool { + for _, sb := range s { + if len(t) == 0 { + return false + } + tb := t[0] + if tb < utf8.RuneSelf { + if sb != tb { + sbUpper := sb & caseMask + if 'A' <= sbUpper && sbUpper <= 'Z' { + if sbUpper != tb&caseMask { + return false + } + } else { + return false + } + } + t = t[1:] + continue + } + // sb is ASCII and t is not. t must be either kelvin + // sign or long s; sb must be s, S, k, or K. + tr, size := utf8.DecodeRune(t) + switch sb { + case 's', 'S': + if tr != smallLongEss { + return false + } + case 'k', 'K': + if tr != kelvin { + return false + } + default: + return false + } + t = t[size:] + + } + return len(t) == 0 +} + diff --git a/core/packs/go.mod b/core/packs/go.mod new file mode 100644 index 0000000..a94d821 --- /dev/null +++ b/core/packs/go.mod @@ -0,0 +1,7 @@ +module packs + + +go 1.22 + + + diff --git a/core/packs/list_pack_builder.go b/core/packs/list_pack_builder.go new file mode 100644 index 0000000..a2dc618 --- /dev/null +++ b/core/packs/list_pack_builder.go @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com, flags Flags) 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", flags Flags); +// 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 packs + +import "time" + +type ( + + ListPackBuilder interface { + + Error () error + + ItemAny (value any, flags Flags) + + ItemRaw (value []byte, flags Flags) + + ItemBinary (value []byte, flags Flags) + ItemString (value string, flags Flags) + + ItemBool (value bool, flags Flags) + + ItemInt8 (value int8, flags Flags) + ItemInt16 (value int16, flags Flags) + ItemInt32 (value int32, flags Flags) + ItemInt64 (value int64, flags Flags) + + ItemUInt8 (value uint8, flags Flags) + ItemUInt16 (value uint16, flags Flags) + ItemUInt32 (value uint32, flags Flags) + ItemUInt64 (value uint64, flags Flags) + + ItemFloat32 (value float32, flags Flags) + ItemFloat64 (value float64, flags Flags) + + ItemDate (value time.Time, flags Flags) + + ItemList (builder func(ListPackBuilder, Flags), flags Flags) + ItemMap (builder func(MapPackBuilder, Flags), flags Flags) + ItemObject(builder func(ObjectPackBuilder,Flags), flags Flags) + + } +) + diff --git a/core/packs/map_pack_builder.go b/core/packs/map_pack_builder.go new file mode 100644 index 0000000..b30ccd3 --- /dev/null +++ b/core/packs/map_pack_builder.go @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com, flags Flags) 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", flags Flags); +// 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 packs + +import "time" + +type ( + + MapPackBuilder interface { + + KeyValueAny (key any, value any, flags Flags) + + KeyValueRaw (key any,value []byte, flags Flags) + + KeyValueBinary(key any, value []byte, flags Flags) + KeyValueString(key any, value string, flags Flags) + + KeyValueBool (key any, value bool, flags Flags) + + KeyValueInt8 (key any, value int8 , flags Flags) + KeyValueInt16 (key any, value int16, flags Flags) + KeyValueInt32 (key any, value int32, flags Flags) + KeyValueInt64 (key any, value int64, flags Flags) + + KeyValueUInt8 (key any, value uint8 , flags Flags) + KeyValueUInt16 (key any, value uint16, flags Flags) + KeyValueUInt32 (key any, value uint32, flags Flags) + KeyValueUInt64 (key any, value uint64, flags Flags) + + KeyValueFloat32(key any, value float32, flags Flags) + KeyValueFloat64(key any, value float64, flags Flags) + + KeyValueDate (key any, value time.Time, flags Flags) + + KeyValueList (key any, builder func(ListPackBuilder, Flags), flags Flags) + KeyValueMap (key any, builder func(MapPackBuilder, Flags), flags Flags) + KeyValueObject(key any, builder func(ObjectPackBuilder,Flags), flags Flags) + + } + +) + + + diff --git a/core/packs/object_pack_builder.go b/core/packs/object_pack_builder.go new file mode 100644 index 0000000..1ac74c0 --- /dev/null +++ b/core/packs/object_pack_builder.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 packs + +import "time" + +type ( + + ObjectPackBuilder interface { + + Error () error + + FieldAny (name string, value any, flags Flags) + + FieldRaw (name string, value []byte, flags Flags) + + FieldBinary (name string, value []byte, flags Flags) + FieldString (name string, value string, flags Flags) + + FieldBool (name string, value bool, flags Flags) + + FieldInt8 (name string, value int8 , flags Flags) + FieldInt16 (name string, value int16, flags Flags) + FieldInt32 (name string, value int32, flags Flags) + FieldInt64 (name string, value int64, flags Flags) + + FieldUInt8 (name string, value uint8, flags Flags) + FieldUInt16 (name string, value uint16, flags Flags) + FieldUInt32 (name string, value uint32, flags Flags) + FieldUInt64 (name string, value uint64, flags Flags) + + FieldFloat32 (name string, value float32, flags Flags) + FieldFloat64 (name string, value float64, flags Flags) + + FieldDate (name string, value time.Time, flags Flags) + + FieldList (name string, builder func(ListPackBuilder, Flags), flags Flags) + FieldMap (name string, builder func(MapPackBuilder, Flags), flags Flags) + FieldObject(name string, builder func(ObjectPackBuilder,Flags), flags Flags) + } + +) + + + diff --git a/core/packs/packer.go b/core/packs/packer.go new file mode 100644 index 0000000..8361acb --- /dev/null +++ b/core/packs/packer.go @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------ +// 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 packs + +type ( + + Packer interface { + + Pack (value any, flags Flags) + + Packet () []byte + Error () error + + Reset () + } +) + + + + + diff --git a/core/packs/packer_state.go b/core/packs/packer_state.go new file mode 100644 index 0000000..04735b6 --- /dev/null +++ b/core/packs/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 packs + +import ( + + "bins/bfers" + "crypts" + "sync/atomic" + "syncs" +) + + + + +type ( + + + State struct { + /*Embedded*/*bfers.Buffer + Temp [64]byte + Level int + Error error + checks map[any]struct{} + counts []int + Encrypter crypts.Encrypter + } + + StateFnc func (st *State) + +) + + +func NewState(options ...StateFnc) *State { + if atomic.CompareAndSwapUint32(&g.poolsSem,0,1) { + g.statePool = syncs.NewPool[State]( + syncs.PoolWithNew[State](func() *State { + return &State{ + Buffer : bfers.NewBuffer(), + checks : make(map[any]struct{}), + counts : []int{0}, + Encrypter: crypts.EncrypterNop{}, + } + }), + ) + } + if len(options) == 0 { + return g.statePool.Get() + } + st := g.statePool.Get() + for _,o := range options { + o(st) + } + return st +} + + +func ReleaseState (state *State) { + if state == nil { + state.Encrypter = crypts.EncrypterNop{} + state.Buffer.Reset() + state.Error = nil + state.counts= append(state.counts[:0],0) + if len(state.checks) > 0 { + for k,_ := range state.checks { + delete(state.checks,k) + } + } + 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.Level = 0 + return true +} + + + +func (s *State) CheckCycle (ptr any) (func(),bool) { + if _,hs := s.checks[ptr]; hs { + s.SetError(G.ErrRedundantPack) + return nil,false + } + s.checks[ptr]=struct{}{} + return func(){ delete(s.checks,ptr) },true +} + + + +func (s *State) Open(opener byte) { + s.WriteByte(opener) + s.Level++ + s.counts = append(s.counts,0) +} + + +func (s *State) Close(closer byte) { + s.WriteByte(closer) + s.Level-- + if s.Level < 0 { + s.SetError(G.ErrInvalidNode) + } + s.counts = s.counts[:len(s.counts)-1] +} + + +func (s *State) Count() int { + if s.Error != nil { + return 0 + } + return s.counts[s.Level] +} + + +func (s *State) Inc () { + if s.Error == nil { + s.counts[s.Level] += 1 + } +} \ No newline at end of file diff --git a/core/packs/pjson/active.go b/core/packs/pjson/active.go new file mode 100644 index 0000000..51a7132 --- /dev/null +++ b/core/packs/pjson/active.go @@ -0,0 +1,127 @@ +// ------------------------------------------------------------------------ +// 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 ( + + "encoding" + "encoding/json" + "packs" + "reflect" + "rsts" + "sync" + "unicode/utf8" +) + + +const ( + + jsonTag = "json" + + maxCyclesAfter = 100 + + defaultFlags = packs.Flags(0) +) + + + +var ( + g = struct { + hex string + jsonChars [utf8.RuneSelf]jsonCharAtt + + nullValue []byte + zeroValue []byte + trueValue []byte + falseValue []byte + + floatNaN []byte + floatInfPos []byte + floatInfNeg []byte + + + packersCache sync.Map + keyersCache sync.Map + fieldsCache sync.Map + + jsonMarshalerType reflect.Type + textMarshalerType reflect.Type + packMarshalerType reflect.Type + + }{ + + hex: "0123456789abcdef", + jsonChars: initJSONChars(), + + nullValue: []byte{'n', 'u', 'l', 'l'}, + zeroValue: []byte{'0'}, + trueValue: []byte{'"','t', 'r', 'u', 'e','"'}, + falseValue: []byte{'"','f', 'a', 'l', 's', 'e','"'}, + + floatNaN: []byte{'"', 'N', 'a', 'N', '"'}, + floatInfPos: []byte{'"', 'I', 'n', 'f', '"'}, + floatInfNeg: []byte{'"', '-', 'I', 'n', 'f', '"'}, + + + jsonMarshalerType: reflect.TypeOf((*json.Marshaler)(nil)).Elem(), + textMarshalerType: reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem(), + packMarshalerType: reflect.TypeOf((*packs.Packer)(nil)).Elem(), + + } +) + + +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 +} + + + + +func Pack (value any, options ... PackerFnc) (res rsts.Bytes) { + p := NewPacker(options ...) + p.Pack(value,defaultFlags) + if p.Error() != nil { + res = rsts.MakeBytesError(p.Error()) + } else { + res = rsts.MakeBytesSuccess(p.Packet()) + } + p.Release() + return res +} + + + + + diff --git a/core/packs/pjson/char_atts.go b/core/packs/pjson/char_atts.go new file mode 100644 index 0000000..b034c41 --- /dev/null +++ b/core/packs/pjson/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/core/packs/pjson/list_pack_builder.go b/core/packs/pjson/list_pack_builder.go new file mode 100644 index 0000000..037d057 --- /dev/null +++ b/core/packs/pjson/list_pack_builder.go @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name builder_list.go +// Created by DEV +// Modified 06/02/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 ( + "packs" + "time" +) + +func (p *Packer) ItemAny (value any, flags packs.Flags) { p.addItem(func(){ p.PackAny(value,flags) }) } + + +func (p *Packer) ItemRaw (value []byte, flags packs.Flags) { p.addItem(func() { p.PackRaw(value,flags) }) } + +func (p *Packer) ItemBinary (value []byte, flags packs.Flags) { p.addItem(func (){ p.PackBinary(value,flags) }) } + +func (p *Packer) ItemString (value string, flags packs.Flags) { p.addItem(func (){ p.PackString(value,flags) }) } + + +func (p *Packer) ItemBool (value bool, flags packs.Flags) { p.addItem(func (){ p.PackBool(value,flags) }) } + +func (p *Packer) ItemInt8 (value int8 , flags packs.Flags) { p.addItem(func (){ packInt(p.state,int64(value),flags) }) } +func (p *Packer) ItemInt16 (value int16, flags packs.Flags) { p.addItem(func (){ packInt(p.state,int64(value),flags) }) } +func (p *Packer) ItemInt32 (value int32, flags packs.Flags) { p.addItem(func (){ packInt(p.state,int64(value),flags) }) } +func (p *Packer) ItemInt64 (value int64, flags packs.Flags) { p.addItem(func (){ packInt(p.state,value,flags) }) } + +func (p *Packer) ItemUInt8 (value uint8 , flags packs.Flags){ p.addItem(func (){ packUInt(p.state,uint64(value),flags) }) } +func (p *Packer) ItemUInt16 (value uint16, flags packs.Flags){ p.addItem(func (){ packUInt(p.state,uint64(value),flags) }) } +func (p *Packer) ItemUInt32 (value uint32, flags packs.Flags){ p.addItem(func (){ packUInt(p.state,uint64(value),flags) }) } +func (p *Packer) ItemUInt64 (value uint64, flags packs.Flags){ p.addItem(func (){ packUInt(p.state,uint64(value),flags) }) } + +func (p *Packer) ItemFloat32 (value float32, flags packs.Flags){ p.addItem(func (){ packFloatString(p.state,float64(value),flags,32)})} +func (p *Packer) ItemFloat64 (value float64, flags packs.Flags){ p.addItem(func (){ packFloatString(p.state,value,flags,64) })} + +func (p *Packer) ItemDate (value time.Time, flags packs.Flags) { p.addItem(func(){ packDate(p.state,value,flags); p.state.Inc() })} + + +func (p *Packer) ItemList (builder func(packs.ListPackBuilder, packs.Flags), flags packs.Flags) { + p.addItem(func(){ p.PackList(builder,flags) }) } + +func (p *Packer) ItemMap (builder func(packs.MapPackBuilder, packs.Flags), flags packs.Flags) { + p.addItem(func(){ p.PackMap(builder,flags) }) } + +func (p *Packer) ItemObject(builder func(packs.ObjectPackBuilder, packs.Flags), flags packs.Flags) { + p.addItem(func(){ p.PackObject(builder,flags) }) } + + + +func (p *Packer) addItem (caller func()) { + if p.state.Count() > 0 { + p.state.WriteByte(',') + } + caller() + if p.state != nil { + p.state.Inc() + } +} + + diff --git a/core/packs/pjson/map_pack_builder.go b/core/packs/pjson/map_pack_builder.go new file mode 100644 index 0000000..15e3838 --- /dev/null +++ b/core/packs/pjson/map_pack_builder.go @@ -0,0 +1,115 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name builderMap.go +// Created by DEV +// Modified 06/02/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 ( + "packs" + "reflect" + "time" +) + +func (p *Packer) KeyValueAny (key any, value any, flags packs.Flags) { + p.addKeyValue(key, func(){ p.PackAny(value,flags)}) } + +func (p *Packer) KeyValueRaw (key any,value []byte, flags packs.Flags) { + p.addKeyValue(key, func(){ p.PackRaw(value,flags)}) } + +func (p *Packer) KeyValueBinary (key any, value []byte, flags packs.Flags) { + p.addKeyValue(key, func(){ p.PackBinary(value,flags)}) } + +func (p *Packer) KeyValueString (key any, value string, flags packs.Flags) { + p.addKeyValue(key, func(){ p.PackString(value,flags)}) } + +func (p *Packer) KeyValueBool (key any, value bool, flags packs.Flags) { + p.addKeyValue(key, func(){ p.PackBool(value,flags)}) } + +func (p *Packer) KeyValueInt8 (key any, value int8 , flags packs.Flags) { p.addKeyValue(key, func(){ p.PackInt64(int64(value),flags)}) } +func (p *Packer) KeyValueInt16 (key any, value int16, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackInt64(int64(value),flags)}) } +func (p *Packer) KeyValueInt32 (key any, value int32, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackInt64(int64(value),flags)}) } +func (p *Packer) KeyValueInt64 (key any, value int64, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackInt64(value,flags)}) } + +func (p *Packer) KeyValueUInt8 (key any, value uint8 , flags packs.Flags) { p.addKeyValue(key, func(){ p.PackUInt64(uint64(value),flags)}) } +func (p *Packer) KeyValueUInt16 (key any, value uint16, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackUInt64(uint64(value),flags)}) } +func (p *Packer) KeyValueUInt32 (key any, value uint32, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackUInt64(uint64(value),flags)}) } +func (p *Packer) KeyValueUInt64 (key any, value uint64, flags packs.Flags) { p.addKeyValue(key, func(){ p.PackUInt64(value,flags)}) } + +func (p *Packer) KeyValueFloat32(key any, value float32, flags packs.Flags){ + p.addKeyValue(key,func(){ p.PackFloat32(value, flags) }) } + +func (p *Packer) KeyValueFloat64(key any, value float64, flags packs.Flags){ + p.addKeyValue(key,func(){ p.PackFloat64(value, flags) }) } + +func (p *Packer) KeyValueDate (key any, value time.Time, flags packs.Flags){ + p.addKeyValue(key,func(){ p.PackDate(value, flags) }) } + + + +func (p *Packer) KeyValueList (key any, builder func(packs.ListPackBuilder, packs.Flags), flags packs.Flags) { + p.addKeyValue(key,func(){ p.PackList(builder, flags) }) } + + +func (p *Packer) KeyValueMap (key any, builder func(packs.MapPackBuilder, packs.Flags), flags packs.Flags) { + p.addKeyValue(key,func(){ p.PackMap(builder, flags) }) } + + +func (p *Packer) KeyValueObject (key any, builder func(packs.ObjectPackBuilder,packs.Flags), flags packs.Flags) { + p.addKeyValue(key,func(){ p.PackObject(builder, flags) }) } + + +func (p *Packer) addKeyValue(key any, caller func()) { + if p.state.Count() > 0 { + p.state.WriteByte(',') + } + p.packStringifyKey(key) + if p.state.Error != nil { + return + } + p.state.WriteByte(':') + caller() + p.state.Inc() + +} + + +func (p *Packer) packStringifyKey(key any) { + switch v := key.(type) { + case string : p.PackString(v,packs.FlagScapeHTML) + case float32: p.PackFloat32(v,packs.FlagScapeHTML|packs.FlagQuote) + case float64: p.PackFloat64(v,packs.FlagScapeHTML|packs.FlagQuote) + default: + me := &rMapEntry{ + v : reflect.ValueOf(key), + } + fn := stringifyRKey(me.v.Type()) + if fn == nil { + p.state.SetError(packs.G.ErrInvalidKey) + return + } + if er := fn(me,me.v); er != nil { + p.state.SetError(er) + return + } + p.PackString(me.k,me.f) + } +} \ No newline at end of file diff --git a/core/packs/pjson/object_pack_builder.go b/core/packs/pjson/object_pack_builder.go new file mode 100644 index 0000000..91efbd0 --- /dev/null +++ b/core/packs/pjson/object_pack_builder.go @@ -0,0 +1,114 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name builder_object.go +// Created by DEV +// Modified 06/02/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 ( + "packs" + "time" +) + +func (p *Packer) FieldAny (name string, value any, flags packs.Flags) { + p.addField(name, func() { p.PackAny(value, flags) }) } + + +func (p *Packer) FieldRaw (name string, value []byte, flags packs.Flags){ + p.addField(name, func() { p.PackRaw(value, flags) }) } + +func (p *Packer) FieldBinary (name string, value []byte, flags packs.Flags) { + p.addField(name, func() { p.PackBinary(value, flags) }) } + +func (p *Packer) FieldString (name string, value string, flags packs.Flags) { + p.addField(name, func() { p.PackString(value, flags) }) +} + +func (p *Packer) FieldBool (name string, value bool, flags packs.Flags) { + p.addField(name, func() { p.PackBool(value, flags) }) +} + +func (p *Packer) FieldInt8 (name string, value int8 , flags packs.Flags) { + p.addField(name, func() { p.PackInt64(int64(value), flags) })} + +func (p *Packer) FieldInt16 (name string, value int16, flags packs.Flags) { + p.addField(name, func() { p.PackInt64(int64(value), flags) })} + +func (p *Packer) FieldInt32 (name string, value int32, flags packs.Flags) { + p.addField(name, func() { p.PackInt64(int64(value), flags) }) } + +func (p *Packer) FieldInt64 (name string, value int64, flags packs.Flags) { + p.addField(name, func() { p.PackInt64(value, flags) }) } + + +func (p *Packer) FieldUInt8 (name string, value uint8, flags packs.Flags) { + p.addField(name, func() { p.PackUInt64(uint64(value), flags) }) } + +func (p *Packer) FieldUInt16 (name string, value uint16, flags packs.Flags) { + p.addField(name,func(){ p.PackUInt64(uint64(value), flags) }) } + +func (p *Packer) FieldUInt32 (name string, value uint32, flags packs.Flags) { + p.addField(name,func(){ p.PackUInt64(uint64(value), flags) }) } + +func (p *Packer) FieldUInt64 (name string, value uint64, flags packs.Flags) { + p.addField(name,func(){ p.PackUInt64(value, flags) }) } + + +func (p *Packer) FieldFloat32(name string, value float32,flags packs.Flags) { + p.addField(name,func(){ p.PackFloat32(value, flags) }) +} + +func (p *Packer) FieldFloat64(name string, value float64,flags packs.Flags) { + p.addField(name,func(){ p.PackFloat64(value, flags) }) +} + +func (p *Packer) FieldDate (name string, value time.Time,flags packs.Flags) { + p.addField(name,func(){ p.PackDate(value, flags) }) +} + +func (p *Packer) FieldList (name string, builder func(packs.ListPackBuilder,packs.Flags), flags packs.Flags) { + p.addField(name,func(){ p.PackList(builder, flags) }) +} + +func (p *Packer) FieldMap (name string, builder func(packs.MapPackBuilder, packs.Flags), flags packs.Flags) { + p.addField(name,func(){ p.PackMap(builder, flags) }) +} + +func (p *Packer) FieldObject (name string, builder func(packs.ObjectPackBuilder,packs.Flags), flags packs.Flags) { + p.addField(name,func(){ p.PackObject(builder, flags) }) +} + + + +func (p *Packer) addField(name string, caller func()) { + if p.state.Count() > 0 { + p.state.WriteByte(',') + } + packString(p.state,name,packs.FlagScapeHTML) + if p.state.Error != nil { + return + } + p.state.WriteByte(':') + caller() + if p.state != nil { + p.state.Inc() + } +} \ No newline at end of file diff --git a/core/packs/pjson/packer.go b/core/packs/pjson/packer.go new file mode 100644 index 0000000..ff4a314 --- /dev/null +++ b/core/packs/pjson/packer.go @@ -0,0 +1,649 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name value_packer.go +// Created by DEV +// Modified 06/02/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 ( + "crypts" + "encoding/base32" + "encoding/base64" + "encoding/json" + "errs" + "math" + "packs" + "reflect" + "strconv" + "time" + "unicode/utf8" +) + + +type ( + + + Packer struct { + state *packs.State + dirty bool + } + + + PackerFnc func (packer *Packer) +) + + +func NewPacker (options ... PackerFnc) *Packer { + pk := &Packer { + state : packs.NewState(), + } + for _,o := range options { + o(pk) + } + return pk +} + + + +func (p *Packer) Pack (value any, flags packs.Flags) { + if p.state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(p.state.Error)) + } + if p.dirty { + panic(packs.G.ErrInvalidState) + } + p.dirty = true + p.PackAny(value,flags) +} + + +func (p *Packer) Packet () []byte { + + + + return p.state.Bytes() } + + +func (p *Packer) Error () error { + return p.state.Error } + + +func (p *Packer) Reset () { + p.state.Reset() + p.dirty = false +} + +func (p *Packer) Release () { + p.dirty = false + packs.ReleaseState(p.state) +} + + + + + +func (p *Packer) PackAny (value any, flags packs.Flags) { + if p.state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(p.state.Error)) + } + if value == nil { + p.state.W(g.nullValue) + return + } + + switch v := value.(type) { + case packs.Builder: + p.state.SetError(v.Build(p)) + + case json.Marshaler: + d,e := v.MarshalJSON() + if e != nil { + p.state.SetError(e) + } else { + p.state.W(d) + } + + case bool : packBool (p.state,v,flags ) + + case string : packString(p.state,v,flags ) + + case int : packInt(p.state,int64(v),flags) + case int8 : packInt(p.state,int64(v),flags) + case int16 : packInt(p.state,int64(v),flags) + case int32 : packInt(p.state,int64(v),flags) + case int64 : packInt(p.state,v,flags ) + + case uint : packUInt(p.state,uint64(v),flags) + case uint8 : packUInt(p.state,uint64(v),flags) + case uint16 : packUInt(p.state,uint64(v),flags) + case uint32 : packUInt(p.state,uint64(v),flags) + case uint64 : packUInt(p.state,v,flags ) + + case float32: packFloatString(p.state,float64(v),flags,32) + case float64: packFloatString(p.state,v,flags,64) + + case time.Time: packDate (p.state,v,flags) + + case reflect.Value: rTypePacker(v.Type())(p.state,v,flags) + + case []uint8 : + if flags.Binary() { + packBinary(p.state,v,flags) + return + } + packListUInt[uint8 ](p.state,v,flags) + case []uint : packListUInt [uint ] (p.state,v,flags) + case []uint16 : packListUInt [uint16] (p.state,v,flags) + case []uint32 : packListUInt [uint32] (p.state,v,flags) + case []uint64 : packListUInt [uint64] (p.state,v,flags) + case []int : packListInt [int ] (p.state,v,flags) + case []int8 : packListInt [int8 ] (p.state,v,flags) + case []int16 : packListInt [int16] (p.state,v,flags) + case []int32 : packListInt [int32] (p.state,v,flags) + case []int64 : packListInt [int64] (p.state,v,flags) + case []float32: packListFloat[float32](p.state,v,flags,32) + case []float64: packListFloat[float64](p.state,v,flags,64) + + case []bool : packListBool (p.state,v,flags) + case []string : packListString(p.state,v,flags) + case []time.Time: packListDate(p.state,v,flags) + + default: + rv := reflect.ValueOf(value) + rTypePacker(rv.Type())(p.state,rv,flags) + } +} + + + + +func (p *Packer) PackRaw (value []byte, flags packs.Flags) { packRaw(p.state,value,flags) } + +func (p *Packer) PackBinary (value []byte, flags packs.Flags) { packBinary(p.state,value,flags) } +func (p *Packer) PackString (value string, flags packs.Flags) { packString (p.state,value,flags) } + +func (p *Packer) PackBool (value bool, flags packs.Flags) { packBool(p.state,value,flags) } + +func (p *Packer) PackInt8 (value int8 , flags packs.Flags) { packInt(p.state,int64(value),flags) } +func (p *Packer) PackInt16 (value int16, flags packs.Flags) { packInt(p.state,int64(value),flags) } +func (p *Packer) PackInt32 (value int32, flags packs.Flags) { packInt(p.state,int64(value),flags) } +func (p *Packer) PackInt64 (value int64, flags packs.Flags) { packInt(p.state,value,flags)} + +func (p *Packer) PackUInt8 (value uint8 , flags packs.Flags) { packUInt(p.state,uint64(value),flags) } +func (p *Packer) PackUInt16 (value uint16, flags packs.Flags) { packUInt(p.state,uint64(value),flags) } +func (p *Packer) PackUInt32 (value uint32, flags packs.Flags) { packUInt(p.state,uint64(value),flags) } +func (p *Packer) PackUInt64 (value uint64, flags packs.Flags) { packUInt(p.state, value,flags) } + +func (p *Packer) PackFloat32 (value float32, flags packs.Flags) { packFloatString(p.state, float64(value), flags, 32) } +func (p *Packer) PackFloat64 (value float64, flags packs.Flags) { packFloatString(p.state, value, flags, 64) } + +func (p *Packer) PackDate (value time.Time, flags packs.Flags) { packDate(p.state,value,flags) } + + +func (p *Packer) PackList (builder func(packs.ListPackBuilder, packs.Flags), flags packs.Flags) { + p.packCompound('[',']',builder==nil,func(pk *Packer, fl packs.Flags){ builder(pk,fl) },flags) +} + +func (p *Packer) PackMap (builder func(packs.MapPackBuilder, packs.Flags), flags packs.Flags) { + p.packCompound('{','}',builder==nil,func(pk *Packer, fl packs.Flags){ builder(pk,fl) },flags) +} + +func (p *Packer) PackObject(builder func(packs.ObjectPackBuilder, packs.Flags), flags packs.Flags) { + p.packCompound('{','}',builder==nil,func(pk *Packer, fl packs.Flags){ builder(pk,fl) },flags) +} + + +func (p *Packer) packCompound (opener, closer byte, isnil bool, buildFn func(*Packer,packs.Flags), flags packs.Flags) { + if p.state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(p.state.Error)) + } + if isnil { + p.state.W(g.nullValue) + return + } + + dn := false + defer func(d *bool) { + if !(*d) { + p.state.SetError(errs.ToError(recover())) + } + }(&dn) + + p.state.Open(opener) + buildFn(p,flags) + if p.state.Error != nil { + return + } + p.state.Close(closer) + dn = true +} + + + +func packRaw (state *packs.State, value []byte, flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + if value == nil { + state.W(g.nullValue) + return + } + if len(value) == 0 { + state.Write2Byte('"','"') + return + } + state.WOQ(flags.Quote(),'"',value) +} + +func packString (state *packs.State, value string , flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + + if len(value) == 0 { + state.Write2Byte('"','"') + return + } + + if flags.Encrypted() { + packEncrypted(state, []byte(value), flags|packs.FlagBinary64) + return + } + + if flags.Binary() { + packBinary(state,[]byte(value),flags) + return + } + + + state.WriteByte('"') + start := 0 + for i := 0; i < len(value); { + if b := value[i]; b < utf8.RuneSelf { + if !g.jsonChars[b].isHtmlUnsafe() || (!flags.EscapeHTML() && !g.jsonChars[b].isUnsafe()) { + i++ + continue + } + + if start < i { + state.WriteString(value[start:i]) + } + state.WriteByte('\\') + switch b { + case '\\', '"': state.WriteByte(b) + case '\n': state.WriteByte('n') + case '\r': state.WriteByte('r') + case '\t': state.WriteByte('t') + default: + state.WriteString(`u00`) + state.Write2Byte(g.hex[b>>4], g.hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(value[i:]) + if c == utf8.RuneError && size == 1 { + if start < i { + state.WriteString(value[start:i]) + } + state.WriteString(`\ufffd`) + i += size + start = i + continue + } + + if c == '\u2028' || c == '\u2029' { + if start < i { + state.WriteString(value[start:i]) + } + state.WriteString(`\u202`) + state.WriteByte(g.hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + if start < len(value) { + state.WriteString(value[start:]) + } + state.WriteByte('"') +} + + +func packEncrypted (state *packs.State, value []byte, flags packs.Flags) { + r := state.Encrypter.Encrypt(value) + if !r.Ok() { + state.SetError(r.Fail()) + return + } + + state.WriteByte('"') + if flags.Bin64() || !flags.Binary() { + packBinary64(state, r.Value(), flags) + } else { + packBinary32(state, r.Value(), flags) + } + if state.Error == nil { + state.WriteByte('"') + } + return +} + +func packBinary (state *packs.State, value []byte , flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + + if value == nil { + _,_ = state.Write(g.nullValue) + return + } + if len(value) == 0 { + state.Write2Byte('"','"') + return + } + + if flags.Encrypted() { + packEncrypted(state,value,flags) + return + } + + state.WriteByte('"') + if flags.Bin64() { + packBinary64(state, value, 0) + } else if flags.Bin32() { + packBinary32(state, value, 0) + } else { + state.SetError(packs.G.ErrUnsupportedType) + return + } + if state.Error == nil { + state.WriteByte('"') + } +} + + +func packBinary64 (state *packs.State, value []byte , _ packs.Flags) { + ln := base64.StdEncoding.EncodedLen(len(value)) + if ln <= len(state.Temp) { + dst := state.Temp[:ln] + base64.StdEncoding.Encode(dst, value) + _,_= state.Write(dst) + } else if ln <= 1024 { + dst := make([]byte, ln) + base64.StdEncoding.Encode(dst, value) + _,_ = state.Write(dst) + } else { + ec := base64.NewEncoder(base64.StdEncoding, state) + _,_ = ec.Write(value) + state.SetError(ec.Close()) + } +} + +func packBinary32 (state *packs.State, value []byte , _ packs.Flags) { + ln := base32.StdEncoding.EncodedLen(len(value)) + if ln <= len(state.Temp) { + dst := state.Temp[:ln] + base32.StdEncoding.Encode(dst, value) + _,_= state.Write(dst) + } else if ln <= 1024 { + dst := make([]byte, ln) + base32.StdEncoding.Encode(dst, value) + _,_ = state.Write(dst) + } else { + ec := base32.NewEncoder(base32.StdEncoding, state) + _,_ = ec.Write(value) + state.SetError(ec.Close()) + } +} + + + + +func packBool (state *packs.State, value bool , flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + if value { + state.WOQ(flags.Quote(),'"', g.trueValue) + } else { + state.WOQ(flags.Quote(),'"', g.falseValue) + } +} + +func packInt (state *packs.State, value int64 , flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + + q :=flags.Quote() + if q { + state.WriteByte('"') + } + if value == 0 { + state.WriteByte('0') + } else { + state.WriteIntStr(value, 10) + } + if q { + state.WriteByte('"') + } +} + + +func packUInt (state *packs.State, value uint64 , flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + q :=flags.Quote() + if q { + state.WriteByte('"') + } + if value == 0 { + state.WriteByte('0') + } else { + state.WriteUIntStr(value, 10) + } + if q { + state.WriteByte('"') + } +} + +func packFloat (state *packs.State, value float64, flags packs.Flags) { + packFloatString(state, value, flags, 64) +} + +func packFloatString (state *packs.State, f float64, flags packs.Flags, bits int) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + + if math.IsInf(f, 0) || math.IsNaN(f) { + state.SetError(packs.G.ErrInvalidValue) + return + } + + abs := math.Abs(f) + fm := byte('f') + + if abs != 0 { + if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { + fm = 'e' + } + } + bf := state.Temp[:0] + bf = strconv.AppendFloat(bf, f, fm, -1, int(bits)) + if fm == 'e' { + // clean up e-09 to e-9 + n := len(bf) + if n >= 4 && bf[n-4] == 'e' && bf[n-3] == '-' && bf[n-2] == '0' { + bf[n-2] = bf[n-1] + bf = bf[:n-1] + } + } + + state.WOQ(flags.Quote(),'"',bf) +} + + +func packDate(state *packs.State, value time.Time, flags packs.Flags) { + if state.Error != nil { + panic(packs.G.ErrInvalidState.WrapWithCause(state.Error)) + } + state.WOQ(true,'"',value.AppendFormat(state.Temp[:0],flags.DateFormat())) +} + + + + + + +func packListString (state *packs.State, list []string, flags packs.Flags) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packString(state,v,flags) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + + +func packListBool (state *packs.State, list []bool, flags packs.Flags) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packBool(state,v,flags) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + + +func packListInt [T int | int8 | int16 | int32 | int64](state *packs.State, list []T, flags packs.Flags) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packInt(state,int64(v),flags) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + + +func packListUInt [T uint | uint8 | uint16 | uint32 | uint64](state *packs.State, list []T, flags packs.Flags) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packUInt(state,uint64(v),flags) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + + +func packListFloat[T float32 | float64](state *packs.State, list []T, flags packs.Flags, bits int) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packFloatString(state,float64(v),flags,bits) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + +func packListDate (state *packs.State, list []time.Time, flags packs.Flags) { + if !checkList(state,list == nil, len(list) ==0) { + return + } + state.WriteByte('[') + for i,v := range list { + if i > 0 { + state.WriteByte(',') + } + packDate(state,v,flags) + if state.Error != nil { + return + } + } + state.WriteByte(']') +} + + +func checkList (state *packs.State, isNull, isEmpty bool) bool { + if isNull { + state.Write2Byte('"','"') + return false + } + if isEmpty { + state.Write2Byte('[',']') + return false + } + return true +} + + + +func WithEncrypter(encrypter crypts.Encrypter) PackerFnc { + return func(p *Packer) { + if encrypter == nil { + encrypter = crypts.EncrypterNop{} + } + p.state.Encrypter = encrypter + } +} diff --git a/core/packs/pjson/rpacker.go b/core/packs/pjson/rpacker.go new file mode 100644 index 0000000..321d322 --- /dev/null +++ b/core/packs/pjson/rpacker.go @@ -0,0 +1,114 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker.go +// Created by DEV +// Modified 05/02/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 ( + "packs" + "reflect" + "sync" +) + +type ( + + + + rPackerFnc func (state *packs.State, rvalue reflect.Value, flags packs.Flags) + +) + + + +func rTypePacker (rtype reflect.Type) rPackerFnc { + if fn,ok := g.packersCache.Load(rtype); ok { + return fn.(rPackerFnc) + } + + var wg sync.WaitGroup + var fn rPackerFnc + + wg.Add(1) + + fi,ld := g.packersCache.LoadOrStore(rtype, rPackerFnc(func (e *packs.State, v reflect.Value, f packs.Flags) { + wg.Wait() + fn(e,v,f) + })) + if ld { + return fi.(rPackerFnc) + } + + fn = _rTypePacker(rtype) + wg.Done() + + g.packersCache.Store(rtype,fn) + return fn +} + + +func _rTypePacker(rtype reflect.Type) rPackerFnc { + + switch rtype.Kind() { + case reflect.Bool : return func(s *packs.State, v reflect.Value, f packs.Flags) { packBool (s,v.Bool (),f )} + case reflect.String : return func(s *packs.State, v reflect.Value, f packs.Flags) { packString(s,v.String(),f )} + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64 : return func(s *packs.State, v reflect.Value, f packs.Flags) { packInt (s,v.Int (),f )} + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64 : return func(s *packs.State, v reflect.Value, f packs.Flags) { packUInt (s,v.Uint (),f )} + case reflect.Float32: return func(s *packs.State, v reflect.Value, f packs.Flags) { packFloatString(s,v.Float(),f,32) } + case reflect.Float64: return func(s *packs.State, v reflect.Value, f packs.Flags) { packFloatString(s,v.Float(),f,64) } + + case reflect.Pointer: + return rPointerPacker(rtype) + + case reflect.Interface: + return rInterfacePacker + + case reflect.Slice, + reflect.Array : + return rListPacker(rtype) + + case reflect.Map : + return rMapPacker(rtype) + + case reflect.Struct: + return rObjectPacker(rtype) + + default: + return unsupportedTypePacker + } + +} + + +func unsupportedTypePacker(state *packs.State, _ reflect.Value, _ packs.Flags) { + state.SetError(packs.G.ErrUnsupportedType) +} + + + diff --git a/core/packs/pjson/rpacker_interface.go b/core/packs/pjson/rpacker_interface.go new file mode 100644 index 0000000..e88ebd5 --- /dev/null +++ b/core/packs/pjson/rpacker_interface.go @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_interface.go +// Created by DEV +// Modified 13/02/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 ( + "packs" + "reflect" +) + +func rInterfacePacker (s *packs.State, v reflect.Value, f packs.Flags) { + if v.IsNil() { + s.W(g.nullValue) + return + } + rValuePacker(v.Elem())(s,v,f) +} \ No newline at end of file diff --git a/core/packs/pjson/rpacker_key.go b/core/packs/pjson/rpacker_key.go new file mode 100644 index 0000000..beb889e --- /dev/null +++ b/core/packs/pjson/rpacker_key.go @@ -0,0 +1,166 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rkey.go +// Created by DEV +// Modified 05/02/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 ( + "encoding" + "math" + "packs" + "reflect" + "strconv" +) + +func stringifyRKey(rt reflect.Type) rMapEntryFnc { + fn,ok := g.keyersCache.Load(rt) + if !ok { + fn, _ = g.keyersCache.LoadOrStore(rt, _stringifyRKey(rt)) + } + return fn.(rMapEntryFnc) +} + + +func _stringifyRKey(rt reflect.Type) rMapEntryFnc { + + if rt.Kind() == reflect.String { + return func(e *rMapEntry, k reflect.Value) error { + e.k = k.String() + e.f = packs.FlagScapeHTML + return nil + } + } + + if rt.Implements(g.textMarshalerType) { + return func(e *rMapEntry, k reflect.Value) error { + if k.Kind() == reflect.Pointer && k.IsNil() { + return nil + } + bf, er := (k.Interface().(encoding.TextMarshaler)).MarshalText() + if er == nil { + e.k = string(bf) + e.f = packs.FlagScapeHTML + } + return er + } + } + + switch rt.Kind() { + + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + return func(e *rMapEntry, k reflect.Value) error { + e.k = strconv.FormatInt(k.Int(), 10) + return nil + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + return func(e *rMapEntry, k reflect.Value) error { + e.k = strconv.FormatUint(k.Uint(), 10) + return nil + } + + case reflect.Interface: + return func(e *rMapEntry, k reflect.Value) error { + k = k.Elem() + + if k.Type().Kind() == reflect.String { + e.k = k.String() + e.f = packs.FlagScapeHTML + return nil + } + + if t,h := k.Interface().(encoding.TextMarshaler); h { + if k.Type().Kind() == reflect.Pointer && k.IsNil() { + return nil + } + bf, er := t.MarshalText() + if er == nil { + e.k = string(bf) + e.f = packs.FlagScapeHTML + } + return er + } + + switch rt.Kind() { + + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + e.k = strconv.FormatInt(k.Int(), 10) + return nil + + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + e.k = strconv.FormatUint(k.Uint(), 10) + return nil + + default: + return packs.G.ErrInvalidKey + } + } + + default: + return nil + } +} + + + +func stringifyFloat (buffer []byte, f float64, bits int) []byte { + if math.IsInf(f, 0) || math.IsNaN(f) { + return nil + } + + abs := math.Abs(f) + fmt := byte('f') + + if abs != 0 { + if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { + fmt = 'e' + } + } + buffer = strconv.AppendFloat(buffer[:0], f, fmt, -1, int(bits)) + if fmt == 'e' { + // clean up e-09 to e-9 + n := len(buffer) + if n >= 4 && buffer[n-4] == 'e' && buffer[n-3] == '-' && buffer[n-2] == '0' { + buffer[n-2] = buffer[n-1] + buffer = buffer[:n-1] + } + } + return buffer +} + diff --git a/core/packs/pjson/rpacker_list.go b/core/packs/pjson/rpacker_list.go new file mode 100644 index 0000000..4eb22a9 --- /dev/null +++ b/core/packs/pjson/rpacker_list.go @@ -0,0 +1,132 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name packer_list.go +// Created by DEV +// Modified 05/02/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 ( + "packs" + "reflect" +) + +type ( + + rList struct { + packFn rPackerFnc + } +) + + +func rListPacker (rtype reflect.Type) rPackerFnc { + lp := *newRList(rtype) + if rtype.Elem().Kind() != reflect.Uint8 { + return lp.pack + } + if rtype.Kind() == reflect.Slice { + return lp.packBinarySlice + } + return lp.packBinary +} + + + + + + +func newRList(rtype reflect.Type) *rList { + return &rList{ packFn: rTypePacker(rtype.Elem()) }} + + + +func (p rList) packBinary (s *packs.State, v reflect.Value, f packs.Flags) { + if f.Binary() { + packBinary(s, v.Interface().([]byte), f) + return + } + p.pack(s,v,f) +} + + +func (p rList) packBinarySlice (s *packs.State, v reflect.Value, f packs.Flags) { + if f.Binary() { + packBinary(s, v.Interface().([]byte), f) + return + } + p.packSlice(s,v,f) +} + + + + +func (p rList) packSlice(s *packs.State, v reflect.Value, f packs.Flags) { + if v.IsNil() { + s.W(g.nullValue) + return + } + + if s.Level > maxCyclesAfter { + cp := struct { + p interface{} + l int + }{ + p: v.UnsafePointer(), + l: v.Len(), + } + if fn,ok := s.CheckCycle(cp); ok { + defer fn() + } else { + s.SetError(packs.G.ErrRedundantPack) + return + } + } + + p.pack(s,v,f) +} + + + +func (p rList) pack (s *packs.State, v reflect.Value, f packs.Flags) { + if v.IsNil() { + s.W(g.nullValue) + return + } + + if v.Len() == 0 { + s.Write2Byte('[',']') + return + } + + s.Open('[') + for i:=0; i 0 { + s.WriteByte(',') + } + p.packFn(s,v.Index(i),f) + if s.Error != nil { + return + } + } + s.Close(']') +} + + + diff --git a/core/packs/pjson/rpacker_map.go b/core/packs/pjson/rpacker_map.go new file mode 100644 index 0000000..48b6357 --- /dev/null +++ b/core/packs/pjson/rpacker_map.go @@ -0,0 +1,111 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_map.go +// Created by DEV +// Modified 05/02/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 ( + "packs" + "reflect" + "sort" +) + +type ( + + rMap struct { + keyFn rMapEntryFnc + packFn rPackerFnc + } +) + + + +func rMapPacker (rtype reflect.Type) rPackerFnc { + return (*newRMap(rtype)).pack +} + + +func newRMap(rtype reflect.Type) *rMap { + return &rMap{ + packFn: rTypePacker (rtype.Elem()), + keyFn : stringifyRKey(rtype.Key()), + } +} + + +func (p *rMap) pack (s *packs.State, v reflect.Value, f packs.Flags) { + if p.keyFn == nil { + s.SetError(packs.G.ErrInvalidKey) + return + } + + if v.IsNil() { + s.W(g.nullValue) + return + } + if v.Len() == 0 { + s.Write2Byte('{','}') + return + } + + if s.Level > maxCyclesAfter { + if fn,ok := s.CheckCycle(v.UnsafePointer()); ok { + defer fn() + } else { + s.SetError(packs.G.ErrRedundantPack) + return + } + } + + mi := v.MapRange() + ls := make(rMapEntryList,v.Len()) + + for i:=0; mi.Next(); i++ { + ls[i] = rMapEntry{ + v: mi.Value(), + } + if er := p.keyFn(&ls[i], mi.Key()); er != nil { + s.SetError(er) + return + } + } + + sort.Sort(ls) + + s.Open ('{') + for i:=0; i0 { + s.WriteByte(',') + } + packString(s,ls[i].k,ls[i].f) + if s.Error != nil { + return + } + s.WriteByte(':') + p.packFn(s,ls[i].v,0) + if s.Error != nil { + return + } + } + s.Close('}') +} + diff --git a/core/packs/pjson/rpacker_map_entry.go b/core/packs/pjson/rpacker_map_entry.go new file mode 100644 index 0000000..807096f --- /dev/null +++ b/core/packs/pjson/rpacker_map_entry.go @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_map_entry.go +// Created by DEV +// Modified 05/02/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 ( + "packs" + "reflect" +) + +type ( + + + rMapEntry struct { + f packs.Flags // flags + v reflect.Value // value + k string // Key + } + + rMapEntryFnc func(entry *rMapEntry, rkey reflect.Value) error + + rMapEntryList []rMapEntry + +) + + + + + +func (e rMapEntryList) Len() int { + return len(e) +} + +func (e rMapEntryList) Less(i, j int) bool { + return e[i].k < e[j].k +} + +func (e rMapEntryList) Swap(i, j int) { + e[i], e[j] = e[j], e[i] +} + + + + + diff --git a/core/packs/pjson/rpacker_object.go b/core/packs/pjson/rpacker_object.go new file mode 100644 index 0000000..2409ddb --- /dev/null +++ b/core/packs/pjson/rpacker_object.go @@ -0,0 +1,280 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_object.go +// Created by DEV +// Modified 07/02/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 ( + "bins/bfers" + "packs" + "reflect" + "sort" +) + +type ( + + rObject struct { + fields rFieldList + nameIndex map[string]int + } + + +) + + +func rObjectPacker (rtype reflect.Type) rPackerFnc { + op,ok := g.fieldsCache.Load(rtype) + if !ok { + op,_ = g.fieldsCache.LoadOrStore(rtype,*newRObject(rtype)) + } + return func(s *packs.State, value reflect.Value, flags packs.Flags) { + op.(rObject).pack(s,value,flags) + } + //return (op.(rObject)).pack +} + + +func newRObject(rtype reflect.Type) *rObject { + cur := rFieldList{} + nxt := rFieldList{{ rtype: rtype}} + + var fls rFieldList + var cnt, nxCnt map[reflect.Type]int + vis := map[reflect.Type]bool{} + nms := bfers.NewBuffer() + + for len(nxt) > 0 { + cur,nxt = nxt,cur[:0] + + for _,f := range cur { + if vis[f.rtype] { + continue + } + vis[f.rtype]=true + + for i:=0; i 1 { + fls = append(fls,fls[len(fls)-1]) + } + continue + } + + nxCnt[ft]++ + if nxCnt[ft] == 1 { + nxt = append(nxt,rObjectField{ name: ft.Name(), index: index, rtype: ft}) + } + + } + } + + } + + sort.Slice(fls,func(i,j int) bool { + ls := fls + if ls[i].name != ls[j].name { + return ls[i].name < ls[j].name + } + if len(ls[i].index) != len(ls[j].index) { + return len(ls[i].index) < len(ls[j].index) + } + if ls[i].isTagged != ls[j].isTagged { + return ls[i].isTagged + } + return rFieldIndexList(ls).Less(i, j) + }) + + out := fls[:0] + for ad,i :=0,0; i< len(fls); i += ad { + fi := fls[i] + nm := fi.name + for ad=1; i+ad 1 && len(l[0].index) == len(l[1].index) && l[0].isTagged == l[1].isTagged { + return rObjectField{},false + } + return l[0],true +} + + + +func (x rFieldIndexList) Len() int { return len(x) } + +func (x rFieldIndexList) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x rFieldIndexList) Less(i, j int) bool { + for k, xik := range x[i].index { + if k >= len(x[j].index) { + return false + } + if xik != x[j].index[k] { + return xik < x[j].index[k] + } + } + return len(x[i].index) < len(x[j].index) +} + + + diff --git a/core/packs/pjson/rpacker_pointer.go b/core/packs/pjson/rpacker_pointer.go new file mode 100644 index 0000000..a47693b --- /dev/null +++ b/core/packs/pjson/rpacker_pointer.go @@ -0,0 +1,64 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_pointer.go +// Created by DEV +// Modified 09/02/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 ( + "packs" + "reflect" +) + +type ( + + rPointer struct { + elemPackFn rPackerFnc + } + +) + +func rPointerPacker (rtype reflect.Type) rPackerFnc { + return (*newRPointer(rtype)).pack +} + + +func newRPointer (rtype reflect.Type) *rPointer { + return &rPointer { elemPackFn: rTypePacker(rtype.Elem()) } +} + + +func (p rPointer) pack (s *packs.State, v reflect.Value, f packs.Flags) { + if v.IsNil() { + s.W(g.nullValue) + return + } + s.Level++ + if s.Level > maxCyclesAfter { + if fn,ok := s.CheckCycle(v.Interface()); ok { + defer fn() + } else { + return + } + } + p.elemPackFn(s,v.Elem(),f) + s.Level-- +} diff --git a/core/packs/pjson/rpacker_value.go b/core/packs/pjson/rpacker_value.go new file mode 100644 index 0000000..599da0a --- /dev/null +++ b/core/packs/pjson/rpacker_value.go @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rpacker_value.go +// Created by DEV +// Modified 13/02/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 ( + "packs" + "reflect" +) + +func rValuePacker (rvalue reflect.Value) rPackerFnc { + if !rvalue.IsValid() { + return invalidValuePacker + } + return rTypePacker(rvalue.Type()) +} + + +func invalidValuePacker(state *packs.State, _ reflect.Value, _ packs.Flags) { + state.SetError(packs.G.ErrInvalidValue) +} \ No newline at end of file diff --git a/core/packs/value_packer.go b/core/packs/value_packer.go new file mode 100644 index 0000000..41b6bd1 --- /dev/null +++ b/core/packs/value_packer.go @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name value_packer.go +// Created by DEV +// Modified 05/02/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 packs + +import "time" + +type ( + + ValuePacker interface { + + PackAny (value any, flags Flags) + + PackRaw (value []byte, flags Flags) + PackBinary (value []byte, flags Flags) + PackString (value string, flags Flags) + + PackBool (value bool, flags Flags) + + PackInt8 (value int8, flags Flags) + PackInt16 (value int16, flags Flags) + PackInt32 (value int32, flags Flags) + PackInt64 (value int64, flags Flags) + + PackUInt8 (value uint8 , flags Flags) + PackUInt16 (value uint16, flags Flags) + PackUInt32 (value uint32, flags Flags) + PackUInt64 (value uint64, flags Flags) + + PackFloat32 (value float32, flags Flags) + PackFloat64 (value float64, flags Flags) + + PackDate (value time.Time, flags Flags) + + PackList (flags Flags, builder func(ListPackBuilder, Flags)) + PackMap (flags Flags, builder func(MapPackBuilder, Flags)) + PackObject(flags Flags, builder func(ObjectPackBuilder,Flags)) + + } +) + + + + + diff --git a/core/rets/go.mod b/core/rets/go.mod deleted file mode 100644 index 2805316..0000000 --- a/core/rets/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module rets - -go 1.22 diff --git a/core/rets/bytes_result.go b/core/rsts/bytes.go similarity index 93% rename from core/rets/bytes_result.go rename to core/rsts/bytes.go index 875c039..a60a155 100644 --- a/core/rets/bytes_result.go +++ b/core/rsts/bytes.go @@ -21,12 +21,12 @@ // limitations under the License. // ------------------------------------------------------------------------ -package rets +package rsts type ( - BytesResult interface { + Bytes interface { Result Value() []byte // GResult implementation } @@ -47,7 +47,7 @@ func TupleBytesSuccess(bytes []byte) ([]byte, error) { func TupleBytesError(err error) ([]byte, error) { return nil, err } -// BytesSuccess -> BytesResult Implementation +// BytesSuccess -> Bytes Implementation func MakeBytesSuccess(success []byte) BytesSuccess { return success } @@ -66,7 +66,7 @@ func (s BytesSuccess) Success() any { -// BytesError -> BytesResult Implementation +// BytesError -> Bytes Implementation func MakeBytesError(cause error) BytesError { return BytesError{cause} } diff --git a/core/rets/g_result.go b/core/rsts/g_result.go similarity index 99% rename from core/rets/g_result.go rename to core/rsts/g_result.go index 3f88171..70db8b6 100644 --- a/core/rets/g_result.go +++ b/core/rsts/g_result.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package rets +package rsts type ( diff --git a/core/rsts/go.mod b/core/rsts/go.mod new file mode 100644 index 0000000..fa945a1 --- /dev/null +++ b/core/rsts/go.mod @@ -0,0 +1,3 @@ +module rsts + +go 1.22 diff --git a/core/rets/int_result.go b/core/rsts/int.go similarity index 98% rename from core/rets/int_result.go rename to core/rsts/int.go index eb84c42..5249b8d 100644 --- a/core/rets/int_result.go +++ b/core/rsts/int.go @@ -21,11 +21,11 @@ // limitations under the License. // ------------------------------------------------------------------------ -package rets +package rsts type ( - IntResult interface { + Int interface { Result Value() int // GResult implementation } diff --git a/core/rets/result.go b/core/rsts/result.go similarity index 99% rename from core/rets/result.go rename to core/rsts/result.go index e6f3d15..5d6605d 100644 --- a/core/rets/result.go +++ b/core/rsts/result.go @@ -21,7 +21,7 @@ // limitations under the License. // ------------------------------------------------------------------------ -package rets +package rsts type ( diff --git a/core/rets/string_result.go b/core/rsts/string.go similarity index 97% rename from core/rets/string_result.go rename to core/rsts/string.go index 3f3151a..881dd8e 100644 --- a/core/rets/string_result.go +++ b/core/rsts/string.go @@ -21,11 +21,11 @@ // limitations under the License. // ------------------------------------------------------------------------ -package rets +package rsts type ( - StringResult interface { + String interface { Result Value() string // GResult implementation } diff --git a/core/timers/active.go b/core/timers/active.go index ff471e8..909a28a 100644 --- a/core/timers/active.go +++ b/core/timers/active.go @@ -23,28 +23,30 @@ package timers +import "errs" + var ( G = struct { - ErrExpired errs.ErrCode - ErrTimeout errs.ErrCode - ErrIntervalInvalid errs.ErrCode - ErrNotStarted errs.ErrCode - ErrNotPaused errs.ErrCode - ErrAlreadyStarted errs.ErrCode - ErrTransitionInvalid errs.ErrCode - ErrTimerTaskInvalid errs.ErrCode + ErrExpired Err + ErrTimeout Err + ErrIntervalInvalid Err + ErrNotStarted Err + ErrNotPaused Err + ErrAlreadyStarted Err + ErrTransitionInvalid Err + ErrTimerTaskInvalid Err } { - ErrExpired: errs.ErrCode("expired"), - ErrTimeout: errs.ErrCode("timeout"), - ErrIntervalInvalid: errs.ErrCode("interval_invalid"), - ErrNotStarted: errs.ErrCode("not_started"), - ErrNotPaused: errs.ErrCode("not_paused"), - ErrAlreadyStarted: errs.ErrCode("already_started"), - ErrTransitionInvalid:errs.ErrCode("transition_invalid"), - ErrTimerTaskInvalid: errs.ErrCode("timer_task_invalid"), + ErrExpired: Err{ errs.ErrCode("expired")}, + ErrTimeout: Err{ errs.ErrCode("timeout")}, + ErrIntervalInvalid: Err{ errs.ErrCode("interval_invalid")}, + ErrNotStarted: Err{ errs.ErrCode("not_started")}, + ErrNotPaused: Err{ errs.ErrCode("not_paused")}, + ErrAlreadyStarted: Err{ errs.ErrCode("already_started")}, + ErrTransitionInvalid: Err{ errs.ErrCode("transition_invalid")}, + ErrTimerTaskInvalid: Err{ errs.ErrCode("timer_task_invalid")}, } diff --git a/core/timers/err.go b/core/timers/err.go new file mode 100644 index 0000000..35a9957 --- /dev/null +++ b/core/timers/err.go @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err_timer.go +// Created by DEV +// Modified 20/04/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 timers + +import "errs" + +type ( + + Err struct { errs.ErrCode } + +) \ No newline at end of file diff --git a/core/times/active.go b/core/times/active.go new file mode 100644 index 0000000..6b4a364 --- /dev/null +++ b/core/times/active.go @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 21/02/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 times + +import "errs" + +const( + + secondsDay = 24 * 60 * 60 + +) + + +var ( + + G = struct { + + ErrInvalidDateRange Err + }{ + + ErrInvalidDateRange : Err{ errs.ErrCode ("invalid-date-range")}, + } + +) + + + + +func IsYearLeap (year int) bool { + return year%4 == 0 && (year%100 != 0 || year%400 == 0) } + + +func DaysInYear (year int) int { + if IsYearLeap(year) { + return 366 } + return 365 +} + + +func DaysIn (year, month int) int { + if month <= 0 || month > 12 { + return 0 } + d := [12]int{ 31,28,31,30,31,30,31,30,31,30,31 } + if month == 2 && IsYearLeap(year) { + return 29 } + return d[month] +} + + +func DayOfWeek (year, month, day int) int { + if month < 3 { + month += 12 + year-- + } + J := year / 100 + K := year % 100 + h := (day + (13*(month+1))/5 + K + K/4 + J/4 + 5*J) % 7 + if h <= 1 { + return h+6 + } + return h-1 +} diff --git a/core/times/bdates/active.go b/core/times/bdates/active.go new file mode 100644 index 0000000..d4fbf23 --- /dev/null +++ b/core/times/bdates/active.go @@ -0,0 +1,55 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name gogo.go +// Created by DEV +// Modified 21/02/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 bdates + +import "errs" + +const( + + minBYear int = 1900 + maxBYear int = 2155 +) + +var ( + + + G = struct { + ErrInvalidDay Err + ErrInvalidMonth Err + ErrInvalidYear Err + }{ + ErrInvalidDay : Err{errs.ErrCode("invalid-day")}, + ErrInvalidMonth : Err{errs.ErrCode("invalid-month")}, + ErrInvalidYear : Err{errs.ErrCode("invalid-year")}, + } +) + + +func checkDayNumber (day int) bool { + return day >=1 && day <=7 } + + +func checkMonthNumber(month int) bool { + return month >=1 && month <=12 } + diff --git a/core/times/bdates/bmonth.go b/core/times/bdates/bmonth.go new file mode 100644 index 0000000..2335813 --- /dev/null +++ b/core/times/bdates/bmonth.go @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bmonth.go +// Created by DEV +// Modified 21/02/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 bdates + + + +type ( + + BMonth uint32 +) + + + diff --git a/core/times/bdates/bweek.go b/core/times/bdates/bweek.go new file mode 100644 index 0000000..cfd1690 --- /dev/null +++ b/core/times/bdates/bweek.go @@ -0,0 +1,125 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name bweek.go +// Created by DEV +// Modified 21/02/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 bdates + +import "math/bits" + +const( + + BWeekDaysMon BWeekDays = 1 << iota + BWeekDaysTue + BWeekDaysWed + BWeekDaysThu + BWeekDaysFri + BWeekDaysSat + BWeekDaysSun + + _BWeekFlag + + BWeekDaysAll = 0x1111111 + + +) + +type ( + + // BWeekDays + // Type: uint8 + // Desc: Representa una lista de los dias de la semana + // a través de un byte + BWeekDays uint8 + +) + + +func (w BWeekDays) GetFlag() bool { + return w&_BWeekFlag==_BWeekFlag } + + +func (w BWeekDays) SetFlag(val bool) BWeekDays { + if val { + return w|_BWeekFlag + } + return w&^_BWeekFlag +} + + + + +func (w BWeekDays) SetDay (num int, val bool) BWeekDays { + if num < 0 || num > 7 { + return w + } + if val { + w |= 1 << num-1 + } else { + w &^= 1 << num-1 + } + return w +} + + +func (w BWeekDays) GetDay (num int) bool { + if num < 0 || num > 7 { + return false + } + c := BWeekDays(1 << num-1) + return (w&c)==c +} + + +func (w BWeekDays) Invert () BWeekDays { + return ^w } + + +func (w BWeekDays) Count () int { + return bits.OnesCount8(uint8(w)) } + + +func (w BWeekDays) List () []int { + c := BWeekDays(1) + r := make([]int,0,7) + for i:=1; i<=7; i++ { + if c&w == c { + r = append(r,i) + } + c <<=1 + } + return r +} + + +func (w BWeekDays) ToSlice () []bool { + c := BWeekDays(1) + r := make([]bool,7) + for i:=0; i<7; i++ { + r[i]=c&w == c + c <<=1 + } + return r +} + + + +func (w BWeekDays) Common (dst BWeekDays) BWeekDays { return w & dst } diff --git a/core/times/bdates/byear.go b/core/times/bdates/byear.go new file mode 100644 index 0000000..7cab073 --- /dev/null +++ b/core/times/bdates/byear.go @@ -0,0 +1,128 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name byear.go +// Created by DEV +// Modified 21/02/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 bdates + +import "times" + +type ( + + BYear struct { + atts BYearAtt + first byte + year byte + months [12]BMonth + } + + +) + + + +func NewBYear (year int) *BYear { + if year < minBYear || year > maxBYear { + panic(G.ErrInvalidYear) + } + at := BYearAtt(BYearAttSet) + if times.IsYearLeap(year) { + at|=BYearAttLeap + } + return &BYear { + atts : at, + first: byte(times.DayOfWeek(year,1,1)), + year : byte(year-1900), + } +} + + +func (y *BYear) Atts () BYearAtt { + return y.atts } + +func (y *BYear) First () int { + return int(y.first) } + +func (y *BYear) Year () int { + return minBYear + int(y.year) } + + +func (y *BYear) Clear (month ...int) { + if len(month) == 0 { + for i := 0; i < 12; i++ { + y.months[i] = 0 + } + return + } + for _,i := range month { + if !checkMonthNumber(i){ + panic(G.ErrInvalidMonth) + } + y.months[i]=0 + } +} + + +func (y *BYear) GetDay (month, day int) bool { + if !checkMonthNumber(month) { + panic(G.ErrInvalidMonth ) + } + if day < 1 || day > y.daysInMonth(month) { + panic(G.ErrInvalidDay) + } + return (uint32(1 << day) & uint32(y.months[month])) != 0 +} + +func (y *BYear) SetDay (month, day int, active bool) { + if !checkMonthNumber(month) { + panic(G.ErrInvalidMonth ) + } + if day < 1 || day > y.daysInMonth(month) { + panic(G.ErrInvalidDay) + } + month-=1 + if active { + y.months[month] = y.months[month] | BMonth(1 << day) + return + } + y.months[month] = y.months[month] &^ BMonth(1 << day) +} + + + +func (y *BYear) GetMonth (month int) BMonth { + if !checkMonthNumber(month) { + panic(G.ErrInvalidMonth) + } + return y.months[month-1] +} + + + + + +func (y BYear) daysInMonth (month int) int { + d := [12]int{ 31,28,31,30,31,30,31,30,31,30,31 } + if month == 2 && y.Atts().IsLeap() { + return 29 + } + return d[month-1] +} diff --git a/core/times/bdates/byear_att.go b/core/times/bdates/byear_att.go new file mode 100644 index 0000000..a02ea4c --- /dev/null +++ b/core/times/bdates/byear_att.go @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name byear_att.go +// Created by DEV +// Modified 21/02/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 bdates + + +const( + + BYearAttSet BYearAtt = iota << 1 + BYearAttLeap + +) + + +type BYearAtt byte + + +func (a BYearAtt) IsSet () bool { + return a&BYearAttSet != 0 } + + +func (a BYearAtt) IsLeap () bool { + return a&BYearAttLeap != 0 } + + + + + + + + diff --git a/core/times/bdates/err.go b/core/times/bdates/err.go new file mode 100644 index 0000000..b5a511a --- /dev/null +++ b/core/times/bdates/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err_bdates.go +// Created by DEV +// Modified 20/04/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 bdates + +import "errs" + +type ( + + Err struct { errs.ErrCode } +) + + diff --git a/core/times/date_days.go b/core/times/date_days.go new file mode 100644 index 0000000..70e1931 --- /dev/null +++ b/core/times/date_days.go @@ -0,0 +1,102 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name days.go +// Created by DEV +// Modified 21/02/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 times + +import "time" + + +type ( + + DateDays int32 + +) + + + + +func (d DateDays) AddDate(years, months, days int) DateDays { + return TimeToDays(d.ToTime().AddDate(years,months,days)) } + + +func (d DateDays) ToTime() time.Time { + return DaysToTime(d) } + +func (d DateDays) Before (days DateDays) bool { + return d < days } + +func (d DateDays) After (days DateDays) bool { + return d > days } + +func (d DateDays) Compare(days DateDays) int { + if d < days { + return -1 } + if d == days { + return 0 } + return 1 +} + +func (d DateDays) Min (days DateDays) DateDays { + if d > days { + return days + } + return d +} + +func (d DateDays) Max (days DateDays) DateDays { + if d < days { + return days + } + return d +} + + + + + + +func TimeToDays (time time.Time) DateDays { + _,x := time.Zone() + s := time.Unix() + int64(x) + if s >= 0 { + return DateDays(s/ secondsDay) } + return -DateDays((secondsDay -1 -s)/ secondsDay) +} + + +func DaysToTime(days DateDays) time.Time { + return time.Unix(int64(days) *secondsDay,0).UTC() } + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/times/date_days_range.go b/core/times/date_days_range.go new file mode 100644 index 0000000..d9a40c3 --- /dev/null +++ b/core/times/date_days_range.go @@ -0,0 +1,94 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name date_days_range.go +// Created by DEV +// Modified 21/02/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 times + +type ( + + DateDaysRange struct { + Start DateDays + End DateDays + } + + + DateDaysRangeFnc func(daysRange *DateDaysRange) +) + +func NewDateRange (options ...DateDaysRangeFnc) *DateDaysRange { + dr := &DateDaysRange{} + for _,o := range options { + o(dr) + } + return dr +} + + + + + +func (r DateDaysRange) IsZero () bool { + return r.End-r.Start <= 0 } + + +func (r DateDaysRange) Size () DateDays { + return DateDays(r.End -r.Start) } + + +func (r DateDaysRange) Contains (days DateDays) bool { + if r.IsZero() { + return false } + return r.Start < days && r.End > days +} + + +func (r DateDaysRange) ContainsRange (drange DateDaysRange) bool { + if r.IsZero() { + return false } + return r.Start > drange.Start && r.End < drange.End +} + + +func (r DateDaysRange) IsRangeOverlap (drange DateDaysRange) bool { + if r.IsZero() { + return false } + if r.Start == drange.Start || r.Start == drange.End || r.End == drange.End { + return true } + if r.Start > drange.Start { + return drange.End < r.End + } + return r.End > drange.Start +} + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/times/duration_formatter.go b/core/times/duration_formatter.go new file mode 100644 index 0000000..d7b059f --- /dev/null +++ b/core/times/duration_formatter.go @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rkey.go +// Created by DEV +// Modified 05/02/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 times + +import ( + "strconv" + "time" +) + +type ( + + + DurationFormatter interface { + + FormatDuration (dur time.Duration, dst []byte) []byte + } + + + FormatDurationFnc func (dur time.Duration, dst []byte) []byte + +) + + +func (f FormatDurationFnc) FormatDuration (dur time.Duration, dst []byte) []byte { + return f(dur,dst) } + + +func WrapDurationFormatterQuoted (dfm DurationFormatter, qte byte) DurationFormatter { + return FormatDurationFnc(func(tme time.Duration, dst []byte) []byte { + dst = append(dst, qte) + dst = dfm.FormatDuration(tme, dst) + return append(dst, qte) + }) +} + + +func DurationMillis (dur time.Duration, dst []byte) []byte { + return strconv.AppendFloat(dst, float64(dur)/float64(time.Millisecond), 'f', -1, 64) } + + + +func DurationNanos(dur time.Duration, dst []byte) []byte { + return strconv.AppendInt(dst, int64(dur), 10) } + + + +func DurationSecs(dur time.Duration, dst []byte) []byte { + return strconv.AppendFloat(dst, float64(dur)/float64(time.Second), 'f', -1, 64) } + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/times/err.go b/core/times/err.go new file mode 100644 index 0000000..76537f4 --- /dev/null +++ b/core/times/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err.go +// Created by DEV +// Modified 20/04/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 times + +import "errs" + +type ( + + Err struct { errs.ErrCode } +) + + diff --git a/core/times/go.mod b/core/times/go.mod new file mode 100644 index 0000000..7681852 --- /dev/null +++ b/core/times/go.mod @@ -0,0 +1,5 @@ +module times + + + +go 1.20 \ No newline at end of file diff --git a/core/times/time_formatter.go b/core/times/time_formatter.go new file mode 100644 index 0000000..d8f86ed --- /dev/null +++ b/core/times/time_formatter.go @@ -0,0 +1,145 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name rkey.go +// Created by DEV +// Modified 05/02/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 times + +import ( + "strconv" + "time" +) + +type ( + + + TimeFormatter interface { + + FormatTime (tme time.Time, dst []byte) []byte + } + + + FormatTimeFnc func (tme time.Time, dst []byte) []byte + +) + + +func (f FormatTimeFnc) FormatTime (tme time.Time, dst []byte) []byte { + return f(tme,dst) } + + + + +func WrapTimeFormatterQuoted (tmf TimeFormatter, qte byte) TimeFormatter { + return FormatTimeFnc(func(tme time.Time, dst []byte) []byte { + dst = append(dst, qte) + dst = tmf.FormatTime(tme, dst) + return append(dst, qte) + }) +} + + +func TimeRFC3339Nano(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC3339Nano) } + + +func TimeANSIC(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.ANSIC) } + + +func TimeUnixDate(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.UnixDate) } + + +func TimeRubyDate(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RubyDate) } + + +func TimeRFC822(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC822) } + + +func TimeRFC822Z(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC822Z) } + + +func TimeRFC850(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC850) } + + +func TimeRFC1123(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC1123) } + + +func TimeRFC1123Z(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC1123Z) } + + +func TimeRFC3339(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.RFC3339) } + + +func TimeKitchen(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.Kitchen) } + + +func TimeISO8601(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, "2006-01-02T15:04:05.000Z0700") } + + + +func TimeEpoch(tme time.Time, dst []byte) []byte { + return strconv.AppendFloat(dst, float64(tme.UnixNano())/float64(time.Second), 'f', -1, 64) } + + +func TimeEpochMillis(tme time.Time, dst []byte) []byte { + return strconv.AppendFloat(dst, float64(tme.UnixNano())/float64(time.Millisecond), 'f', -1, 64) } + + +func TimeStamp(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.Stamp) } + + +func TimeStampMilli(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.StampMilli) } + + +func TimeStampMicro(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.StampMicro) } + + +func TimeStampNano(tme time.Time, dst []byte) []byte { + return tme.AppendFormat(dst, time.StampNano) } + + +/* + :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + I HAVE NO DESIRE TO WALK ON WATER," SAID SIDDHARTA. + "LET THE OLD SHRAMANAS SATISFY THEMSELVES WITH SUCH SKILLS. + + SIDDHARTA + - HERMANN HESSE - + + ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +*/ diff --git a/core/vals/err.go b/core/vals/err.go new file mode 100644 index 0000000..747ebb3 --- /dev/null +++ b/core/vals/err.go @@ -0,0 +1,33 @@ +// ------------------------------------------------------------------------ +// Project active2 +// Active Thing (activething.com) git.activething.com/go +// +// File name err.go +// Created by DEV +// Modified 20/04/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 vals + +import "errs" + + + + +type Err struct { errs.ErrCode } + + diff --git a/go.work b/go.work index 2d925b0..feee17d 100644 --- a/go.work +++ b/go.work @@ -3,15 +3,19 @@ go 1.22 use ( ./core/errs - ./core/rets + ./core/rsts + ./core/crypts ./core/vals - ./core/bins + ./core/btes + ./core/bits ./core/ansi ./core/opts ./core/syncs + ./core/times ./core/timers ./core/ctxs ./core/atypes + ./core/packs ./app