Skip to content

Commit

Permalink
DOM: Align codec functions
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Kosegi <richard.kosegi@gmail.com>
  • Loading branch information
rkosegi committed Aug 20, 2024
1 parent 9f977ce commit c31bdc2
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 90 deletions.
4 changes: 2 additions & 2 deletions diff/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ level1:
},
})
var buf bytes.Buffer
err = doc.Serialize(&buf, dom.DefaultNodeMappingFn, dom.DefaultYamlEncoder)
err = doc.Serialize(&buf, dom.DefaultNodeEncoderFn, dom.DefaultYamlEncoder)
assert.Nil(t, err)
assert.Equal(t, `leaf0: 1234
leafX: null
Expand Down Expand Up @@ -89,7 +89,7 @@ level1:
},
})
var buf bytes.Buffer
err = doc.Serialize(&buf, dom.DefaultNodeMappingFn, dom.DefaultYamlEncoder)
err = doc.Serialize(&buf, dom.DefaultNodeEncoderFn, dom.DefaultYamlEncoder)
assert.Nil(t, err)
assert.Equal(t, `leaf0: 1234
level1:
Expand Down
2 changes: 1 addition & 1 deletion diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ level1:
}, res)
Apply(cright, *res)
var buf bytes.Buffer
err = cright.Serialize(&buf, dom.DefaultNodeMappingFn, dom.DefaultYamlEncoder)
err = cright.Serialize(&buf, dom.DefaultNodeEncoderFn, dom.DefaultYamlEncoder)
assert.Nil(t, err)
assert.Equal(t, `another:
container:
Expand Down
90 changes: 90 additions & 0 deletions dom/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
Copyright 2024 Richard Kosegi
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 dom

import "reflect"

func encodeLeafFn(n Leaf) interface{} {
return n.Value()
}

func encoderListFn(n List) []interface{} {
res := make([]interface{}, n.Size())
for i, item := range n.Items() {
if item.IsContainer() {
res[i] = encodeContainerFn(item.(Container))
} else if item.IsList() {
res[i] = encoderListFn(item.(List))
} else {
res[i] = encodeLeafFn(item.(Leaf))
}
}
return res
}

func encodeContainerFn(n Container) map[string]interface{} {
res := map[string]interface{}{}
for k, v := range n.(Container).Children() {
if v.IsContainer() {
res[k] = encodeContainerFn(v.(Container))
} else if v.IsList() {
res[k] = encoderListFn(v.(List))
} else {
res[k] = encodeLeafFn(v.(Leaf))
}
}
return res
}

func decodeLeafFn(v interface{}) Leaf {
return LeafNode(v)
}

func decodeListFn(v []interface{}, l ListBuilder) {
for _, item := range v {
t := reflect.ValueOf(item)
switch t.Kind() {
case reflect.Map:
l.Append(DefaultNodeDecoderFn(item.(map[string]interface{})))
case reflect.Slice, reflect.Array:
list := &listBuilderImpl{}
decodeListFn(item.([]interface{}), list)
l.Append(list)
case reflect.Int, reflect.Float64, reflect.String, reflect.Bool:
l.Append(decodeLeafFn(item))
}
}
}

func decodeContainerFn(current *map[string]interface{}, parent ContainerBuilder) {
for k, v := range *current {
if v == nil {
parent.AddValue(k, nilLeaf)
} else {
t := reflect.ValueOf(v)
switch t.Kind() {
case reflect.Map:
ref := v.(map[string]interface{})
decodeContainerFn(&ref, parent.AddContainer(k))
case reflect.Slice, reflect.Array:
decodeListFn(v.([]interface{}), parent.AddList(k))
case reflect.Int, reflect.Float64, reflect.String, reflect.Bool:
parent.AddValue(k, decodeLeafFn(v))
}
}
}
}
45 changes: 2 additions & 43 deletions dom/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/rkosegi/yaml-toolkit/utils"
"gopkg.in/yaml.v3"
"io"
"reflect"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -141,7 +140,7 @@ func (c *containerImpl) Children() map[string]Node {
return c.children
}

func (c *containerImpl) Serialize(writer io.Writer, mappingFunc NodeMappingFunc, encFn EncoderFunc) error {
func (c *containerImpl) Serialize(writer io.Writer, mappingFunc NodeEncoderFunc, encFn EncoderFunc) error {
return encFn(writer, mappingFunc(c))
}

Expand Down Expand Up @@ -284,44 +283,6 @@ func (c *containerBuilderImpl) RemoveAt(path string) {
}
}

func appendMap(current *map[string]interface{}, parent ContainerBuilder) {
for k, v := range *current {
if v == nil {
parent.AddValue(k, nilLeaf)
} else {
t := reflect.ValueOf(v)
switch t.Kind() {
case reflect.Map:
ref := v.(map[string]interface{})
appendMap(&ref, parent.AddContainer(k))
case reflect.Slice, reflect.Array:
appendSlice(v.([]interface{}), parent.AddList(k))
case reflect.Int, reflect.Float64, reflect.String, reflect.Bool:
parent.AddValue(k, LeafNode(v))
}
}
}
}

func appendSlice(items []interface{}, l ListBuilder) {
for _, item := range items {
t := reflect.ValueOf(item)
switch t.Kind() {
case reflect.Map:
ref := item.(map[string]interface{})
c := &containerBuilderImpl{}
appendMap(&ref, c)
l.Append(c)
case reflect.Slice, reflect.Array:
list := &listBuilderImpl{}
appendSlice(item.([]interface{}), list)
l.Append(list)
case reflect.Int, reflect.Float64, reflect.String, reflect.Bool:
l.Append(LeafNode(item))
}
}
}

type containerFactory struct {
}

Expand All @@ -338,9 +299,7 @@ func (f *containerFactory) FromAny(v interface{}) ContainerBuilder {
}

func (f *containerFactory) FromMap(in map[string]interface{}) ContainerBuilder {
doc := containerBuilderImpl{}
appendMap(&in, &doc)
return &doc
return DefaultNodeDecoderFn(in).(ContainerBuilder)
}

func (f *containerFactory) FromProperties(in map[string]interface{}) ContainerBuilder {
Expand Down
6 changes: 3 additions & 3 deletions dom/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestBuildAndSerialize(t *testing.T) {
AddContainer("level3").
AddValue("leaf1", LeafNode("Hello"))
var buf bytes.Buffer
err := builder.Serialize(&buf, DefaultNodeMappingFn, DefaultJsonEncoder)
err := builder.Serialize(&buf, DefaultNodeEncoderFn, DefaultJsonEncoder)
assert.Nil(t, err)
assert.Equal(t, `{
"root": {
Expand All @@ -92,7 +92,7 @@ func TestRemove(t *testing.T) {
AddValue("leaf1", LeafNode("Hello"))
builder.Remove("root")
var buf bytes.Buffer
err := builder.Serialize(&buf, DefaultNodeMappingFn, DefaultJsonEncoder)
err := builder.Serialize(&buf, DefaultNodeEncoderFn, DefaultJsonEncoder)
assert.Nil(t, err)
assert.Equal(t, "{}\n", buf.String())
}
Expand Down Expand Up @@ -182,7 +182,7 @@ func TestAddValueAt(t *testing.T) {
)
assert.Equal(t, "abc", c.Lookup("test1.test2.test31").(Leaf).Value())
var buff bytes.Buffer
err := c.Serialize(&buff, DefaultNodeMappingFn, DefaultYamlEncoder)
err := c.Serialize(&buff, DefaultNodeEncoderFn, DefaultYamlEncoder)
assert.Nil(t, err)
}

Expand Down
36 changes: 2 additions & 34 deletions dom/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (m *overlayDocument) Populate(overlay, path string, data *map[string]interf
if path != "" {
current = ensurePath(current, m.pathComponents(path))
}
appendMap(data, current)
decodeContainerFn(data, current)
}

func (m *overlayDocument) Lookup(overlay, path string) Node {
Expand Down Expand Up @@ -184,39 +184,7 @@ func firstValidListItem(idx int, lists ...List) Node {
return nilLeaf
}

func leafMappingFn(n Leaf) interface{} {
return n.Value()
}

func listMappingFn(n List) []interface{} {
res := make([]interface{}, n.Size())
for i, item := range n.Items() {
if item.IsContainer() {
res[i] = containerMappingFn(item.(Container))
} else if item.IsList() {
res[i] = listMappingFn(item.(List))
} else {
res[i] = leafMappingFn(item.(Leaf))
}
}
return res
}

func containerMappingFn(n Container) map[string]interface{} {
res := map[string]interface{}{}
for k, v := range n.(Container).Children() {
if v.IsContainer() {
res[k] = containerMappingFn(v.(Container))
} else if v.IsList() {
res[k] = listMappingFn(v.(List))
} else {
res[k] = leafMappingFn(v.(Leaf))
}
}
return res
}

func (m *overlayDocument) Serialize(writer io.Writer, mappingFunc NodeMappingFunc, encFn EncoderFunc) error {
func (m *overlayDocument) Serialize(writer io.Writer, mappingFunc NodeEncoderFunc, encFn EncoderFunc) error {
return encFn(writer, mappingFunc(m.Merged()))
}

Expand Down
6 changes: 3 additions & 3 deletions dom/overlay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ func TestSerialize(t *testing.T) {
c.AddValue("test3", LeafNode("no"))
d.Put("", "key2", c)
var buf bytes.Buffer
assert.Nil(t, d.Serialize(&buf, DefaultNodeMappingFn, DefaultYamlEncoder))
assert.Nil(t, d.Serialize(&buf, DefaultNodeEncoderFn, DefaultYamlEncoder))
assert.True(t, buf.Len() > 0)
buf.Reset()
assert.Nil(t, d.Serialize(&buf, DefaultNodeMappingFn, DefaultYamlEncoder))
assert.Nil(t, d.Serialize(&buf, DefaultNodeEncoderFn, DefaultYamlEncoder))
assert.True(t, buf.Len() > 0)
}

Expand All @@ -76,7 +76,7 @@ func TestLoad(t *testing.T) {
assert.Equal(t, 1, len(d.Layers()))

var buf bytes.Buffer
assert.Nil(t, d.Serialize(&buf, DefaultNodeMappingFn, DefaultYamlEncoder))
assert.Nil(t, d.Serialize(&buf, DefaultNodeEncoderFn, DefaultYamlEncoder))
var node yaml.Node
err = yaml.NewDecoder(&buf).Decode(&node)
assert.NoError(t, err)
Expand Down
24 changes: 21 additions & 3 deletions dom/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ func SearchEqual(in interface{}) SearchValueFunc {
}
}

// NodeMappingFunc maps internal Container value into external data representation
// NodeMappingFunc maps internal Container value into external data representation.
// Deprecated. Use NodeEncoderFunc
type NodeMappingFunc func(Container) interface{}

// NodeEncoderFunc maps internal Container value into external data representation
type NodeEncoderFunc func(Container) interface{}

// NodeDecoderFunc takes external data representation and decode it to Container
type NodeDecoderFunc func(map[string]interface{}) Container

// EncoderFunc encodes raw value into stream using provided io.Writer
type EncoderFunc func(w io.Writer, v interface{}) error

Expand All @@ -61,14 +68,25 @@ func DefaultJsonEncoder(w io.Writer, v interface{}) error {
return e.Encode(v)
}

func DefaultNodeEncoderFn(n Container) interface{} {
return DefaultNodeMappingFn(n)
}

// Deprecated. Use DefaultNodeEncoderFn
func DefaultNodeMappingFn(n Container) interface{} {
return containerMappingFn(n)
return encodeContainerFn(n)
}

func DefaultNodeDecoderFn(m map[string]interface{}) Container {
cb := containerBuilderImpl{}
decodeContainerFn(&m, &cb)
return &cb
}

// Serializable interface allows to persist data into provided io.Writer
type Serializable interface {
// Serialize writes content into given writer, while encoding using provided EncoderFunc
Serialize(writer io.Writer, mappingFunc NodeMappingFunc, encFn EncoderFunc) error
Serialize(writer io.Writer, mappingFunc NodeEncoderFunc, encFn EncoderFunc) error
}

// Node is elemental unit of document. At runtime, it could be either Leaf or Container.
Expand Down
2 changes: 1 addition & 1 deletion k8s/embedded.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func DecodeEmbeddedDoc(item string, decFn dom.DecoderFunc) DecodeInternalFn {
func EncodeEmbeddedDoc(item string, encFn dom.EncoderFunc) EncodeInternalFn {
return func(m Manifest, node dom.ContainerBuilder) error {
var buff bytes.Buffer
if err := node.Serialize(&buff, dom.DefaultNodeMappingFn, encFn); err != nil {
if err := node.Serialize(&buff, dom.DefaultNodeEncoderFn, encFn); err != nil {
return err
}
m.StringData().Update(item, buff.String())
Expand Down

0 comments on commit c31bdc2

Please sign in to comment.