func IsMaxFloat(max float64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Float32, reflect.Float64:
		default:
			panic("stick: expected float value")
		}
		if sub.RValue.Float() > max {
			return xo.SF("too big")
		}
		return nil
	}
}
IsMaxFloat checks whether the value satisfies the provided maximum.
package stick
import (
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
	"github.com/256dpi/xo"
	"github.com/asaskevich/govalidator"
)
type Validatable interface {
	Validate() error
}
type NoValidation struct{}
func (*NoValidation) Validate() error {
	return nil
}
type ValidationError map[error][]string
func (e ValidationError) Error() string {
	var messages []string
	for err, path := range e {
		msg := "error"
		if xo.IsSafe(err) {
			msg = err.Error()
		}
		messages = append(messages, fmt.Sprintf("%s: %s", strings.Join(path, "."), msg))
	}
	sort.Strings(messages)
	err := strings.Join(messages, "; ")
	return err
}
type Validator struct {
	value interface{}
	path  []string
	error ValidationError
}
func Validate(v interface{}, fn func(v *Validator)) error {
	val := &Validator{value: v}
	fn(val)
	return val.Error()
}
func (v *Validator) Nest(field string, fn func()) {
	v.path = append(v.path, field)
	fn()
	v.path = v.path[:len(v.path)-1]
}
func (v *Validator) Value(name string, optional bool, rules ...Rule) {
	value := MustGetRaw(v.value, name)
	sub := Subject{
		IValue: value.Interface(),
		RValue: value,
	}
	if optional {
		if sub.RValue.Kind() != reflect.Ptr {
			panic("stick: expected pointer")
		}
		if sub.RValue.IsNil() {
			return
		}
		sub.RValue = sub.RValue.Elem()
		sub.IValue = sub.RValue.Interface()
	}
	for _, rule := range rules {
		err := rule(sub)
		if err != nil {
			v.Report(name, err)
		}
	}
}
func (v *Validator) Items(name string, rules ...Rule) {
	slice := MustGetRaw(v.value, name)
	if slice.Kind() != reflect.Slice && slice.Kind() != reflect.Array {
		panic("stick: expected array/slice")
	}
	v.Nest(name, func() {
		for i := 0; i < slice.Len(); i++ {
			item := slice.Index(i)
			sub := Subject{
				IValue: item.Interface(),
				RValue: item,
			}
			for _, rule := range rules {
				err := rule(sub)
				if err != nil {
					v.Report(strconv.Itoa(i), err)
				}
			}
		}
	})
}
func (v *Validator) Report(name string, err error) {
	if v.error == nil {
		v.error = ValidationError{}
	}
	var valError ValidationError
	if errors.As(err, &valError) {
		for err, pth := range valError {
			path := append([]string{}, v.path...)
			path = append(path, name)
			path = append(path, pth...)
			v.error[err] = path
		}
		return
	}
	path := append([]string{}, v.path...)
	path = append(path, name)
	v.error[xo.W(err)] = path
}
func (v *Validator) Error() error {
	if v.error != nil {
		return xo.SW(v.error)
	}
	return nil
}
type Subject struct {
	IValue interface{}
	RValue reflect.Value
}
func (s *Subject) Unwrap() bool {
	var unwrapped bool
	for s.RValue.Kind() == reflect.Ptr {
		if s.RValue.IsNil() {
			return false
		}
		s.RValue = s.RValue.Elem()
		unwrapped = true
	}
	if unwrapped {
		s.IValue = s.RValue.Interface()
	}
	return true
}
func (s *Subject) Reference() Subject {
	addr := s.RValue.Addr()
	return Subject{
		IValue: addr.Interface(),
		RValue: addr,
	}
}
type Rule func(sub Subject) error
func IsZero(sub Subject) error {
	if !isZero(sub) {
		return xo.SF("not zero")
	}
	return nil
}
func IsNotZero(sub Subject) error {
	if isZero(sub) {
		return xo.SF("zero")
	}
	return nil
}
func isZero(sub Subject) bool {
	if !sub.Unwrap() {
		return true
	}
	ref := sub.Reference()
	type isZero interface {
		IsZero() bool
	}
	if v, ok := sub.IValue.(isZero); ok {
		return v.IsZero()
	} else if v, ok := ref.IValue.(isZero); ok {
		return v.IsZero()
	}
	type zero interface {
		Zero() bool
	}
	if v, ok := sub.IValue.(zero); ok {
		return v.Zero()
	} else if v, ok := ref.IValue.(zero); ok {
		return v.Zero()
	}
	return sub.RValue.IsZero()
}
func IsEmpty(sub Subject) error {
	if !sub.Unwrap() {
		return nil
	}
	if !isEmpty(sub) {
		return xo.SF("not empty")
	}
	return nil
}
func IsNotEmpty(sub Subject) error {
	if !sub.Unwrap() {
		return nil
	}
	if isEmpty(sub) {
		return xo.SF("empty")
	}
	return nil
}
func isEmpty(sub Subject) bool {
	switch sub.RValue.Kind() {
	case reflect.Slice, reflect.Map, reflect.String:
		return sub.RValue.Len() == 0
	}
	panic(fmt.Sprintf("stick: cannot check length of %T", sub.IValue))
}
func IsValid(sub Subject) error {
	if !sub.Unwrap() {
		return nil
	}
	ok, err := isValid(sub.IValue)
	if ok {
		return err
	}
	ok, err = isValid(sub.Reference().IValue)
	if ok {
		return err
	}
	panic(fmt.Sprintf("stick: cannot check validity of %T", sub.IValue))
}
func isValid(val interface{}) (bool, error) {
	if v, ok := val.(Validatable); ok {
		return true, v.Validate()
	}
	type isValid interface {
		IsValid() bool
	}
	if v, ok := val.(isValid); ok {
		if !v.IsValid() {
			return true, xo.SF("invalid")
		}
		return true, nil
	}
	type valid interface {
		Valid() bool
	}
	if v, ok := val.(valid); ok {
		if !v.Valid() {
			return true, xo.SF("invalid")
		}
		return true, nil
	}
	return false, nil
}
func IsMinLen(min int) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		default:
			panic("stick: expected array/map/slice/string value")
		}
		if sub.RValue.Len() < min {
			return xo.SF("too short")
		}
		return nil
	}
}
func IsMaxLen(max int) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		default:
			panic("stick: expected array/map/slice/string value")
		}
		if sub.RValue.Len() > max {
			return xo.SF("too long")
		}
		return nil
	}
}
func IsMinInt(min int64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		default:
			panic("stick: expected int value")
		}
		if sub.RValue.Int() < min {
			return xo.SF("too small")
		}
		return nil
	}
}
func IsMaxInt(max int64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		default:
			panic("stick: expected int value")
		}
		if sub.RValue.Int() > max {
			return xo.SF("too big")
		}
		return nil
	}
}
func IsMinUint(min uint64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		default:
			panic("stick: expected uint value")
		}
		if sub.RValue.Uint() < min {
			return xo.SF("too small")
		}
		return nil
	}
}
func IsMaxUint(max uint64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		default:
			panic("stick: expected uint value")
		}
		if sub.RValue.Uint() > max {
			return xo.SF("too big")
		}
		return nil
	}
}
func IsMinFloat(min float64) Rule {
	return func(sub Subject) error {
		if !sub.Unwrap() {
			return nil
		}
		switch sub.RValue.Kind() {
		case reflect.Float32, reflect.Float64:
		default:
			panic("stick: expected float value")
		}
		if sub.RValue.Float() < min {
			return xo.SF("too small")
		}
		return nil
	}
}