@@ -20,6 +20,7 @@ import (
2020)
2121
2222const (
23+ utf8HexComma = "0x2C"
2324 tagSeparator = ","
2425 orSeparator = "|"
2526 noValidationTag = "-"
@@ -30,6 +31,48 @@ const (
3031 structErrMsg = "Struct:%s\n "
3132)
3233
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+
3376type cachedTags struct {
3477 keyVals [][]string
3578 isOrVal bool
@@ -187,6 +230,9 @@ type Validate struct {
187230
188231// New creates a new Validate instance for use.
189232func New (tagName string , funcs map [string ]Func ) * Validate {
233+
234+ structPool = newPool (10 )
235+
190236 return & Validate {
191237 tagName : tagName ,
192238 validationFuncs : funcs ,
@@ -200,6 +246,16 @@ func (v *Validate) SetTag(tagName string) {
200246 v .tagName = tagName
201247}
202248
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+
203259// AddFunction adds a validation Func to a Validate's map of validators denoted by the key
204260// NOTE: if the key already exists, it will get replaced.
205261// NOTE: this method is not thread-safe
@@ -259,11 +315,8 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
259315 structCache .Set (structType , cs )
260316 }
261317
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
267320
268321 for i := 0 ; i < numFields ; i ++ {
269322
@@ -359,6 +412,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
359412 }
360413
361414 if len (validationErrors .Errors ) == 0 && len (validationErrors .StructErrors ) == 0 {
415+ structPool .Return (validationErrors )
362416 return nil
363417 }
364418
@@ -428,7 +482,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
428482 cField .tags = append (cField .tags , cTag )
429483
430484 for i , val := range orVals {
431- vals := strings .Split (val , tagKeySeparator )
485+ vals := strings .SplitN (val , tagKeySeparator , 2 )
432486
433487 key := strings .TrimSpace (vals [0 ])
434488
@@ -438,7 +492,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
438492
439493 param := ""
440494 if len (vals ) > 1 {
441- param = vals [1 ]
495+ param = strings . Replace ( vals [1 ], utf8HexComma , "," , - 1 )
442496 }
443497
444498 cTag .keyVals [i ] = []string {key , param }
0 commit comments