@@ -20,6 +20,7 @@ import (
20
20
)
21
21
22
22
const (
23
+ utf8HexComma = "0x2C"
23
24
tagSeparator = ","
24
25
orSeparator = "|"
25
26
noValidationTag = "-"
@@ -30,6 +31,48 @@ const (
30
31
structErrMsg = "Struct:%s\n "
31
32
)
32
33
34
+ var structPool * pool
35
+
36
+ // Pool holds a channelStructErrors.
37
+ type pool struct {
38
+ pool chan * StructErrors
39
+ }
40
+
41
+ // NewPool creates a new pool of Clients.
42
+ func newPool (max int ) * pool {
43
+ return & pool {
44
+ pool : make (chan * StructErrors , max ),
45
+ }
46
+ }
47
+
48
+ // Borrow a StructErrors from the pool.
49
+ func (p * pool ) Borrow () * StructErrors {
50
+ var c * StructErrors
51
+
52
+ select {
53
+ case c = <- p .pool :
54
+ default :
55
+ c = & StructErrors {
56
+ Errors : map [string ]* FieldError {},
57
+ StructErrors : map [string ]* StructErrors {},
58
+ }
59
+ }
60
+
61
+ return c
62
+ }
63
+
64
+ // Return returns a StructErrors to the pool.
65
+ func (p * pool ) Return (c * StructErrors ) {
66
+
67
+ // c.Struct = ""
68
+
69
+ select {
70
+ case p .pool <- c :
71
+ default :
72
+ // let it go, let it go...
73
+ }
74
+ }
75
+
33
76
type cachedTags struct {
34
77
keyVals [][]string
35
78
isOrVal bool
@@ -187,6 +230,9 @@ type Validate struct {
187
230
188
231
// New creates a new Validate instance for use.
189
232
func New (tagName string , funcs map [string ]Func ) * Validate {
233
+
234
+ structPool = newPool (10 )
235
+
190
236
return & Validate {
191
237
tagName : tagName ,
192
238
validationFuncs : funcs ,
@@ -200,6 +246,16 @@ func (v *Validate) SetTag(tagName string) {
200
246
v .tagName = tagName
201
247
}
202
248
249
+ // SetStructPoolMax sets the struct pools max size. this may be usefull for fine grained
250
+ // performance tuning towards your application, however, the default should be fine for
251
+ // nearly all cases. only increase if you have a deeply nested struct structure.
252
+ // NOTE: this method is not thread-safe
253
+ // NOTE: this is only here to keep compatibility with v5, in v6 the method will be removed
254
+ // and the max pool size will be passed into the New function
255
+ func (v * Validate ) SetMaxStructPoolSize (max int ) {
256
+ structPool = newPool (max )
257
+ }
258
+
203
259
// AddFunction adds a validation Func to a Validate's map of validators denoted by the key
204
260
// NOTE: if the key already exists, it will get replaced.
205
261
// NOTE: this method is not thread-safe
@@ -259,11 +315,8 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
259
315
structCache .Set (structType , cs )
260
316
}
261
317
262
- validationErrors := & StructErrors {
263
- Struct : structName ,
264
- Errors : map [string ]* FieldError {},
265
- StructErrors : map [string ]* StructErrors {},
266
- }
318
+ validationErrors := structPool .Borrow ()
319
+ validationErrors .Struct = structName
267
320
268
321
for i := 0 ; i < numFields ; i ++ {
269
322
@@ -359,6 +412,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
359
412
}
360
413
361
414
if len (validationErrors .Errors ) == 0 && len (validationErrors .StructErrors ) == 0 {
415
+ structPool .Return (validationErrors )
362
416
return nil
363
417
}
364
418
@@ -428,7 +482,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
428
482
cField .tags = append (cField .tags , cTag )
429
483
430
484
for i , val := range orVals {
431
- vals := strings .Split (val , tagKeySeparator )
485
+ vals := strings .SplitN (val , tagKeySeparator , 2 )
432
486
433
487
key := strings .TrimSpace (vals [0 ])
434
488
@@ -438,7 +492,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
438
492
439
493
param := ""
440
494
if len (vals ) > 1 {
441
- param = vals [1 ]
495
+ param = strings . Replace ( vals [1 ], utf8HexComma , "," , - 1 )
442
496
}
443
497
444
498
cTag .keyVals [i ] = []string {key , param }
0 commit comments