diff --git a/validator.go b/validator.go index 7cfcd4d..8a7e686 100644 --- a/validator.go +++ b/validator.go @@ -3,6 +3,7 @@ package validator import ( "fmt" "reflect" + "strconv" ) const ( @@ -20,6 +21,7 @@ type validate struct { isPartial bool hasExcludes bool includeExclude map[string]struct{} // reset only if StructPartial or StructExcept are called, no need otherwise + misc []byte // StructLevel & FieldLevel fields slflParent reflect.Value @@ -203,13 +205,48 @@ OUTER: switch kind { case reflect.Slice, reflect.Array: + var nm string + + // TODO: cache pool &cField for i := 0; i < current.Len(); i++ { - v.traverseField(parent, current.Index(i), ns, structNs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct) + + v.misc = append(v.misc[0:0], cf.Name...) + v.misc = append(v.misc, '[') + v.misc = strconv.AppendInt(v.misc, int64(i), 10) + v.misc = append(v.misc, ']') + + nm = string(v.misc) + + v.misc = append(v.misc[0:0], cf.AltName...) + v.misc = append(v.misc, '[') + v.misc = strconv.AppendInt(v.misc, int64(i), 10) + v.misc = append(v.misc, ']') + + v.traverseField(parent, current.Index(i), ns, structNs, &cField{Name: nm, AltName: string(v.misc)}, ct) } case reflect.Map: + + var nm string + var pv string + for _, key := range current.MapKeys() { - v.traverseField(parent, current.MapIndex(key), ns, structNs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct) + + pv = fmt.Sprintf("%v", key.Interface()) + + v.misc = append(v.misc[0:0], cf.Name...) + v.misc = append(v.misc, '[') + v.misc = append(v.misc, pv...) + v.misc = append(v.misc, ']') + + nm = string(v.misc) + + v.misc = append(v.misc[0:0], cf.AltName...) + v.misc = append(v.misc, '[') + v.misc = append(v.misc, pv...) + v.misc = append(v.misc, ']') + + v.traverseField(parent, current.MapIndex(key), ns, structNs, &cField{Name: nm, AltName: string(v.misc)}, ct) } default: @@ -222,7 +259,7 @@ OUTER: case typeOr: - errTag := make([]byte, 0, 64) + v.misc = v.misc[0:0] for { @@ -248,8 +285,8 @@ OUTER: } } - errTag = append(errTag, '|') - errTag = append(errTag, ct.tag...) + v.misc = append(v.misc, '|') + v.misc = append(v.misc, ct.tag...) if ct.next == nil { // if we get here, no valid 'or' value and no more tags @@ -275,8 +312,8 @@ OUTER: v.errs = append(v.errs, &fieldError{ - tag: string(errTag)[1:], - actualTag: string(errTag)[1:], + tag: string(v.misc)[1:], + actualTag: string(v.misc)[1:], ns: string(append(ns, cf.AltName...)), structNs: string(append(structNs, cf.Name...)), field: cf.AltName, diff --git a/validator_instance.go b/validator_instance.go index 0e68290..1e6b53d 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -89,8 +89,11 @@ func New() *Validate { v.pool = &sync.Pool{ New: func() interface{} { return &validate{ - v: v, - errs: make(ValidationErrors, 0, 4), + v: v, + errs: make(ValidationErrors, 0, 4), + ns: make([]byte, 0, 64), + actualNs: make([]byte, 0, 64), + misc: make([]byte, 32), } }, } @@ -209,9 +212,10 @@ func (v *Validate) Struct(s interface{}) (err error) { vd.top = top vd.isPartial = false // vd.hasExcludes = false // only need to reset in StructPartial and StructExcept - vd.validateStruct(top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil) + // fmt.Println(cap(vd.ns)) + if len(vd.errs) > 0 { err = vd.errs vd.errs = nil diff --git a/validator_test.go b/validator_test.go index 7a8ce21..11817c6 100644 --- a/validator_test.go +++ b/validator_test.go @@ -237,7 +237,7 @@ func StructValidationTestStructSuccess(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "good value" { - sl.ReportError(reflect.ValueOf(st.String), "StringVal", "String", "badvalueteststruct") + sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct") } } @@ -246,7 +246,7 @@ func StructValidationTestStruct(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { - sl.ReportError(reflect.ValueOf(st.String), "StringVal", "String", "badvalueteststruct") + sl.ReportError(st.String, "StringVal", "String", "badvalueteststruct") } } @@ -255,7 +255,7 @@ func StructValidationNoTestStructCustomName(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { - sl.ReportError(reflect.ValueOf(st.String), "String", "", "badvalueteststruct") + sl.ReportError(st.String, "String", "", "badvalueteststruct") } } @@ -264,7 +264,7 @@ func StructValidationTestStructInvalid(sl StructLevel) { st := sl.Current().Interface().(TestStruct) if st.String != "bad value" { - sl.ReportError(reflect.ValueOf(nil), "StringVal", "String", "badvalueteststruct") + sl.ReportError(nil, "StringVal", "String", "badvalueteststruct") } }