parent
4ef5088582
commit
8ff022c69a
@ -1,40 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name bin_encoder.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 js
|
||||
|
||||
|
||||
|
||||
type (
|
||||
|
||||
binEncoder interface {
|
||||
EncodedLen (size int) int
|
||||
Encode(dst, src []byte)
|
||||
}
|
||||
|
||||
binEncoderWriter interface {
|
||||
Write ([]byte) (int,error)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 js
|
||||
|
||||
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
|
||||
}
|
||||
@ -1,188 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 js
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
FlagOmitEmpty Flags = 1 << iota
|
||||
FlagQuote
|
||||
FlagScapeHTML
|
||||
|
||||
FlagBinary64 Flags = 0b0000100000000000
|
||||
FlagBinary32 Flags = 0b0000010000000000
|
||||
|
||||
FlagDateRFC822 Flags = 0b0001000000000000
|
||||
FlagDateUnix Flags = 0b0010000000000000
|
||||
FlagDateANSIC Flags = 0b0100000000000000
|
||||
FlagDateRFC850 Flags = 0b1000000000000000
|
||||
|
||||
binMask = 0b0000110000000000
|
||||
dateMask = 0b1111000000000000
|
||||
flagMaskBin Flags = 0b1111001111111111
|
||||
flagMaskDate Flags = 0b0000111111111111
|
||||
|
||||
)
|
||||
|
||||
|
||||
type Flags uint16
|
||||
|
||||
|
||||
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) 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) SetWithName(flag string) Flags {
|
||||
switch strings.ToLower(flag) {
|
||||
case "o","omitempty": return f | FlagOmitEmpty
|
||||
case "q","quote" : return f | FlagQuote
|
||||
case "h","html" : return f | FlagScapeHTML
|
||||
|
||||
case "b64","bin64" : return (f & flagMaskBin) | FlagBinary64
|
||||
case "b32","bin32" : return (f & flagMaskBin) | FlagBinary32
|
||||
|
||||
// formatos de fechas
|
||||
case "unix" : return (f & flagMaskDate) | FlagDateUnix
|
||||
case "rfc822" : return (f & flagMaskDate) | FlagDateRFC822
|
||||
case "ansic" : return (f & flagMaskDate) | FlagDateANSIC
|
||||
case "rfc850" : return (f & flagMaskDate) | FlagDateRFC850
|
||||
case "rfc822z": return f & flagMaskDate
|
||||
|
||||
default: return f
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (f Flags) SetWithNames(flags ... string) Flags {
|
||||
nf := f
|
||||
for _,n := range flags {
|
||||
switch strings.ToLower(n) {
|
||||
case "o","omitempty": nf |= FlagOmitEmpty
|
||||
case "q","quote" : nf |= FlagQuote
|
||||
case "h","html" : nf |= FlagScapeHTML
|
||||
|
||||
case "b32","bin32" : nf = (nf & flagMaskBin) | FlagBinary32
|
||||
case "b64","bin64" : nf = (nf & flagMaskBin) | FlagBinary64
|
||||
|
||||
// formatos de fechas
|
||||
case "unix" : nf = (nf & flagMaskDate) | FlagDateUnix
|
||||
case "rfc822" : nf = (nf & flagMaskDate) | FlagDateRFC822
|
||||
case "ansic" : nf = (nf & flagMaskDate) | FlagDateANSIC
|
||||
case "rfc850" : nf = (nf & flagMaskDate) | FlagDateRFC850
|
||||
case "rfc822z": nf &= flagMaskDate
|
||||
}
|
||||
}
|
||||
return nf
|
||||
}
|
||||
|
||||
func (f Flags) SetWithString (flags string) Flags {
|
||||
if len(flags) == 0 {
|
||||
return f
|
||||
}
|
||||
nf := f
|
||||
for flags != "" {
|
||||
var op string
|
||||
op,flags,_ = strings.Cut(flags,",")
|
||||
nf |= f.SetWithName(op)
|
||||
}
|
||||
return nf
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (f Flags) Names () string {
|
||||
var ls []string
|
||||
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&flagMaskBin != 0 {
|
||||
ls = append(ls,f.binName())
|
||||
}
|
||||
if f&dateMask != 0 {
|
||||
ls = append(ls,f.DateName())
|
||||
}
|
||||
if len(ls) > 0 {
|
||||
return strings.Join(ls,",")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (f Flags) binName () string {
|
||||
switch f & binMask {
|
||||
case FlagBinary64 : return "b64"
|
||||
case FlagBinary32 : return "b32"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
func (f Flags) DateName () string {
|
||||
switch f & dateMask {
|
||||
case FlagDateUnix : return "unix"
|
||||
case FlagDateRFC822: return "rfc822"
|
||||
case FlagDateANSIC : return "ansic"
|
||||
case FlagDateRFC850: return "rfc8550"
|
||||
default: return time.RFC822Z
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (f Flags) DateFormat () string {
|
||||
switch f & dateMask {
|
||||
case FlagDateUnix : return time.UnixDate
|
||||
case FlagDateRFC822: return time.RFC822
|
||||
case FlagDateANSIC : return time.ANSIC
|
||||
case FlagDateRFC850: return time.RFC850
|
||||
default: return time.RFC822Z
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,167 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// 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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
|
||||
const startDetectingCyclesAfter = 100
|
||||
|
||||
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
|
||||
|
||||
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 stringifyKey(buffer []byte, value any) []byte {
|
||||
if value == nil {
|
||||
return G.nullValue
|
||||
}
|
||||
|
||||
if st,is := value.(string); is {
|
||||
return append(buffer[:0],st...)
|
||||
}
|
||||
|
||||
if tm,is := value.(encoding.TextMarshaler); is {
|
||||
if bf,er := tm.MarshalText(); er == nil {
|
||||
return append(buffer[:0],bf...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
switch tp := value.(type) {
|
||||
case bool:
|
||||
if tp {
|
||||
return G.trueValue
|
||||
}
|
||||
return G.falseValue
|
||||
|
||||
case int : return strconv.AppendInt (buffer[:0],int64(tp), 10)
|
||||
case int8 : return strconv.AppendInt (buffer[:0],int64(tp), 10)
|
||||
case int16 : return strconv.AppendInt (buffer[:0],int64(tp), 10)
|
||||
case int32 : return strconv.AppendInt (buffer[:0],int64(tp), 10)
|
||||
case int64 : return strconv.AppendInt (buffer[:0],tp, 10)
|
||||
|
||||
case uint : return strconv.AppendUint(buffer[:0],uint64(tp), 10)
|
||||
case uint8 : return strconv.AppendUint(buffer[:0],uint64(tp), 10)
|
||||
case uint16 : return strconv.AppendUint(buffer[:0],uint64(tp), 10)
|
||||
case uint32 : return strconv.AppendUint(buffer[:0],uint64(tp), 10)
|
||||
case uint64 : return strconv.AppendUint(buffer[:0],tp, 10)
|
||||
|
||||
case float32: return stringifyFloat(buffer[:0],float64(tp),32)
|
||||
case float64: return stringifyFloat(buffer[:0],tp,64)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@ -1,349 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name value_packer.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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
|
||||
|
||||
func pack (state *packs.State, value any , flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
_,_ = state.Write(G.nullValue)
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
|
||||
case bool : packBool (state,v,flags)
|
||||
case string : packString(state,v,flags)
|
||||
|
||||
case uint : packUInt(state,uint64(v),flags)
|
||||
case uint8 : packUInt(state,uint64(v),flags)
|
||||
case uint16 : packUInt(state,uint64(v),flags)
|
||||
case uint32 : packUInt(state,uint64(v),flags)
|
||||
case uint64 : packUInt(state,v,flags)
|
||||
|
||||
case int : packInt(state,int64(v),flags)
|
||||
case int8 : packInt(state,int64(v),flags)
|
||||
case int16 : packInt(state,int64(v),flags)
|
||||
case int32 : packInt(state,int64(v),flags)
|
||||
case int64 : packInt(state,v,flags)
|
||||
|
||||
case float32: packFloat(state,float64(v),flags)
|
||||
case float64: packFloat(state,v,flags)
|
||||
|
||||
case time.Time : PackDate(state,v,flags)
|
||||
|
||||
case reflect.Value : RPacker(state,v.Elem(),0)
|
||||
|
||||
default:
|
||||
|
||||
/*
|
||||
if pb,is := value.(packs.Builder); is {
|
||||
e := pb.Build(pb)
|
||||
if e != nil {
|
||||
state.SetError(e)
|
||||
return
|
||||
}
|
||||
_, _ = state.Write(d)
|
||||
return
|
||||
}
|
||||
if ms,is := value.(json.Marshaler); is {
|
||||
d,e := ms.MarshalJSON()
|
||||
if state.SetError(e) {
|
||||
return
|
||||
}
|
||||
_,_ = state.Write(d)
|
||||
return
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(value)
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
packListReflected(rv)
|
||||
case reflect.Map:
|
||||
packMapReflected(rv)
|
||||
case reflect.Struct:
|
||||
packObjectReflected(rv)
|
||||
default:
|
||||
d,e := options.encoder.Encode(value)
|
||||
if e != nil {
|
||||
state.SetError(e)
|
||||
return
|
||||
}
|
||||
state.Write(d)
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func packString (state *packs.State, value string , flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
|
||||
if len(value) == 0 {
|
||||
state.Write2Byte('"','"')
|
||||
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 packBinary (state *packs.State, value []byte , f Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
_,_ = state.Write(G.nullValue)
|
||||
return
|
||||
}
|
||||
if len(value) == 0 {
|
||||
state.Write2Byte('"','"')
|
||||
return
|
||||
}
|
||||
state.WriteByte('"')
|
||||
|
||||
var ec binEncoder = base64.StdEncoding
|
||||
if f.Bin32() {
|
||||
ec = base32.StdEncoding
|
||||
}
|
||||
|
||||
ln := ec.EncodedLen(len(value))
|
||||
if ln <= len(state.Temp) {
|
||||
dst := state.Temp[:ln]
|
||||
ec.Encode(dst, value)
|
||||
_,_= state.Write(dst)
|
||||
} else if ln <= 1024 {
|
||||
dst := make([]byte, ln)
|
||||
ec.Encode(dst, value)
|
||||
_,_ = state.Write(dst)
|
||||
} else {
|
||||
var wc io.WriteCloser
|
||||
|
||||
if f.Bin32() {
|
||||
wc = base32.NewEncoder(base32.StdEncoding, state)
|
||||
} else if f.Bin64() {
|
||||
wc = base64.NewEncoder(base64.StdEncoding, state)
|
||||
} else {
|
||||
state.SetError(packs.G.ErrUnsupportedType)
|
||||
return
|
||||
}
|
||||
_,_ = wc.Write(value)
|
||||
state.SetError(wc.Close())
|
||||
return
|
||||
}
|
||||
state.WriteByte('"')
|
||||
}
|
||||
|
||||
|
||||
|
||||
func packBool (state *packs.State, value bool , flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
if value {
|
||||
state.W(G.trueValue)
|
||||
} else {
|
||||
state.W(G.falseValue)
|
||||
}
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
func packInt (state *packs.State, value int64 , flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
if value == 0 {
|
||||
state.WriteByte('0')
|
||||
} else {
|
||||
state.WriteIntStr(value, 10)
|
||||
}
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
func packUInt (state *packs.State, value uint64 , flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
if value == 0 {
|
||||
state.WriteByte('0')
|
||||
} else {
|
||||
state.WriteUIntStr(value, 10)
|
||||
}
|
||||
if flags.Quote() {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
func packFloat (state *packs.State, value float64, flags Flags) {
|
||||
packFloatString(state, value,64, flags.Quote())
|
||||
}
|
||||
|
||||
func packFloatString (state *packs.State, f float64, bits int, quote bool) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
|
||||
if math.IsInf(f, 0) || math.IsNaN(f) {
|
||||
state.SetError(packs.G.ErrInvalidValue)
|
||||
return
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
bf := state.Temp[:0]
|
||||
bf = strconv.AppendFloat(bf, f, fmt, -1, int(bits))
|
||||
if fmt == '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]
|
||||
}
|
||||
}
|
||||
|
||||
if quote {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
state.W(bf)
|
||||
if quote {
|
||||
state.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func PackDate (state *packs.State, value time.Time, flags Flags) {
|
||||
if state.Error != nil {
|
||||
panic(state.Error)
|
||||
}
|
||||
state.WriteByte('"')
|
||||
bf := state.Temp[:0]
|
||||
bf = value.AppendFormat(bf,flags.DateFormat())
|
||||
state.W(bf)
|
||||
state.WriteByte('"')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,142 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rkey.go
|
||||
// Created by DEV
|
||||
// Modified 04/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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"encoding"
|
||||
"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 = 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 = 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 = 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 = 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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name type_slice_packer.go
|
||||
// Created by DEV
|
||||
// Modified 30/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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
rList struct {
|
||||
valFn packerFn
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func (p rList) pack (s *packs.State, v reflect.Value, f Flags) {
|
||||
if v.IsNil() {
|
||||
_,_ = s.Write(G.nullValue)
|
||||
return
|
||||
}
|
||||
if v.Len() == 0 {
|
||||
s.Write2Byte('[',']')
|
||||
return
|
||||
}
|
||||
s.Open('[')
|
||||
for i:=0; i<v.Len(); i++ {
|
||||
if i > 0 {
|
||||
s.WriteByte(',')
|
||||
}
|
||||
p.valFn(s,v.Index(i),f)
|
||||
if s.Error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
s.Close(']')
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name key_val_packer.go
|
||||
// Created by DEV
|
||||
// Modified 03/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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
rMap struct {
|
||||
keyFn rMapEntryFnc
|
||||
valFn packerFn
|
||||
}
|
||||
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
func newRMap (rtype reflect.Type) *rMap {
|
||||
return &rMap{
|
||||
valFn : rTypePacker(rtype.Elem()),
|
||||
keyFn : stringifyRKey(rtype.Key()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (p *rMap) pack (s *packs.State, v reflect.Value, f 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 > startDetectingCyclesAfter {
|
||||
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; i<len(ls); i++ {
|
||||
if i>0 {
|
||||
s.WriteByte(',')
|
||||
}
|
||||
packString(s,ls[i].k,ls[i].f)
|
||||
if s.Error != nil {
|
||||
return
|
||||
}
|
||||
s.WriteByte(':')
|
||||
p.valFn(s,ls[i].v,0)
|
||||
if s.Error != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
s.Close('}')
|
||||
}
|
||||
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name key_entry.go
|
||||
// Created by DEV
|
||||
// Modified 02/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 js
|
||||
|
||||
import "reflect"
|
||||
|
||||
type (
|
||||
|
||||
|
||||
rMapEntry struct {
|
||||
f 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]
|
||||
}
|
||||
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name type_packer.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 js
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
packer interface {
|
||||
|
||||
}
|
||||
|
||||
packerFn func (state *packs.State, value reflect.Value, flags Flags)
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
func RPacker(state *packs.State, value any, flags Flags ) {
|
||||
v := reflect.ValueOf(value)
|
||||
t := v.Type()
|
||||
rTypePacker(t)(state,v,flags)
|
||||
}
|
||||
|
||||
|
||||
func rTypePacker(rtype reflect.Type) packerFn {
|
||||
if fn,ok := G.packersCache.Load(rtype); ok {
|
||||
return fn.(packerFn)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var fn packerFn
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
fi,ld := G.packersCache.LoadOrStore(rtype, packerFn(func (e *packs.State, v reflect.Value, f Flags) {
|
||||
wg.Wait()
|
||||
fn(e,v,f)
|
||||
}))
|
||||
if ld {
|
||||
return fi.(packerFn)
|
||||
}
|
||||
|
||||
fn = _rTypePacker(rtype)
|
||||
wg.Done()
|
||||
|
||||
G.packersCache.Store(rtype,fn)
|
||||
return fn
|
||||
}
|
||||
|
||||
|
||||
func _rTypePacker(t reflect.Type) packerFn {
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Bool : return func(s *packs.State, v reflect.Value, f Flags) { packBool (s,v.Bool (),f )}
|
||||
case reflect.String : return func(s *packs.State, v reflect.Value, f 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 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 Flags) { packUInt (s,v.Uint (),f )}
|
||||
case reflect.Float32: return func(s *packs.State, v reflect.Value, f Flags) { packFloatString(s,v.Float(),32, f.Quote()) }
|
||||
case reflect.Float64: return func(s *packs.State, v reflect.Value, f Flags) { packFloatString(s,v.Float(),64, f.Quote()) }
|
||||
|
||||
case reflect.Slice,
|
||||
reflect.Array :
|
||||
return (rList{ valFn: rTypePacker(t.Elem()) }).pack
|
||||
|
||||
case reflect.Map :
|
||||
return newRMap(t).pack
|
||||
}
|
||||
return unsupportedTypePacker
|
||||
}
|
||||
|
||||
|
||||
func unsupportedTypePacker(state *packs.State, _ reflect.Value, _ Flags) {
|
||||
state.SetError(packs.G.ErrUnsupportedType)
|
||||
}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
module activething.com/go/gogo/packs/reflects
|
||||
|
||||
go 1.20
|
||||
@ -1,56 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name gogo.go
|
||||
// Created by DEV
|
||||
// Modified 28/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 reflects
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
G = struct {
|
||||
|
||||
locker sync.Mutex
|
||||
cache map[reflect.Type]RStruct
|
||||
|
||||
}{
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func GetRTypePacker (rtype reflect.Type, packer packs.Packer) *RStruct {
|
||||
G.locker.Lock()
|
||||
if G.cache == nil {
|
||||
G.cache = make(map[reflect.Type]RStruct)
|
||||
}
|
||||
|
||||
G.locker.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name reflect_struct_field.go
|
||||
// Created by DEV
|
||||
// Modified 26/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 reflects
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/opts"
|
||||
"activething.com/go/gogo/core/slices"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
RField struct {
|
||||
RType reflect.Type
|
||||
RField reflect.StructField
|
||||
|
||||
Name string
|
||||
SName string // scaped name
|
||||
HName string // html name
|
||||
|
||||
BName []byte // name bytes
|
||||
Index []int
|
||||
|
||||
Tags map[string]slices.String
|
||||
Flags uint16
|
||||
|
||||
EqualFoldFn func(s, t []byte) bool
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
func NewRField (rfield reflect.StructField, options ...opts.OptionFnc[RField]) *RField {
|
||||
rf := &RField{
|
||||
RField: rfield,
|
||||
Tags : make(map[string]slices.String),
|
||||
}
|
||||
rf.parseTag("json",nil)
|
||||
return opts.Apply(rf,options...)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (f *RField) parseTag (tagKey string, onOptionFn func(*RField,int,string)) {
|
||||
if _,h := f.Tags[tagKey]; !h {
|
||||
t := f.RField.Tag.Get(tagKey)
|
||||
if len(t) > 0 {
|
||||
l := strings.Split(t,",")
|
||||
f.Tags[tagKey]= l
|
||||
if onOptionFn != nil {
|
||||
for i,o := range l {
|
||||
onOptionFn(f,i,o)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func parseTag (field reflect.StructField, tagKey string, onOptionFn func(int,string)) (slices.String,bool) {
|
||||
t := field.Tag.Get(tagKey)
|
||||
if len(t) > 0 {
|
||||
l := strings.Split(t,",")
|
||||
if onOptionFn != nil {
|
||||
for i,o := range l {
|
||||
onOptionFn(i,o)
|
||||
}
|
||||
}
|
||||
return l,true
|
||||
}
|
||||
return nil,true
|
||||
}
|
||||
|
||||
|
||||
func isValidTag(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
|
||||
case !unicode.IsLetter(c) && !unicode.IsDigit(c):
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rfield_tag.go
|
||||
// Created by DEV
|
||||
// Modified 27/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 reflects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
RFieldTag struct {
|
||||
Tag string
|
||||
parsed bool
|
||||
Name string
|
||||
Flags uint8
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
func NewRFieldTag (rfield reflect.StructField, tag string, onOption func(rf reflect.Type, position int, option string) uint8) *RFieldTag {
|
||||
f := &RFieldTag{
|
||||
Tag : rfield.Tag.Get(tag),
|
||||
}
|
||||
var ops string
|
||||
f.Name,ops,_ = strings.Cut(f.Tag,",")
|
||||
|
||||
if len(ops) == 0 {
|
||||
f.parsed = true
|
||||
} else if onOption != nil {
|
||||
f.parsed = true
|
||||
for pos:=0; ops != ""; pos++ {
|
||||
var name string
|
||||
name, ops, _ = strings.Cut(ops, ",")
|
||||
f.Flags = onOption(rfield.Type, pos,name)
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rfields.go
|
||||
// Created by DEV
|
||||
// Modified 27/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 reflects
|
||||
|
||||
|
||||
|
||||
type (
|
||||
|
||||
RFields []RField
|
||||
|
||||
)
|
||||
|
||||
/*
|
||||
func (f RFields) Dominant() (RField, bool) {
|
||||
// The Fields are sorted in increasing index-length order, then by presence of tag.
|
||||
// That means that the first RField is the dominant one. We need only check
|
||||
// for error cases: two Fields at top level, either both tagged or neither tagged.
|
||||
if len(f) > 1 && len(f[0].Index) == len(f[1].Index) && f[0].Tagged() == f[1].Tagged() {
|
||||
return RField{}, false
|
||||
}
|
||||
return f[0], true
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
func (f RFields) Len() int { return len(f) }
|
||||
|
||||
func (f RFields) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
||||
|
||||
func (f RFields) Less(i, j int) bool {
|
||||
for k, xik := range f[i].Index {
|
||||
if k >= len(f[j].Index) {
|
||||
return false
|
||||
}
|
||||
if xik != f[j].Index[k] {
|
||||
return xik < f[j].Index[k]
|
||||
}
|
||||
}
|
||||
return len(f[i].Index) < len(f[j].Index)
|
||||
}
|
||||
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rmap.go
|
||||
// Created by DEV
|
||||
// Modified 28/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 reflects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
|
||||
type (
|
||||
|
||||
RMap struct {
|
||||
KeyValues []RKeyValue
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewRMap (value reflect.Value, stringifyFn func(v reflect.Value) (string,error), scapeFn func(string)string) (*RMap,error) {
|
||||
ls := make([]RKeyValue,value.Len())
|
||||
mi := value.MapRange()
|
||||
|
||||
sf := scapeFn
|
||||
if sf == nil {
|
||||
sf = func(v string) string { return v }
|
||||
}
|
||||
|
||||
for i:=0; mi.Next(); i++ {
|
||||
k,e := NewRKeyValue(mi.Key(),mi.Value(), stringifyFn,sf)
|
||||
if e != nil {
|
||||
return nil,e
|
||||
}
|
||||
ls[i]=*k
|
||||
}
|
||||
|
||||
sort.Slice(ls,func(i,j int) bool { return ls[i].Key < ls[j].Key })
|
||||
|
||||
return &RMap {
|
||||
KeyValues: ls,
|
||||
},nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func ensureScapeFn (sfn func(string)string) func(string)string {
|
||||
if sfn == nil {
|
||||
return func(v string) string { return v }
|
||||
}
|
||||
return sfn
|
||||
}
|
||||
@ -1,87 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rmap.go
|
||||
// Created by DEV
|
||||
// Modified 28/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 reflects
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/packs"
|
||||
"encoding"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
RKeyValue struct {
|
||||
RKey reflect.Value
|
||||
RVal reflect.Value
|
||||
Key string
|
||||
}
|
||||
|
||||
|
||||
)
|
||||
|
||||
|
||||
func NewRKeyValue(key reflect.Value, value reflect.Value, stringifyFn func(v reflect.Value) (string,error), scapeFn func(string) string) (*RKeyValue,error) {
|
||||
kv := &RKeyValue{
|
||||
RKey : key,
|
||||
RVal : value,
|
||||
}
|
||||
if kv.RKey.Kind() == reflect.String {
|
||||
kv.Key = scapeFn(kv.RKey.String())
|
||||
return kv,nil
|
||||
}
|
||||
|
||||
if tm,hs := kv.RKey.Interface().(encoding.TextMarshaler); hs {
|
||||
if kv.RKey.Kind() == reflect.Pointer && kv.RKey.IsNil() {
|
||||
return nil,packs.G.ErrInvalidKey
|
||||
}
|
||||
b,e := tm.MarshalText()
|
||||
if e != nil {
|
||||
return nil,packs.G.ErrInvalidKey
|
||||
}
|
||||
kv.Key = string(b)
|
||||
return kv,nil
|
||||
}
|
||||
|
||||
if stringifyFn != nil {
|
||||
b,e := stringifyFn(kv.RKey)
|
||||
if e != nil {
|
||||
return nil,packs.G.ErrInvalidKey.WithCause(e)
|
||||
}
|
||||
kv.Key = scapeFn(b)
|
||||
return kv,nil
|
||||
}
|
||||
|
||||
switch key.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
kv.Key = strconv.FormatInt(kv.RKey.Int(), 10)
|
||||
return kv,nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
kv.Key= strconv.FormatUint(kv.RKey.Uint(), 10)
|
||||
return kv,nil
|
||||
}
|
||||
|
||||
return nil,packs.G.ErrInvalidKey
|
||||
|
||||
}
|
||||
@ -1,153 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rRFields_type.go
|
||||
// Created by DEV
|
||||
// Modified 26/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 reflects
|
||||
|
||||
type (
|
||||
|
||||
RStruct struct {
|
||||
Fields RFields
|
||||
NameIndex map[string]int
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
func NewRStruct (rtype reflect.Type) *RStruct {
|
||||
res := &RStruct{
|
||||
Fields : make(RFields,0,rtype.NumField()),
|
||||
NameIndex: make(map[string]int),
|
||||
}
|
||||
|
||||
cur := RFields{}
|
||||
nxt := RFields{{ RType: rtype }}
|
||||
|
||||
var (
|
||||
cnt,nxc map[reflect.Type]int
|
||||
vis map[reflect.Type]struct{}
|
||||
nms bytes.Buffer
|
||||
)
|
||||
|
||||
for len(nxt) > 0 {
|
||||
cur, nxt = nxt, cur[:0]
|
||||
cnt, nxc = nxc, map[reflect.Type]int{}
|
||||
|
||||
for _,f := range cur {
|
||||
if _,h := vis[f.RType]; h {
|
||||
continue
|
||||
}
|
||||
vis[f.RType]=struct{}{}
|
||||
|
||||
for i :=0; i<f.RType.NumField(); i++ {
|
||||
sf := f.RType.Field(i)
|
||||
if sf.Anonymous {
|
||||
st := sf.Type
|
||||
if st.Kind() == reflect.Pointer {
|
||||
st = st.Elem()
|
||||
}
|
||||
if !sf.IsExported() && st.Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
} else if !sf.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
nm := false
|
||||
tags,ok := parseTag(sf,"json",nil)
|
||||
if ok {
|
||||
if tags.Has("-") {
|
||||
continue
|
||||
}
|
||||
if isValidTag(tags[0]) {
|
||||
nm=true
|
||||
}
|
||||
}
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Pointer {
|
||||
ft=ft.Elem()
|
||||
}
|
||||
|
||||
|
||||
//qt := false
|
||||
//if tags.Has("string") {
|
||||
// switch ft.Kind() {
|
||||
// case reflect.Bool,
|
||||
// reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
|
||||
// reflect.Float32, reflect.Float64,
|
||||
// reflect.String:
|
||||
// qt = true
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
index := make([]int, len(f.Index)+1)
|
||||
copy(index, f.Index)
|
||||
index[len(f.Index)] = i
|
||||
|
||||
|
||||
|
||||
var name string
|
||||
if nm || sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
if nm {
|
||||
name = tags[0]
|
||||
} else {
|
||||
name = sf.Name
|
||||
}
|
||||
|
||||
res.Fields = append(res.Fields, RField{
|
||||
RField: sf,
|
||||
RType: ft,
|
||||
Name: name,
|
||||
BName: []byte(name),
|
||||
Tags: map[string]slices.String{"json": append(slices.String(nil), tags...)},
|
||||
})
|
||||
if cnt[f.RType] > 1 {
|
||||
res.Fields = append(res.Fields, res.Fields[len(res.Fields)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
nxc[ft]++
|
||||
if nxc[ft] == 1 {
|
||||
nxt = append(nxt, RField{
|
||||
RType: ft,
|
||||
Name: ft.Name(),
|
||||
Index: index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for i,f := range res.Fields {
|
||||
res.NameIndex[f.Name]=i
|
||||
}
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
Loading…
Reference in new issue