parent
1df755eba9
commit
858f700161
@ -0,0 +1,96 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name packs.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 main
|
||||
|
||||
import (
|
||||
"activething.com/go/gogo/core/errs"
|
||||
"activething.com/go/gogo/packs/pjson"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func packs_main () {
|
||||
|
||||
|
||||
pk := pjson.NewPacker()
|
||||
|
||||
/*
|
||||
slc2 := [][]int16 {{1,2,3,4},{16,26,36,46}}
|
||||
|
||||
//slc2:= [][]int16 {{}}
|
||||
slc2 = append(slc2,slc2 ...)
|
||||
|
||||
pk.PackMap(func(mp packs.MapPacker) {
|
||||
mp.KeyValue("fb0",slc2)
|
||||
mp.KeyValueList("l01",func(l packs.ListPacker){
|
||||
l.ItemList(func(l1 packs.ListPacker){
|
||||
l1.ItemUInt64(11)
|
||||
l1.ItemUInt64(22)
|
||||
})
|
||||
l.ItemList(func(l1 packs.ListPacker){
|
||||
l1.ItemUInt64(33)
|
||||
l1.ItemUInt64(44)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
mp.KeyValueBool("boolean",true)
|
||||
mp.KeyValueFloat32("bf",12223234.34234)
|
||||
mp.KeyValueBinary("binary",[]byte{22,121,21,23,23,54,67})
|
||||
|
||||
mp.KeyValueDate("date",time.Now())
|
||||
mp.KeyValueInt16("una",34)
|
||||
|
||||
|
||||
|
||||
mp.KeyValueObject("MiObjeto",func(op packs.ObjectPacker){
|
||||
op.FieldInt32("fb1",43433)
|
||||
op.FieldString ("fb2","aaaaa")
|
||||
op.Field("fb3",slc)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
*/
|
||||
|
||||
var s = struct {
|
||||
F1Int int
|
||||
F2Uint uint
|
||||
F3String string
|
||||
F4Binary []byte
|
||||
}{
|
||||
F1Int :-111,
|
||||
F2Uint: 333,
|
||||
F3String: "Esto es un string <quoted & scaped >",
|
||||
F4Binary: []byte("dklsdjflsdjflsdkfjlsdkfjlsdkfjlsdfjdlsfjsdlf"),
|
||||
}
|
||||
|
||||
pk.Pack(s)
|
||||
|
||||
errs.Test(pk.Error(),true)
|
||||
fmt.Printf("JSON \n%s",pk.Bytes())
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rfields_by_index.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
|
||||
|
||||
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type RFieldsByIndex []RField
|
||||
|
||||
func (x RFieldsByIndex) Len() int { return len(x) }
|
||||
|
||||
func (x RFieldsByIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x RFieldsByIndex) 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)
|
||||
}
|
||||
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name RStructFieldFlags.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 packs
|
||||
|
||||
|
||||
const(
|
||||
|
||||
RFieldFlagTagged RFieldFlags = 1 >> iota
|
||||
RFieldOmitEmpty
|
||||
RFieldQuoted
|
||||
)
|
||||
|
||||
|
||||
type (
|
||||
|
||||
RFieldFlags uint8
|
||||
)
|
||||
|
||||
|
||||
|
||||
func (f RFieldFlags) Tagged () bool {
|
||||
return RFieldFlagTagged&f != 0
|
||||
}
|
||||
|
||||
func (f RFieldFlags) OmitEmpty () bool {
|
||||
return RFieldOmitEmpty&f != 0
|
||||
}
|
||||
|
||||
func (f RFieldFlags) Quote () bool {
|
||||
return RFieldQuoted&f != 0
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
// ------------------------------------------------------------------------
|
||||
// Project atila
|
||||
// Active Thing (activething.com) git.activething.com/go
|
||||
//
|
||||
// File name rfields_by_index.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 packs
|
||||
|
||||
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type RFieldsByIndex []RField
|
||||
|
||||
func (x RFieldsByIndex) Len() int { return len(x) }
|
||||
|
||||
func (x RFieldsByIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x RFieldsByIndex) 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)
|
||||
}
|
||||
|
||||
|
||||
@ -1,258 +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 packs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
RTypeFields struct {
|
||||
Fields RFields
|
||||
Index map[string]int
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func NewRTypeFields (t reflect.Type) *RTypeFields {
|
||||
// Anonymous Fields to explore at the current level and the next.
|
||||
current := RFields{}
|
||||
next := []RField{{RType: t}}
|
||||
|
||||
// Count of queued names for current level and the next.
|
||||
var count, nextCount map[reflect.Type]int
|
||||
|
||||
// Types already visited at an earlier level.
|
||||
visited := map[reflect.Type]bool{}
|
||||
|
||||
// Fields found.
|
||||
var fs []RField
|
||||
|
||||
// Buffer to run HTMLEscape on RField names.
|
||||
var nameEscBuf bytes.Buffer
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if visited[f.RType] {
|
||||
continue
|
||||
}
|
||||
visited[f.RType] = true
|
||||
|
||||
// Scan f.RType for Fields to include.
|
||||
for i := 0; i < f.RType.NumField(); i++ {
|
||||
var flags RFieldFlags
|
||||
sf := f.RType.Field(i)
|
||||
if sf.Anonymous {
|
||||
t := sf.Type
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if !sf.IsExported() && t.Kind() != reflect.Struct {
|
||||
// Ignore embedded Fields of unexported non-struct types.
|
||||
continue
|
||||
}
|
||||
// Do not ignore embedded Fields of unexported struct types
|
||||
// since they may have exported Fields.
|
||||
} else if !sf.IsExported() {
|
||||
// Ignore unexported non-embedded Fields.
|
||||
continue
|
||||
}
|
||||
tag := sf.Tag.Get("json")
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
name, opts := parseTag(tag)
|
||||
if !isValidTag(name) {
|
||||
name = ""
|
||||
}
|
||||
index := make([]int, len(f.Index)+1)
|
||||
copy(index, f.Index)
|
||||
index[len(f.Index)] = i
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Pointer {
|
||||
// Follow pointer.
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
// Only strings, floats, integers, and booleans can be quoted.
|
||||
if opts.Contains("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:
|
||||
flags|=RFieldQuoted
|
||||
}
|
||||
}
|
||||
|
||||
// Record found RField and index sequence.
|
||||
if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
if name != "" {
|
||||
flags |= RFieldFlagTagged
|
||||
}
|
||||
if name == "" {
|
||||
name = sf.Name
|
||||
}
|
||||
rf := RField{
|
||||
Name : name,
|
||||
Index: index,
|
||||
RType: ft,
|
||||
}
|
||||
/*
|
||||
if opts.Contains("omitempty") {
|
||||
rf.Flags|=RFieldOmitEmpty
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
rf.BName = []byte(rf.Name)
|
||||
//rf.EqualFold = foldFunc(rf.BName)
|
||||
|
||||
// Build nameEscHTML and nameNonEsc ahead of time.
|
||||
nameEscBuf.Reset()
|
||||
nameEscBuf.WriteString(`"`)
|
||||
//HTMLEscape(&nameEscBuf, rf.BName)
|
||||
nameEscBuf.WriteString(`":`)
|
||||
rf.HName = nameEscBuf.String()
|
||||
//rf. = `"` + rf.Name + `":`
|
||||
|
||||
fs = append(fs, rf)
|
||||
if count[f.RType] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fs = append(fs, fs[len(fs)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anonymous struct to explore in next round.
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
next = append(next, RField{Name: ft.Name(), Index: index, RType: ft})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(fs, func(i, j int) bool {
|
||||
x := fs
|
||||
// sort RField by name, breaking ties with depth, then
|
||||
// breaking ties with "name came from json tag", then
|
||||
// breaking ties with index sequence.
|
||||
if x[i].Name != x[j].Name {
|
||||
return x[i].Name < x[j].Name
|
||||
}
|
||||
if len(x[i].Index) != len(x[j].Index) {
|
||||
return len(x[i].Index) < len(x[j].Index)
|
||||
}
|
||||
if x[i].Tagged() != x[j].Tagged() {
|
||||
return x[i].Tagged()
|
||||
}
|
||||
return RFieldsByIndex(x).Less(i, j)
|
||||
})
|
||||
|
||||
// Delete all Fields that are hidden by the Go rules for embedded Fields,
|
||||
// except that Fields with JSON tags are promoted.
|
||||
|
||||
// The Fields are sorted in primary order of name, secondary order
|
||||
// of RField index length. Loop over names; for each name, delete
|
||||
// hidden Fields by choosing the one dominant RField that survives.
|
||||
out := fs[:0]
|
||||
for advance, i := 0, 0; i < len(fs); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of Fields with the name of this first RField.
|
||||
fi := fs[i]
|
||||
name := fi.Name
|
||||
for advance = 1; i+advance < len(fs); advance++ {
|
||||
fj := fs[i+advance]
|
||||
if fj.Name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one RField with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := RFields(fs[i : i+advance]).Dominant()
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fs = out
|
||||
sort.Sort(RFieldsByIndex(fs))
|
||||
|
||||
for i := range fs {
|
||||
//f := &fs[i]
|
||||
//f.encoder = typeEncoder(typeByIndex(t, f.index))
|
||||
}
|
||||
nameIndex := make(map[string]int, len(fs))
|
||||
for i, f := range fs {
|
||||
nameIndex[f.Name] = i
|
||||
}
|
||||
|
||||
return &RTypeFields{
|
||||
Fields: fs,
|
||||
Index : nameIndex,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
tag, opt, _ := strings.Cut(tag, ",")
|
||||
return tag, tagOptions(opt)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func isValidTag(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
|
||||
// Backslash and quote chars are reserved, but
|
||||
// otherwise any punctuation chars are allowed
|
||||
// in a tag name.
|
||||
case !unicode.IsLetter(c) && !unicode.IsDigit(c):
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Loading…
Reference in new issue