diff --git a/app/main.go b/app/main.go index d67f948..6cd77c2 100644 --- a/app/main.go +++ b/app/main.go @@ -23,74 +23,8 @@ package main -import ( - "activething.com/go/gogo/core/errs" - "activething.com/go/gogo/packs/pjson" - "fmt" -) - func 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 ", - F4Binary: []byte("dklsdjflsdjflsdkfjlsdkfjlsdkfjlsdfjdlsfjsdlf"), - } - - pk.Pack(s) - - errs.Test(pk.Error(),true) - fmt.Printf("JSON \n%s",pk.Bytes()) - - + reflects_main() } diff --git a/app/packs.go b/app/packs.go new file mode 100644 index 0000000..412ebb7 --- /dev/null +++ b/app/packs.go @@ -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 ", + F4Binary: []byte("dklsdjflsdjflsdkfjlsdkfjlsdkfjlsdfjdlsfjsdlf"), + } + + pk.Pack(s) + + errs.Test(pk.Error(),true) + fmt.Printf("JSON \n%s",pk.Bytes()) + + + +} \ No newline at end of file diff --git a/core/reflects/rfield_flags.go b/app/reflects.go similarity index 61% rename from core/reflects/rfield_flags.go rename to app/reflects.go index ae285d5..7d9334c 100644 --- a/core/reflects/rfield_flags.go +++ b/app/reflects.go @@ -2,9 +2,9 @@ // Project atila // Active Thing (activething.com) git.activething.com/go // -// File name RStructFieldFlags.go +// File name reflects.go // Created by DEV -// Modified 26/01/2024 +// Modified 27/01/2024 // // Copyright 2024 activething.com // ------------------------------------------------------------------------ @@ -21,32 +21,52 @@ // limitations under the License. // ------------------------------------------------------------------------ -package reflects +package main +import ( + "activething.com/go/gogo/core/reflects" + "fmt" + "reflect" +) + +type ( -const( + MiTipo struct { + FS1 string `json:"nombre,omitempty,binary"` + FU2 uint + FB3 bool + } - RFieldFlagTagged RFieldFlags = 1 >> iota - RFieldOmitEmpty - RFieldQuoted ) -type ( - RFieldFlags uint8 -) +func reflects_main () { + + + t := MiTipo { + + FS1 : "dfdfdf", + FU2 : 233, + FB3 : true, + + } + + + rf := reflect.TypeOf(t) + + for i:=0; i 1 && len(f[0].Index) == len(f[1].Index) && f[0].Tagged() == f[1].Tagged() { - return RField{}, false +func NewRField (rfield reflect.StructField, options ...opts.OptionFnc[RField]) *RField { + rf := &RField { + RField: rfield, } - return f[0], true + + return opts.Apply(rf,options...) } + +func (f *RField) parseTag (tag string) slices.String { + var l slices.String + s,h := f.Tags[tag] + if !h { + + } + return l +} diff --git a/packs/rfield_tag_options.go b/core/reflects/rfield_tag.go similarity index 64% rename from packs/rfield_tag_options.go rename to core/reflects/rfield_tag.go index 428350d..b43348b 100644 --- a/packs/rfield_tag_options.go +++ b/core/reflects/rfield_tag.go @@ -21,29 +21,43 @@ // limitations under the License. // ------------------------------------------------------------------------ -package packs +package reflects -import "strings" +import ( + "reflect" + "strings" +) type ( RFieldTag struct { Tag string - Options map[string]struct{} + parsed bool + Name string + Flags uint8 } ) -func NewRFieldTag (tag string, onOption func(o string)) *RFieldTag { - m := make(map[string]struct{}) - for _,v := range strings.Split(tag,",") { - m[v]=struct{}{} +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), } - return &RFieldTag{ - Tag : tag, - Options : m, + 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 } diff --git a/packs/rfield.go b/core/reflects/rfields.go similarity index 77% rename from packs/rfield.go rename to core/reflects/rfields.go index 132f84a..1e16159 100644 --- a/packs/rfield.go +++ b/core/reflects/rfields.go @@ -2,9 +2,9 @@ // Project atila // Active Thing (activething.com) git.activething.com/go // -// File name reflect_struct_field.go +// File name rfields.go // Created by DEV -// Modified 26/01/2024 +// Modified 27/01/2024 // // Copyright 2024 activething.com // ------------------------------------------------------------------------ @@ -21,35 +21,17 @@ // limitations under the License. // ------------------------------------------------------------------------ -package packs +package reflects -import "reflect" -type ( - - RField struct { - RFieldFlags - RType reflect.Type - - Name string - SName string // scaped name - HName string // html name - - EqualFoldFn func(s, t []byte) bool - - BName []byte // name bytes - Index []int - Options map[string]RFieldTag - } +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 @@ -59,5 +41,24 @@ func (f RFields) Dominant() (RField, bool) { } 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) +} diff --git a/core/reflects/rfields_by_index.go b/core/reflects/rfields_by_index.go deleted file mode 100644 index ff249f0..0000000 --- a/core/reflects/rfields_by_index.go +++ /dev/null @@ -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) -} - - diff --git a/core/reflects/rtype_fields.go b/core/reflects/rstruct.go similarity index 96% rename from core/reflects/rtype_fields.go rename to core/reflects/rstruct.go index 49f8371..db67209 100644 --- a/core/reflects/rtype_fields.go +++ b/core/reflects/rstruct.go @@ -23,24 +23,22 @@ package reflects -import ( - "bytes" - "reflect" - "sort" - "strings" - "unicode" -) + type ( - RTypeFields struct { - Fields RFields - Index map[string]int + RStruct struct { + Fields RFields + NameIndex map[string]int } ) -func NewRTypeFields (t reflect.Type) *RTypeFields { + + + +/* +func NewRStruct (t reflect.Type) *RStruct { // Anonymous Fields to explore at the current level and the next. current := RFields{} next := []RField{{RType: t}} @@ -129,12 +127,12 @@ func NewRTypeFields (t reflect.Type) *RTypeFields { Index: index, RType: ft, } - /* + if opts.Contains("omitempty") { rf.Flags|=RFieldOmitEmpty } - */ + rf.BName = []byte(rf.Name) //rf.EqualFold = foldFunc(rf.BName) @@ -224,9 +222,9 @@ func NewRTypeFields (t reflect.Type) *RTypeFields { nameIndex[f.Name] = i } - return &RTypeFields{ - Fields: fs, - Index : nameIndex, + return &RStruct{ + Fields: fs, + FieldsIndex: nameIndex, } } @@ -255,4 +253,6 @@ func isValidTag(s string) bool { } } return true -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/go.work b/go.work index c58fe33..a070bf8 100644 --- a/go.work +++ b/go.work @@ -9,6 +9,7 @@ use ( ./core/errs ./core/opts ./core/syncs + ./core/reflects ./packs ) diff --git a/packs/rfield_flags.go b/packs/rfield_flags.go deleted file mode 100644 index 4d2a6c1..0000000 --- a/packs/rfield_flags.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/packs/rfields_by_index.go b/packs/rfields_by_index.go deleted file mode 100644 index cfedb79..0000000 --- a/packs/rfields_by_index.go +++ /dev/null @@ -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) -} - - diff --git a/packs/rtype_fields.go b/packs/rtype_fields.go deleted file mode 100644 index 2f56883..0000000 --- a/packs/rtype_fields.go +++ /dev/null @@ -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 -} \ No newline at end of file