Godeps/_workspace/src/gopkg.in/bluesuncorp/validator.v5/validator.go
func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}) *StructErrors {

	structValue := reflect.ValueOf(s)

	if structValue.Kind() == reflect.Ptr && !structValue.IsNil() {
		return v.structRecursive(top, current, structValue.Elem().Interface())
	}

	if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface {
		panic("interface passed for validation is not a struct")
	}

	structType := reflect.TypeOf(s)

	var structName string
	var numFields int
	var cs *cachedStruct
	var isCached bool

	cs, isCached = structCache.Get(structType)

	if isCached {
		structName = cs.name
		numFields = cs.children
	} else {
		structName = structType.Name()
		numFields = structValue.NumField()
		cs = &cachedStruct{name: structName, children: numFields}
	}

	validationErrors := structPool.Get().(*StructErrors)
	validationErrors.Struct = structName

	for i := 0; i < numFields; i++ {

		var valueField reflect.Value
		var cField *cachedField
		var typeField reflect.StructField

		if isCached {
			cField = cs.fields[i]
			valueField = structValue.Field(cField.index)

			if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
				valueField = valueField.Elem()
			}
		} else {
			valueField = structValue.Field(i)

			if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
				valueField = valueField.Elem()
			}

			typeField = structType.Field(i)

			cField = &cachedField{index: i, tag: typeField.Tag.Get(v.tagName), isTime: (valueField.Type() == reflect.TypeOf(time.Time{}) || valueField.Type() == reflect.TypeOf(&time.Time{}))}

			if cField.tag == noValidationTag {
				cs.children--
				continue
			}

			// if no validation and not a struct (which may containt fields for validation)
			if cField.tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) {
				cs.children--
				continue
			}

			cField.name = typeField.Name
			cField.kind = valueField.Kind()
			cField.typ = valueField.Type()
		}

		// this can happen if the first cache value was nil
		// but the second actually has a value
		if cField.kind == reflect.Ptr {
			cField.kind = valueField.Kind()
		}

		switch cField.kind {

		case reflect.Struct, reflect.Interface:

			if !unicode.IsUpper(rune(cField.name[0])) {
				cs.children--
				continue
			}

			if cField.isTime {

				if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
					validationErrors.Errors[fieldError.Field] = fieldError
					// free up memory reference
					fieldError = nil
				}

			} else {

				if strings.Contains(cField.tag, structOnlyTag) {
					cs.children--
					continue
				}

				if (valueField.Kind() == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {

					if strings.Contains(cField.tag, omitempty) {
						goto CACHEFIELD
					}

					tags := strings.Split(cField.tag, tagSeparator)

					if len(tags) > 0 {

						var param string
						vals := strings.SplitN(tags[0], tagKeySeparator, 2)

						if len(vals) > 1 {
							param = vals[1]
						}

						validationErrors.Errors[cField.name] = &FieldError{
							Field: cField.name,
							Tag:   vals[0],
							Param: param,
							Value: valueField.Interface(),
							Kind:  valueField.Kind(),
							Type:  valueField.Type(),
						}

						goto CACHEFIELD
					}
				}

				// if we get here, the field is interface and could be a struct or a field
				// and we need to check the inner type and validate
				if cField.kind == reflect.Interface {

					valueField = valueField.Elem()

					if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
						valueField = valueField.Elem()
					}

					if valueField.Kind() == reflect.Struct {
						goto VALIDATESTRUCT
					}

					// sending nil for cField as it was type interface and could be anything
					// each time and so must be calculated each time and can't be cached reliably
					if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, nil); fieldError != nil {
						validationErrors.Errors[fieldError.Field] = fieldError
						// free up memory reference
						fieldError = nil
					}

					goto CACHEFIELD
				}

			VALIDATESTRUCT:
				if structErrors := v.structRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil {
					validationErrors.StructErrors[cField.name] = structErrors
					// free up memory map no longer needed
					structErrors = nil
				}
			}

		case reflect.Slice, reflect.Array:
			cField.isSliceOrArray = true
			cField.sliceSubtype = cField.typ.Elem()
			cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{}))
			cField.sliceSubKind = cField.sliceSubtype.Kind()

			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}

		case reflect.Map:
			cField.isMap = true
			cField.mapSubtype = cField.typ.Elem()
			cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{}))
			cField.mapSubKind = cField.mapSubtype.Kind()

			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}

		default:
			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}
		}

	CACHEFIELD:
		if !isCached {
			cs.fields = append(cs.fields, cField)
		}
	}

	structCache.Set(structType, cs)

	if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 {
		structPool.Put(validationErrors)
		return nil
	}

	return validationErrors
}
func (v *Validate) structRecursive(top interface{}, current interface{}, s interface{}) *StructErrors {

	structValue := reflect.ValueOf(s)

	if structValue.Kind() == reflect.Ptr && !structValue.IsNil() {
		return v.structRecursive(top, current, structValue.Elem().Interface())
	}

	if structValue.Kind() != reflect.Struct && structValue.Kind() != reflect.Interface {
		panic("interface passed for validation is not a struct")
	}

	structType := reflect.TypeOf(s)

	var structName string
	var numFields int
	var cs *cachedStruct
	var isCached bool

	cs, isCached = structCache.Get(structType)

	if isCached {
		structName = cs.name
		numFields = cs.children
	} else {
		structName = structType.Name()
		numFields = structValue.NumField()
		cs = &cachedStruct{name: structName, children: numFields}
	}

	validationErrors := structPool.Get().(*StructErrors)
	validationErrors.Struct = structName

	for i := 0; i < numFields; i++ {

		var valueField reflect.Value
		var cField *cachedField
		var typeField reflect.StructField

		if isCached {
			cField = cs.fields[i]
			valueField = structValue.Field(cField.index)

			if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
				valueField = valueField.Elem()
			}
		} else {
			valueField = structValue.Field(i)

			if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
				valueField = valueField.Elem()
			}

			typeField = structType.Field(i)

			cField = &cachedField{index: i, tag: typeField.Tag.Get(v.tagName), isTime: (valueField.Type() == reflect.TypeOf(time.Time{}) || valueField.Type() == reflect.TypeOf(&time.Time{}))}

			if cField.tag == noValidationTag {
				cs.children--
				continue
			}

			// if no validation and not a struct (which may containt fields for validation)
			if cField.tag == "" && ((valueField.Kind() != reflect.Struct && valueField.Kind() != reflect.Interface) || valueField.Type() == reflect.TypeOf(time.Time{})) {
				cs.children--
				continue
			}

			cField.name = typeField.Name
			cField.kind = valueField.Kind()
			cField.typ = valueField.Type()
		}

		// this can happen if the first cache value was nil
		// but the second actually has a value
		if cField.kind == reflect.Ptr {
			cField.kind = valueField.Kind()
		}

		switch cField.kind {

		case reflect.Struct, reflect.Interface:

			if !unicode.IsUpper(rune(cField.name[0])) {
				cs.children--
				continue
			}

			if cField.isTime {

				if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
					validationErrors.Errors[fieldError.Field] = fieldError
					// free up memory reference
					fieldError = nil
				}

			} else {

				if strings.Contains(cField.tag, structOnlyTag) {
					cs.children--
					continue
				}

				if (valueField.Kind() == reflect.Ptr || cField.kind == reflect.Interface) && valueField.IsNil() {

					if strings.Contains(cField.tag, omitempty) {
						goto CACHEFIELD
					}

					tags := strings.Split(cField.tag, tagSeparator)

					if len(tags) > 0 {

						var param string
						vals := strings.SplitN(tags[0], tagKeySeparator, 2)

						if len(vals) > 1 {
							param = vals[1]
						}

						validationErrors.Errors[cField.name] = &FieldError{
							Field: cField.name,
							Tag:   vals[0],
							Param: param,
							Value: valueField.Interface(),
							Kind:  valueField.Kind(),
							Type:  valueField.Type(),
						}

						goto CACHEFIELD
					}
				}

				// if we get here, the field is interface and could be a struct or a field
				// and we need to check the inner type and validate
				if cField.kind == reflect.Interface {

					valueField = valueField.Elem()

					if valueField.Kind() == reflect.Ptr && !valueField.IsNil() {
						valueField = valueField.Elem()
					}

					if valueField.Kind() == reflect.Struct {
						goto VALIDATESTRUCT
					}

					// sending nil for cField as it was type interface and could be anything
					// each time and so must be calculated each time and can't be cached reliably
					if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, nil); fieldError != nil {
						validationErrors.Errors[fieldError.Field] = fieldError
						// free up memory reference
						fieldError = nil
					}

					goto CACHEFIELD
				}

			VALIDATESTRUCT:
				if structErrors := v.structRecursive(top, valueField.Interface(), valueField.Interface()); structErrors != nil {
					validationErrors.StructErrors[cField.name] = structErrors
					// free up memory map no longer needed
					structErrors = nil
				}
			}

		case reflect.Slice, reflect.Array:
			cField.isSliceOrArray = true
			cField.sliceSubtype = cField.typ.Elem()
			cField.isTimeSubtype = (cField.sliceSubtype == reflect.TypeOf(time.Time{}) || cField.sliceSubtype == reflect.TypeOf(&time.Time{}))
			cField.sliceSubKind = cField.sliceSubtype.Kind()

			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}

		case reflect.Map:
			cField.isMap = true
			cField.mapSubtype = cField.typ.Elem()
			cField.isTimeSubtype = (cField.mapSubtype == reflect.TypeOf(time.Time{}) || cField.mapSubtype == reflect.TypeOf(&time.Time{}))
			cField.mapSubKind = cField.mapSubtype.Kind()

			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}

		default:
			if fieldError := v.fieldWithNameAndValue(top, current, valueField.Interface(), cField.tag, cField.name, false, cField); fieldError != nil {
				validationErrors.Errors[fieldError.Field] = fieldError
				// free up memory reference
				fieldError = nil
			}
		}

	CACHEFIELD:
		if !isCached {
			cs.fields = append(cs.fields, cField)
		}
	}

	structCache.Set(structType, cs)

	if len(validationErrors.Errors) == 0 && len(validationErrors.StructErrors) == 0 {
		structPool.Put(validationErrors)
		return nil
	}

	return validationErrors
}
func ( v * Validate ) structRecursive ( top interface { } , current interface { } , s interface { } ) * StructErrors { structValue := reflect . ValueOf ( s ) if structValue . Kind ( ) == reflect . Ptr && ! structValue . IsNil ( ) { return v . structRecursive ( top , current , structValue . Elem ( ) . Interface ( ) ) } if structValue . Kind ( ) != reflect . Struct && structValue . Kind ( ) != reflect . Interface { panic ( " " ) } structType := reflect . TypeOf ( s ) var structName string var numFields int var cs * cachedStruct var isCached bool cs , isCached = structCache . Get ( structType ) if isCached { structName = cs . name numFields = cs . children } else { structName = structType . Name ( ) numFields = structValue . NumField ( ) cs = & cachedStruct { name : structName , children : numFields } } validationErrors := structPool . Get ( ) . ( * StructErrors ) validationErrors . Struct = structName for i := 0 ; i < numFields ; i ++ { var valueField reflect . Value var cField * cachedField var typeField reflect . StructField if isCached { cField = cs . fields [ i ] valueField = structValue . Field ( cField . index ) if valueField . Kind ( ) == reflect . Ptr && ! valueField . IsNil ( ) { valueField = valueField . Elem ( ) } } else { valueField = structValue . Field ( i ) if valueField . Kind ( ) == reflect . Ptr && ! valueField . IsNil ( ) { valueField = valueField . Elem ( ) } typeField = structType . Field ( i ) cField = & cachedField { index : i , tag : typeField . Tag . Get ( v . tagName ) , isTime : ( valueField . Type ( ) == reflect . TypeOf ( time . Time { } ) || valueField . Type ( ) == reflect . TypeOf ( & time . Time { } ) ) } if cField . tag == noValidationTag { cs . children -- continue } // if no validation and not a struct (which may containt fields for validation) if cField . tag == " " && ( ( valueField . Kind ( ) != reflect . Struct && valueField . Kind ( ) != reflect . Interface ) || valueField . Type ( ) == reflect . TypeOf ( time . Time { } ) ) { cs . children -- continue } cField . name = typeField . Name cField . kind = valueField . Kind ( ) cField . typ = valueField . Type ( ) } // this can happen if the first cache value was nil // but the second actually has a value if cField . kind == reflect . Ptr { cField . kind = valueField . Kind ( ) } switch cField . kind { case reflect . Struct , reflect . Interface : if ! unicode . IsUpper ( rune ( cField . name [ 0 ] ) ) { cs . children -- continue } if cField . isTime { if fieldError := v . fieldWithNameAndValue ( top , current , valueField . Interface ( ) , cField . tag , cField . name , false , cField ) ; fieldError != nil { validationErrors . Errors [ fieldError . Field ] = fieldError // free up memory reference fieldError = nil } } else { if strings . Contains ( cField . tag , structOnlyTag ) { cs . children -- continue } if ( valueField . Kind ( ) == reflect . Ptr || cField . kind == reflect . Interface ) && valueField . IsNil ( ) { if strings . Contains ( cField . tag , omitempty ) { goto CACHEFIELD } tags := strings . Split ( cField . tag , tagSeparator ) if len ( tags ) > 0 { var param string vals := strings . SplitN ( tags [ 0 ] , tagKeySeparator , 2 ) if len ( vals ) > 1 { param = vals [ 1 ] } validationErrors . Errors [ cField . name ] = & FieldError { Field : cField . name , Tag : vals [ 0 ] , Param : param , Value : valueField . Interface ( ) , Kind : valueField . Kind ( ) , Type : valueField . Type ( ) , } goto CACHEFIELD } } // if we get here, the field is interface and could be a struct or a field // and we need to check the inner type and validate if cField . kind == reflect . Interface { valueField = valueField . Elem ( ) if valueField . Kind ( ) == reflect . Ptr && ! valueField . IsNil ( ) { valueField = valueField . Elem ( ) } if valueField . Kind ( ) == reflect . Struct { goto VALIDATESTRUCT } // sending nil for cField as it was type interface and could be anything // each time and so must be calculated each time and can't be cached reliably if fieldError := v . fieldWithNameAndValue ( top , current , valueField . Interface ( ) , cField . tag , cField . name , false , nil ) ; fieldError != nil { validationErrors . Errors [ fieldError . Field ] = fieldError // free up memory reference fieldError = nil } goto CACHEFIELD } VALIDATESTRUCT : if structErrors := v . structRecursive ( top , valueField . Interface ( ) , valueField . Interface ( ) ) ; structErrors != nil { validationErrors . StructErrors [ cField . name ] = structErrors // free up memory map no longer needed structErrors = nil } } case reflect . Slice , reflect . Array : cField . isSliceOrArray = true cField . sliceSubtype = cField . typ . Elem ( ) cField . isTimeSubtype = ( cField . sliceSubtype == reflect . TypeOf ( time . Time { } ) || cField . sliceSubtype == reflect . TypeOf ( & time . Time { } ) ) cField . sliceSubKind = cField . sliceSubtype . Kind ( ) if fieldError := v . fieldWithNameAndValue ( top , current , valueField . Interface ( ) , cField . tag , cField . name , false , cField ) ; fieldError != nil { validationErrors . Errors [ fieldError . Field ] = fieldError // free up memory reference fieldError = nil } case reflect . Map : cField . isMap = true cField . mapSubtype = cField . typ . Elem ( ) cField . isTimeSubtype = ( cField . mapSubtype == reflect . TypeOf ( time . Time { } ) || cField . mapSubtype == reflect . TypeOf ( & time . Time { } ) ) cField . mapSubKind = cField . mapSubtype . Kind ( ) if fieldError := v . fieldWithNameAndValue ( top , current , valueField . Interface ( ) , cField . tag , cField . name , false , cField ) ; fieldError != nil { validationErrors . Errors [ fieldError . Field ] = fieldError // free up memory reference fieldError = nil } default : if fieldError := v . fieldWithNameAndValue ( top , current , valueField . Interface ( ) , cField . tag , cField . name , false , cField ) ; fieldError != nil { validationErrors . Errors [ fieldError . Field ] = fieldError // free up memory reference fieldError = nil } } CACHEFIELD : if ! isCached { cs . fields = append ( cs . fields , cField ) } } structCache . Set ( structType , cs ) if len ( validationErrors . Errors ) == 0 && len ( validationErrors . StructErrors ) == 0 { structPool . Put ( validationErrors ) return nil } return validationErrors }
// structRecursive validates a struct recursivly and passes the top level and current struct around for use in validator functions and returns a struct containing the errors
structRecursive validates a struct recursivly and passes the top level and current struct around for use in validator functions and returns a struct containing the errors