Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

type container struct {
A []int `jsonry:"a"`
C interface{} `jsonry:"b.c"`
D string `jsonry:"b.d"`
A []int `jsonry:"a"`
C any `jsonry:"b.c"`
D string `jsonry:"b.d"`
}

const marshaled = `{"a":[1,2,3],"b":{"c":null,"d":"hello"}}`
Expand Down Expand Up @@ -48,8 +48,8 @@ func BenchmarkUnmarshal(b *testing.B) {
var receiver struct {
A []int `json:"a"`
B struct {
C interface{} `json:"c"`
D string `json:"d"`
C any `json:"c"`
D string `json:"d"`
} `json:"b"`
}
json.Unmarshal([]byte(marshaled), &receiver)
Expand Down Expand Up @@ -92,8 +92,8 @@ func BenchmarkMarshal(b *testing.B) {
var transmitter struct {
A []int `json:"a"`
B struct {
C interface{} `json:"c"`
D string `json:"d"`
C any `json:"c"`
D string `json:"d"`
} `json:"b"`
}
transmitter.A = u.A
Expand Down
4 changes: 2 additions & 2 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ func (u unsupportedKeyType) message(ctx errorcontext.ErrorContext) string {
}

type conversionError struct {
value interface{}
value any
}

func newConversionError(value interface{}) error {
func newConversionError(value any) error {
return &conversionError{
value: value,
}
Expand Down
24 changes: 12 additions & 12 deletions internal/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"code.cloudfoundry.org/jsonry/internal/path"
)

type Tree map[string]interface{}
type Tree map[string]any

func (t Tree) Attach(p path.Path, v interface{}) Tree {
func (t Tree) Attach(p path.Path, v any) Tree {
switch p.Len() {
case 0:
panic("empty path")
Expand All @@ -31,7 +31,7 @@ func (t Tree) Attach(p path.Path, v interface{}) Tree {
return t
}

func (t Tree) Fetch(p path.Path) (interface{}, bool) {
func (t Tree) Fetch(p path.Path) (any, bool) {
switch p.Len() {
case 0:
panic("empty path")
Expand All @@ -47,41 +47,41 @@ func (t Tree) Fetch(p path.Path) (interface{}, bool) {
}

switch vt := v.(type) {
case map[string]interface{}:
case map[string]any:
return Tree(vt).Fetch(stem)
case []interface{}:
case []any:
return unspread(vt, stem), true
default:
return nil, false
}
}
}

func spread(p path.Path, v interface{}) []interface{} {
func spread(p path.Path, v any) []any {
vv := reflect.ValueOf(v)
if vv.Kind() != reflect.Array && vv.Kind() != reflect.Slice {
v = []interface{}{v}
v = []any{v}
vv = reflect.ValueOf(v)
}

var s []interface{}
var s []any
for i := 0; i < vv.Len(); i++ {
s = append(s, make(Tree).Attach(p, vv.Index(i).Interface()))
}
return s
}

func unspread(v []interface{}, stem path.Path) []interface{} {
l := make([]interface{}, 0, len(v))
func unspread(v []any, stem path.Path) []any {
l := make([]any, 0, len(v))
for i := range v {
switch vt := v[i].(type) {
case map[string]interface{}:
case map[string]any:
if r, ok := Tree(vt).Fetch(stem); ok {
l = append(l, r)
} else {
l = append(l, nil)
}
case []interface{}:
case []any:
l = append(l, unspread(vt, stem)...)
default:
l = append(l, v[i])
Expand Down
10 changes: 5 additions & 5 deletions internal/tree/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ var _ = Describe("Tree", func() {

v, ok := t.Fetch(p)
Expect(ok).To(BeTrue())
Expect(v).To(Equal(map[string]interface{}{"d": map[string]interface{}{"e": "hello"}}))
Expect(v).To(Equal(map[string]any{"d": map[string]any{"e": "hello"}}))
})

It("can fetch a list at the leaf", func() {
Expand All @@ -88,7 +88,7 @@ var _ = Describe("Tree", func() {

v, ok := t.Fetch(p)
Expect(ok).To(BeTrue())
Expect(v).To(Equal([]interface{}{"h", "e", "l", "l", "o"}))
Expect(v).To(Equal([]any{"h", "e", "l", "l", "o"}))
})

It("can fetch a list at a branch", func() {
Expand All @@ -98,7 +98,7 @@ var _ = Describe("Tree", func() {

v, ok := t.Fetch(p)
Expect(ok).To(BeTrue())
Expect(v).To(Equal([]interface{}{"h", "i", "!"}))
Expect(v).To(Equal([]any{"h", "i", "!"}))
})

It("inserts nils when a list has missing elements", func() {
Expand All @@ -108,7 +108,7 @@ var _ = Describe("Tree", func() {

v, ok := t.Fetch(p)
Expect(ok).To(BeTrue())
Expect(v).To(Equal([]interface{}{"h", nil, "i", nil, "!"}))
Expect(v).To(Equal([]any{"h", nil, "i", nil, "!"}))
})

It("flattens lists of lists", func() {
Expand All @@ -118,7 +118,7 @@ var _ = Describe("Tree", func() {

v, ok := t.Fetch(p)
Expect(ok).To(BeTrue())
Expect(v).To(Equal([]interface{}{"h", nil, "i", "!"}))
Expect(v).To(Equal([]any{"h", nil, "i", "!"}))
})
})
})
18 changes: 9 additions & 9 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
// to determine whether or not to marshal the field, overriding any `,omitempty` tags.
//
// The field type can be string, bool, int*, uint*, float*, map, slice, array or struct. JSONry is recursive.
func Marshal(in interface{}) ([]byte, error) {
func Marshal(in any) ([]byte, error) {
iv := reflect.Indirect(reflect.ValueOf(in))

if iv.Kind() != reflect.Struct {
Expand All @@ -36,7 +36,7 @@ func Marshal(in interface{}) ([]byte, error) {
return json.Marshal(m)
}

func marshalStruct(in reflect.Value) (map[string]interface{}, error) {
func marshalStruct(in reflect.Value) (map[string]any, error) {
out := make(tree.Tree)
t := in.Type()

Expand All @@ -61,7 +61,7 @@ func marshalStruct(in reflect.Value) (map[string]interface{}, error) {
return out, nil
}

func marshal(in reflect.Value) (r interface{}, err error) {
func marshal(in reflect.Value) (r any, err error) {
input := reflect.Indirect(in)
kind := input.Kind()

Expand All @@ -87,12 +87,12 @@ func marshal(in reflect.Value) (r interface{}, err error) {
return
}

func marshalList(in reflect.Value) (out []interface{}, err error) {
func marshalList(in reflect.Value) (out []any, err error) {
if in.Type().Kind() == reflect.Slice && in.IsNil() {
return out, nil
}

out = make([]interface{}, in.Len())
out = make([]any, in.Len())
for i := 0; i < in.Len(); i++ {
r, err := marshal(in.Index(i))
if err != nil {
Expand All @@ -104,12 +104,12 @@ func marshalList(in reflect.Value) (out []interface{}, err error) {
return out, nil
}

func marshalMap(in reflect.Value) (out map[string]interface{}, err error) {
func marshalMap(in reflect.Value) (out map[string]any, err error) {
if in.IsNil() {
return out, nil
}

out = make(map[string]interface{})
out = make(map[string]any)
iter := in.MapRange()
for iter.Next() {
k := iter.Key()
Expand All @@ -127,15 +127,15 @@ func marshalMap(in reflect.Value) (out map[string]interface{}, err error) {
return out, nil
}

func marshalJSONMarshaler(in reflect.Value) (interface{}, error) {
func marshalJSONMarshaler(in reflect.Value) (any, error) {
const method = "MarshalJSON"
t := in.MethodByName(method).Call(nil)

if err := checkForError(t[1]); err != nil {
return nil, newForeignError(fmt.Sprintf("error from %s() call", method), err)
}

var r interface{}
var r any
err := json.Unmarshal(t[0].Bytes(), &r)
if err != nil {
return nil, newForeignError(fmt.Sprintf(`error parsing %s() output "%s"`, method, t[0].Bytes()), err)
Expand Down
36 changes: 18 additions & 18 deletions marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
)

var _ = Describe("Marshal", func() {
expectToMarshal := func(input interface{}, expected string) {
expectToMarshal := func(input any, expected string) {
out, err := jsonry.Marshal(input)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
ExpectWithOffset(1, out).To(MatchJSON(expected))
}

expectToFail := func(input interface{}, message string) {
expectToFail := func(input any, message string) {
_, err := jsonry.Marshal(input)
ExpectWithOffset(1, err).To(MatchError(message), func() string {
if err != nil {
Expand Down Expand Up @@ -130,7 +130,7 @@ var _ = Describe("Marshal", func() {
})

It("marshals a nil interface", func() {
expectToMarshal(struct{ N interface{} }{N: nil}, `{"N":null}`)
expectToMarshal(struct{ N any }{N: nil}, `{"N":null}`)
})

It("marshals a nil pointer", func() {
Expand All @@ -142,18 +142,18 @@ var _ = Describe("Marshal", func() {
})

It("marshals an array", func() {
s := [3]interface{}{"hello", true, 42}
expectToMarshal(struct{ S [3]interface{} }{S: s}, `{"S":["hello",true,42]}`)
s := [3]any{"hello", true, 42}
expectToMarshal(struct{ S [3]any }{S: s}, `{"S":["hello",true,42]}`)
expectToMarshal(struct {
S *[3]interface{}
S *[3]any
}{S: &s}, `{"S":["hello",true,42]}`)
})

Context("slices", func() {
It("marshals slices with interface{} values", func() {
s := []interface{}{"hello", true, 42}
expectToMarshal(struct{ S []interface{} }{S: s}, `{"S":["hello",true,42]}`)
expectToMarshal(struct{ S *[]interface{} }{S: &s}, `{"S":["hello",true,42]}`)
s := []any{"hello", true, 42}
expectToMarshal(struct{ S []any }{S: s}, `{"S":["hello",true,42]}`)
expectToMarshal(struct{ S *[]any }{S: &s}, `{"S":["hello",true,42]}`)
})

It("marshals slices with string values", func() {
Expand All @@ -177,9 +177,9 @@ var _ = Describe("Marshal", func() {

Context("maps", func() {
It("marshals maps with interface{} values", func() {
mi := map[string]interface{}{"foo": "hello", "bar": true, "baz": 42}
expectToMarshal(struct{ M map[string]interface{} }{M: mi}, `{"M":{"foo":"hello","bar":true,"baz":42}}`)
expectToMarshal(struct{ M *map[string]interface{} }{M: &mi}, `{"M":{"foo":"hello","bar":true,"baz":42}}`)
mi := map[string]any{"foo": "hello", "bar": true, "baz": 42}
expectToMarshal(struct{ M map[string]any }{M: mi}, `{"M":{"foo":"hello","bar":true,"baz":42}}`)
expectToMarshal(struct{ M *map[string]any }{M: &mi}, `{"M":{"foo":"hello","bar":true,"baz":42}}`)
})

It("marshals maps with string values", func() {
Expand All @@ -200,8 +200,8 @@ var _ = Describe("Marshal", func() {
})

It("fails with invalid keys", func() {
mn := map[int]interface{}{4: 3}
expectToFail(struct{ M map[int]interface{} }{M: mn}, `maps must only have string keys for "map[int]interface {}" at field "M" (type "map[int]interface {}")`)
mn := map[int]any{4: 3}
expectToFail(struct{ M map[int]any }{M: mn}, `maps must only have string keys for "map[int]interface {}" at field "M" (type "map[int]interface {}")`)
})

It("marshals a map with keys that are string type definitions", func() {
Expand Down Expand Up @@ -284,14 +284,14 @@ var _ = Describe("Marshal", func() {
B *t `jsonry:",omitempty"`
C *[]string `jsonry:",omitempty"`
D *map[int]int `jsonry:",omitempty"`
E *interface{} `jsonry:",omitempty"`
E *any `jsonry:",omitempty"`
}{}
expectToMarshal(s, `{}`)
})

It("omits nil interface values", func() {
s := struct {
A interface{} `jsonry:",omitempty"`
A any `jsonry:",omitempty"`
B json.Marshaler `jsonry:",omitempty"`
}{}
expectToMarshal(s, `{}`)
Expand All @@ -318,8 +318,8 @@ var _ = Describe("Marshal", func() {

It("omits empty maps", func() {
s := struct {
A map[interface{}]interface{} `jsonry:",omitempty"`
D map[int]int `jsonry:",omitempty"`
A map[any]any `jsonry:",omitempty"`
D map[int]int `jsonry:",omitempty"`
}{
D: make(map[int]int),
}
Expand Down
Loading