Skip to content

Commit

Permalink
Marshal: refactor to simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
blgm committed May 6, 2020
1 parent b86ac8a commit 8c5a726
Showing 1 changed file with 29 additions and 54 deletions.
83 changes: 29 additions & 54 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,6 @@ import (
"code.cloudfoundry.org/jsonry/internal/context"
)

type sort uint

const (
basicSort sort = iota
structSort
listSort
mapSort
jsonMarshalerSort
jsonryMarshalerSort
unsupportedSort
)

var (
jsonMarshalerInterface = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
jsonryMarshalerInterface = reflect.TypeOf((*Marshaler)(nil)).Elem()
)

// Marshaler is the interface implemented by types that
// can marshal themselves into a Go type that JSONry can handle.
type Marshaler interface {
Expand All @@ -47,34 +30,40 @@ func Marshal(input interface{}) ([]byte, error) {
}

func marshal(ctx context.Context, in reflect.Value) (r interface{}, err error) {
switch sortOf(in) {
case basicSort:
ut := underlyingType(in)
uv := underlyingValue(in)
k := uv.Kind()

switch {
case ut.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()):
r, err = marshalJSONMarshaler(ctx, uv)
case ut.Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()):
panic("not done yet")
case k == reflect.Struct:
r, err = marshalStruct(ctx, uv)
case isBasicType(k):
r = in.Interface()
case structSort:
r, err = marshalStruct(ctx, in)
case listSort:
r, err = marshalList(ctx, in)
case mapSort:
r, err = marshalMap(ctx, in)
case jsonMarshalerSort:
r, err = marshalJSONMarshaler(ctx, in)
case k == reflect.Slice || k == reflect.Array:
r, err = marshalList(ctx, uv)
case k == reflect.Map:
r, err = marshalMap(ctx, uv)
default:
err = NewUnsupportedTypeError(ctx, underlyingType(in))
err = NewUnsupportedTypeError(ctx, ut)
}

return
}

func marshalStruct(ctx context.Context, in reflect.Value) (map[string]interface{}, error) {
out := make(map[string]interface{})

s := underlyingValue(in)
t := s.Type()
t := in.Type()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
private := f.PkgPath != ""

if !private {
r, err := marshal(ctx.WithField(f.Name, f.Type), s.Field(i))
r, err := marshal(ctx.WithField(f.Name, f.Type), in.Field(i))
if err != nil {
return nil, err
}
Expand All @@ -89,10 +78,9 @@ func marshalStruct(ctx context.Context, in reflect.Value) (map[string]interface{
func marshalList(ctx context.Context, in reflect.Value) ([]interface{}, error) {
var out []interface{}

list := underlyingValue(in)
for i := 0; i < list.Len(); i++ {
ctx := ctx.WithIndex(i, list.Type())
r, err := marshal(ctx, list.Index(i))
for i := 0; i < in.Len(); i++ {
ctx := ctx.WithIndex(i, in.Type())
r, err := marshal(ctx, in.Index(i))
if err != nil {
return nil, err
}
Expand All @@ -105,7 +93,7 @@ func marshalList(ctx context.Context, in reflect.Value) ([]interface{}, error) {
func marshalMap(ctx context.Context, in reflect.Value) (map[string]interface{}, error) {
out := make(map[string]interface{})

iter := underlyingValue(in).MapRange()
iter := in.MapRange()
for iter.Next() {
k := iter.Key()
if k.Kind() != reflect.String {
Expand All @@ -125,7 +113,7 @@ func marshalMap(ctx context.Context, in reflect.Value) (map[string]interface{},
}

func marshalJSONMarshaler(ctx context.Context, in reflect.Value) (interface{}, error) {
t := underlyingValue(in).MethodByName("MarshalJSON").Call(nil)
t := in.MethodByName("MarshalJSON").Call(nil)

if !t[1].IsNil() {
return nil, fmt.Errorf("error from MarshaJSON() call %s: %w", ctx, toError(t[1]))
Expand All @@ -140,28 +128,15 @@ func marshalJSONMarshaler(ctx context.Context, in reflect.Value) (interface{}, e
return r, nil
}

func sortOf(v reflect.Value) sort {
switch {
case underlyingType(v).Implements(jsonMarshalerInterface):
return jsonMarshalerSort
case v.Type().Implements(jsonryMarshalerInterface):
return jsonryMarshalerSort
}

switch underlyingValue(v).Kind() {
case reflect.Struct:
return structSort
func isBasicType(k reflect.Kind) bool {
switch k {
case reflect.String, reflect.Bool,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
return basicSort
case reflect.Slice, reflect.Array:
return listSort
case reflect.Map:
return mapSort
return true
default:
return unsupportedSort
return false
}
}

Expand Down

0 comments on commit 8c5a726

Please sign in to comment.