Skip to content

Commit 2907b24

Browse files
Dean KarnDean Karn
authored andcommitted
add Encoder + Decoder Mode setting to allow Implicit, the default, or Explicit decoding or encoding
1 parent ec9eaa9 commit 2907b24

File tree

9 files changed

+83
-5
lines changed

9 files changed

+83
-5
lines changed

cache.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (s *structCacheMap) Set(key reflect.Type, value *cachedStruct) {
4444
s.m.Store(nm)
4545
}
4646

47-
func (s *structCacheMap) parseStruct(current reflect.Value, key reflect.Type, tagName string) *cachedStruct {
47+
func (s *structCacheMap) parseStruct(mode Mode, current reflect.Value, key reflect.Type, tagName string) *cachedStruct {
4848

4949
s.lock.Lock()
5050

@@ -76,6 +76,10 @@ func (s *structCacheMap) parseStruct(current reflect.Value, key reflect.Type, ta
7676
continue
7777
}
7878

79+
if mode == ModeExplicit && len(name) == 0 {
80+
continue
81+
}
82+
7983
if len(name) == 0 {
8084
name = fld.Name
8185
}

cache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestDecoderMultipleSimultaniousParseStructRequests(t *testing.T) {
4343
for i := 0; i < 200; i++ {
4444
go func() {
4545
<-proceed
46-
s := sc.parseStruct(sv, typ, "form")
46+
s := sc.parseStruct(ModeImplicit, sv, typ, "form")
4747
NotEqual(t, s, nil)
4848
}()
4949
}

decoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func (d *decoder) traverseStruct(v reflect.Value, typ reflect.Type, namespace []
149149
// including tags
150150
s, ok := d.d.structCache.Get(typ)
151151
if !ok {
152-
s = d.d.structCache.parseStruct(v, typ, d.d.tagName)
152+
s = d.d.structCache.parseStruct(d.d.mode, v, typ, d.d.tagName)
153153
}
154154

155155
for _, f := range s.fields {

decoder_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,3 +1428,26 @@ func TestDecoderPointerToPointer(t *testing.T) {
14281428
Equal(t, err, nil)
14291429
Equal(t, tst.Value, "testVal")
14301430
}
1431+
1432+
func TestDecoderExplicit(t *testing.T) {
1433+
1434+
type Test struct {
1435+
Name string `form:"Name"`
1436+
Age int
1437+
}
1438+
1439+
values := map[string][]string{
1440+
"Name": {"Joeybloggs"},
1441+
"Age": {"3"},
1442+
}
1443+
1444+
var test Test
1445+
1446+
d := NewDecoder()
1447+
d.SetMode(ModeExplicit)
1448+
1449+
err := d.Decode(&test, values)
1450+
Equal(t, err, nil)
1451+
Equal(t, test.Name, "Joeybloggs")
1452+
Equal(t, test.Age, 0)
1453+
}

encoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (e *encoder) traverseStruct(v reflect.Value, namespace []byte, idx int) {
4545
// including tags
4646
s, ok := e.e.structCache.Get(typ)
4747
if !ok {
48-
s = e.e.structCache.parseStruct(v, typ, e.e.tagName)
48+
s = e.e.structCache.parseStruct(e.e.mode, v, typ, e.e.tagName)
4949
}
5050

5151
for _, f := range s.fields {

encoder_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,3 +1234,24 @@ func TestEncoderPanicsAndBadValues(t *testing.T) {
12341234
Equal(t, ok, true)
12351235
Equal(t, err.Error(), "form: Encode(nil *form.TestStruct)")
12361236
}
1237+
1238+
func TestEncoderExplicit(t *testing.T) {
1239+
1240+
type Test struct {
1241+
Name string `form:"Name"`
1242+
Age int
1243+
}
1244+
1245+
test := &Test{
1246+
Name: "Joeybloggs",
1247+
Age: 3,
1248+
}
1249+
1250+
encoder := NewEncoder()
1251+
encoder.SetMode(ModeExplicit)
1252+
1253+
values, err := encoder.Encode(test)
1254+
Equal(t, err, nil)
1255+
Equal(t, len(values), 1)
1256+
Equal(t, values["Name"][0], "Joeybloggs")
1257+
}

form.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,17 @@ const (
1616
var (
1717
timeType = reflect.TypeOf(time.Time{})
1818
)
19+
20+
// Mode specifies which mode the form decoder is to run
21+
type Mode uint8
22+
23+
const (
24+
25+
// ModeImplicit tries to parse values for all
26+
// fields that do not have an ignore '-' tag
27+
ModeImplicit Mode = iota
28+
29+
// ModeExplicit only parses values for field with a field tag
30+
// and that tag is not the ignore '-' tag
31+
ModeExplicit
32+
)

form_decoder.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type dataMap []*recursiveData
6464
// Decoder is the main decode instance
6565
type Decoder struct {
6666
tagName string
67+
mode Mode
6768
structCache *structCacheMap
6869
customTypeFuncs map[reflect.Type]DecodeCustomTypeFunc
6970
maxArraySize int
@@ -75,6 +76,7 @@ func NewDecoder() *Decoder {
7576

7677
d := &Decoder{
7778
tagName: "form",
79+
mode: ModeImplicit,
7880
structCache: newStructCacheMap(),
7981
maxArraySize: 10000,
8082
}
@@ -95,6 +97,12 @@ func (d *Decoder) SetTagName(tagName string) {
9597
d.tagName = tagName
9698
}
9799

100+
// SetMode sets the mode the decoder should run
101+
// Default is ModeImplicit
102+
func (d *Decoder) SetMode(mode Mode) {
103+
d.mode = mode
104+
}
105+
98106
// SetMaxArraySize sets maximum array size that can be created.
99107
// This limit is for the array indexing this library supports to
100108
// avoid potential DOS or man-in-the-middle attacks using an unusually

form_encoder.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func (e *InvalidEncodeError) Error() string {
4545
// Encoder is the main encode instance
4646
type Encoder struct {
4747
tagName string
48+
mode Mode
4849
structCache *structCacheMap
4950
customTypeFuncs map[reflect.Type]EncodeCustomTypeFunc
5051
dataPool *sync.Pool
@@ -55,6 +56,7 @@ func NewEncoder() *Encoder {
5556

5657
e := &Encoder{
5758
tagName: "form",
59+
mode: ModeImplicit,
5860
structCache: newStructCacheMap(),
5961
}
6062

@@ -68,12 +70,18 @@ func NewEncoder() *Encoder {
6870
return e
6971
}
7072

71-
// SetTagName sets the given tag name to be used by the decoder.
73+
// SetTagName sets the given tag name to be used by the encoder.
7274
// Default is "form"
7375
func (e *Encoder) SetTagName(tagName string) {
7476
e.tagName = tagName
7577
}
7678

79+
// SetMode sets the mode the encoder should run
80+
// Default is ModeImplicit
81+
func (e *Encoder) SetMode(mode Mode) {
82+
e.mode = mode
83+
}
84+
7785
// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
7886
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any parsing
7987
func (e *Encoder) RegisterCustomTypeFunc(fn EncodeCustomTypeFunc, types ...interface{}) {

0 commit comments

Comments
 (0)