Skip to content

Commit

Permalink
Reflectutils (#14)
Browse files Browse the repository at this point in the history
* use reflectutils for simple unpacking

* array unpacking

* lint
  • Loading branch information
muir authored Nov 2, 2021
1 parent cda63e7 commit a518ffa
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 56 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.15
require (
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f
github.com/gorilla/mux v1.8.0
github.com/muir/reflectutils v0.0.1
github.com/muir/reflectutils v0.0.2
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210913180222-943fd674d43e
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/muir/reflectutils v0.0.1 h1:PJpRSMDo81CKXxfXe7Ny3OugmYoX3l0NkhtUwsj3AFg=
github.com/muir/reflectutils v0.0.1/go.mod h1:lCtGIbDtqCcsroEYyz7Qt5ZFN4NdYNLLjYXo2HKqzWk=
github.com/muir/reflectutils v0.0.2 h1:tNiAng3RR60nBnmvj+pxCRmgRhSG5Pc2JV1kwILXcys=
github.com/muir/reflectutils v0.0.2/go.mod h1:hyMWDtoeNsc1FTq9qlXsbwDzbwp3A3M8zbRNKDzvSmc=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
95 changes: 40 additions & 55 deletions nvelope/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ func mapUnpack(
return nil
}

func arrayUnpack(
func sliceUnpack(
from string, f reflect.Value,
singleUnpack func(from string, target reflect.Value, value string) error,
values []string,
Expand All @@ -610,6 +610,27 @@ func arrayUnpack(
return nil
}

func arrayUnpack(
from string, f reflect.Value,
singleUnpack func(from string, target reflect.Value, value string) error,
values []string,
) error {
arrayLen := f.Len()
if len(values) > arrayLen {
return errors.New("too many values for fixed length array")
}
for i, value := range values {
err := singleUnpack(from, f.Index(i), value)
if err != nil {
return err
}
}
for k := len(values); k < arrayLen; k++ {
f.Index(k).Set(reflect.Zero(f.Index(0).Type()))
}
return nil
}

type unpack struct {
createMe bool
single func(from string, target reflect.Value, value string) error
Expand Down Expand Up @@ -678,58 +699,21 @@ func getUnpacker(
return unpacker.single(from, target.Elem(), value)
}}, nil
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return unpack{single: func(from string, target reflect.Value, value string) error {
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return errors.Wrapf(err, "decode %s %s", from, name)
}
target.SetInt(i)
return nil
}}, nil
case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return unpack{single: func(from string, target reflect.Value, value string) error {
i, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return errors.Wrapf(err, "decode %s %s", from, name)
}
target.SetUint(i)
return nil
}}, nil
case reflect.Float32, reflect.Float64:
return unpack{single: func(from string, target reflect.Value, value string) error {
f, err := strconv.ParseFloat(value, 64)
if err != nil {
return errors.Wrapf(err, "decode %s %s", from, name)
}
target.SetFloat(f)
return nil
}}, nil
case reflect.String:
return unpack{single: func(_ string, target reflect.Value, value string) error {
target.SetString(value)
return nil
}}, nil
case reflect.Complex64, reflect.Complex128:
return unpack{single: func(from string, target reflect.Value, value string) error {
c, err := strconv.ParseComplex(value, 128)
if err != nil {
return errors.Wrapf(err, "decode %s %s", from, name)
}
target.SetComplex(c)
return nil
}}, nil
case reflect.Bool:
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64,
reflect.String,
reflect.Complex64, reflect.Complex128,
reflect.Bool:
f, err := reflectutils.MakeStringSetter(fieldType)
if err != nil {
return unpack{}, errors.Wrapf(err, "Cannot decode into %s, %s", fieldName, fieldType)
}
return unpack{single: func(from string, target reflect.Value, value string) error {
b, err := strconv.ParseBool(value)
if err != nil {
return errors.Wrapf(err, "decode %s %s", from, name)
}
target.SetBool(b)
return nil
return errors.Wrapf(f(target, value), "decode %s %s", from, name)
}}, nil

case reflect.Slice:
case reflect.Slice, reflect.Array:
switch base {
case "cookie", "path":
if tags.delimiter != "," {
Expand All @@ -747,19 +731,23 @@ func getUnpacker(
if err != nil {
return unpack{}, err
}
unslicer := sliceUnpack
if fieldType.Kind() == reflect.Array {
unslicer = arrayUnpack
}
switch base {
case "query", "header":
if tags.explode {
return unpack{
multi: func(from string, target reflect.Value, values []string) error {
return arrayUnpack(from, target, singleUnpack.single, values)
return unslicer(from, target, singleUnpack.single, values)
},
}, nil
}
}
return unpack{single: func(from string, target reflect.Value, value string) error {
values := strings.Split(value, tags.delimiter)
return arrayUnpack(from, target, singleUnpack.single, values)
return unslicer(from, target, singleUnpack.single, values)
}}, nil

case reflect.Struct:
Expand Down Expand Up @@ -855,9 +843,6 @@ func getUnpacker(
return mapUnpack(from, target, keyUnpack.single, elementUnpack.single, values)
}}, nil

case reflect.Array:
// TODO: handle arrays
fallthrough
case reflect.Chan, reflect.Interface, reflect.UnsafePointer, reflect.Func, reflect.Invalid:
fallthrough
default:
Expand Down
2 changes: 2 additions & 0 deletions nvelope/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func TestDecodeQueryComplexParameters(t *testing.T) {
Int32Slice *[]*int8 `json:",omitempty" nvelope:"query,name=int32slice,explode=false,delimiter=pipe"`
MapIntBool map[int]bool `json:",omitempty" nvelope:"query,name=mapintbool,explode=false"`
MapIntString map[int]string `json:",omitempty" nvelope:"query,name=mapintstring,deepObject=true"`
IntArrayP *[3]int `json:",omitempty" nvelope:"query,name=intarrayp,explode=false"`
Emb1 *struct {
Int int `json:",omitempty" nvelope:"eint"`
Int8 int8 `json:",omitempty" nvelope:"eint8"`
Expand All @@ -118,6 +119,7 @@ func TestDecodeQueryComplexParameters(t *testing.T) {
assert.Equal(t, `200->{"MapIntString":{"-9":"hi","7":"bye"}}`, do("/x?mapintstring[7]=bye&mapintstring[-9]=hi"))
assert.Equal(t, `200->{"Emb1":{"Int":192,"Int8":-3,"String":"foo"}}`, do("/x?emb1=eint,192,eint8,-3,String,foo"))
assert.Equal(t, `200->{"Emb2":{"Int":193,"Int8":-4,"String":"bar"}}`, do("/x?emb2[eint]=193&emb2[eint8]=-4&emb2[String]=bar"))
assert.Equal(t, `200->{"IntArrayP":[7,22,0]}`, do("/x?intarrayp=7,22"))
}

type Foo string
Expand Down

0 comments on commit a518ffa

Please sign in to comment.