func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
	v.initCheck()
	if v.structLevelFuncs == nil {
		v.structLevelFuncs = map[reflect.Type]StructLevelFunc{}
	}
	for _, t := range types {
		v.structLevelFuncs[reflect.TypeOf(t)] = fn
	}
	v.hasStructLevelFuncs = true
}
RegisterStructValidation registers a StructLevelFunc against a number of types
NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
package validator
import (
	"bytes"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"sync"
	"time"
)
const (
	utf8HexComma            = "0x2C"
	utf8Pipe                = "0x7C"
	tagSeparator            = ","
	orSeparator             = "|"
	tagKeySeparator         = "="
	structOnlyTag           = "structonly"
	noStructLevelTag        = "nostructlevel"
	omitempty               = "omitempty"
	skipValidationTag       = "-"
	diveTag                 = "dive"
	existsTag               = "exists"
	fieldErrMsg             = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"
	arrayIndexFieldName     = "%s" + leftBracket + "%d" + rightBracket
	mapIndexFieldName       = "%s" + leftBracket + "%v" + rightBracket
	invalidValidation       = "Invalid validation tag on field %s"
	undefinedValidation     = "Undefined validation function on field %s"
	validatorNotInitialized = "Validator instance not initialized"
	fieldNameRequired       = "Field Name Required"
	tagRequired             = "Tag Required"
)
var (
	timeType      = reflect.TypeOf(time.Time{})
	timePtrType   = reflect.TypeOf(&time.Time{})
	defaultCField = new(cField)
)
type StructLevel struct {
	TopStruct     reflect.Value
	CurrentStruct reflect.Value
	errPrefix     string
	nsPrefix      string
	errs          ValidationErrors
	v             *Validate
}
func (sl *StructLevel) ReportValidationErrors(relativeKey string, errs ValidationErrors) {
	for _, e := range errs {
		idx := strings.Index(relativeKey, "|")
		var rel string
		var cRel string
		if idx != -1 {
			rel = relativeKey[:idx]
			cRel = relativeKey[idx+1:]
		} else {
			rel = relativeKey
		}
		key := sl.errPrefix + rel + e.Field
		e.FieldNamespace = key
		e.NameNamespace = sl.nsPrefix + cRel + e.Name
		sl.errs[key] = e
	}
}
func (sl *StructLevel) ReportError(field reflect.Value, fieldName string, customName string, tag string) {
	field, kind := sl.v.ExtractType(field)
	if fieldName == blank {
		panic(fieldNameRequired)
	}
	if customName == blank {
		customName = fieldName
	}
	if tag == blank {
		panic(tagRequired)
	}
	ns := sl.errPrefix + fieldName
	switch kind {
	case reflect.Invalid:
		sl.errs[ns] = &FieldError{
			FieldNamespace: ns,
			NameNamespace:  sl.nsPrefix + customName,
			Name:           customName,
			Field:          fieldName,
			Tag:            tag,
			ActualTag:      tag,
			Param:          blank,
			Kind:           kind,
		}
	default:
		sl.errs[ns] = &FieldError{
			FieldNamespace: ns,
			NameNamespace:  sl.nsPrefix + customName,
			Name:           customName,
			Field:          fieldName,
			Tag:            tag,
			ActualTag:      tag,
			Param:          blank,
			Value:          field.Interface(),
			Kind:           kind,
			Type:           field.Type(),
		}
	}
}
type Validate struct {
	tagName             string
	fieldNameTag        string
	validationFuncs     map[string]Func
	structLevelFuncs    map[reflect.Type]StructLevelFunc
	customTypeFuncs     map[reflect.Type]CustomTypeFunc
	aliasValidators     map[string]string
	hasCustomFuncs      bool
	hasAliasValidators  bool
	hasStructLevelFuncs bool
	tagCache            *tagCache
	structCache         *structCache
	errsPool            *sync.Pool
}
func (v *Validate) initCheck() {
	if v == nil {
		panic(validatorNotInitialized)
	}
}
type Config struct {
	TagName      string
	FieldNameTag string
}
type CustomTypeFunc func(field reflect.Value) interface{}
type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool
type StructLevelFunc func(v *Validate, structLevel *StructLevel)
type ValidationErrors map[string]*FieldError
func (ve ValidationErrors) Error() string {
	buff := bytes.NewBufferString(blank)
	for key, err := range ve {
		buff.WriteString(fmt.Sprintf(fieldErrMsg, key, err.Field, err.Tag))
		buff.WriteString("\n")
	}
	return strings.TrimSpace(buff.String())
}
type FieldError struct {
	FieldNamespace string
	NameNamespace  string
	Field          string
	Name           string
	Tag            string
	ActualTag      string
	Kind           reflect.Kind
	Type           reflect.Type
	Param          string
	Value          interface{}
}
func New(config *Config) *Validate {
	tc := new(tagCache)
	tc.m.Store(make(map[string]*cTag))
	sc := new(structCache)
	sc.m.Store(make(map[reflect.Type]*cStruct))
	v := &Validate{
		tagName:      config.TagName,
		fieldNameTag: config.FieldNameTag,
		tagCache:     tc,
		structCache:  sc,
		errsPool: &sync.Pool{New: func() interface{} {
			return ValidationErrors{}
		}}}
	if len(v.aliasValidators) == 0 {
		v.aliasValidators = map[string]string{}
		for k, val := range bakedInAliasValidators {
			v.RegisterAliasValidation(k, val)
		}
	}
	if len(v.validationFuncs) == 0 {
		v.validationFuncs = map[string]Func{}
		for k, val := range bakedInValidators {
			v.RegisterValidation(k, val)
		}
	}
	return v
}