github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/validator/validator__string.go (about)

     1  package validator
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"regexp"
     8  
     9  	"github.com/machinefi/w3bstream/pkg/depends/kit/validator/errors"
    10  	"github.com/machinefi/w3bstream/pkg/depends/kit/validator/rules"
    11  )
    12  
    13  var (
    14  	TargetStringLength = "string length"
    15  	TargetStringValue  = "string value"
    16  )
    17  
    18  type String struct {
    19  	Enums   map[string]string
    20  	Pattern *regexp.Regexp
    21  	LenMode StrLenMode
    22  
    23  	MinLength uint64
    24  	MaxLength *uint64
    25  }
    26  
    27  func init() { DefaultFactory.Register(&String{}) }
    28  
    29  func (String) Names() []string { return []string{"string", "char"} }
    30  
    31  func (vs *String) Validate(v interface{}) error {
    32  	rv, ok := v.(reflect.Value)
    33  	if !ok {
    34  		rv = reflect.ValueOf(v)
    35  	}
    36  
    37  	_t := reflect.TypeOf("")
    38  
    39  	if !rv.Type().ConvertibleTo(_t) {
    40  		return errors.NewUnsupportedTypeError(rv.Type().String(), vs.String())
    41  	}
    42  
    43  	s := rv.Convert(_t).String()
    44  
    45  	if vs.Enums != nil {
    46  		if _, ok := vs.Enums[s]; !ok {
    47  			values := make([]interface{}, 0)
    48  			for _, v := range vs.Enums {
    49  				values = append(values, v)
    50  			}
    51  
    52  			return &errors.NotInEnumError{
    53  				Target:  TargetStringValue,
    54  				Current: v,
    55  				Enums:   values,
    56  			}
    57  		}
    58  		return nil
    59  	}
    60  
    61  	if vs.Pattern != nil {
    62  		if !vs.Pattern.MatchString(s) {
    63  			return &errors.NotMatchError{
    64  				Target:  TargetStringLength,
    65  				Pattern: vs.Pattern,
    66  				Current: v,
    67  			}
    68  		}
    69  		return nil
    70  	}
    71  
    72  	length := StrLenModes[vs.LenMode](s)
    73  
    74  	if length < vs.MinLength {
    75  		return &errors.OutOfRangeError{
    76  			Target:  TargetStringLength,
    77  			Current: length,
    78  			Minimum: vs.MinLength,
    79  		}
    80  	}
    81  
    82  	if vs.MaxLength != nil && length > *vs.MaxLength {
    83  		return &errors.OutOfRangeError{
    84  			Target:  TargetStringLength,
    85  			Current: length,
    86  			Maximum: vs.MaxLength,
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  func (String) New(ctx context.Context, r *Rule) (Validator, error) {
    93  	vs := &String{}
    94  
    95  	if r.ExclusiveMin || r.ExclusiveMax {
    96  		return nil, errors.NewSyntaxError(
    97  			"range mark of %s should not be `(` or `)`", vs.Names()[0],
    98  		)
    99  	}
   100  
   101  	mode, err := StringRuleParam(r)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	vs.LenMode = mode
   106  
   107  	if r.Pattern != nil {
   108  		vs.Pattern = r.Pattern
   109  		return vs, vs.TypeCheck(r)
   110  	}
   111  
   112  	min, max, err := UintRuleRange(r, fmt.Sprintf("%s of string", vs.LenMode), 64)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	vs.MinLength = min
   117  	vs.MaxLength = max
   118  
   119  	vs.Enums = StringRuleValues(r)
   120  
   121  	return vs, vs.TypeCheck(r)
   122  }
   123  
   124  func (vs *String) TypeCheck(r *Rule) error {
   125  	if r.Type.Kind() == reflect.String {
   126  		return nil
   127  	}
   128  	return errors.NewUnsupportedTypeError(r.String(), vs.String())
   129  }
   130  
   131  func (vs *String) String() string {
   132  	r := rules.NewRule(vs.Names()[0])
   133  
   134  	if vs.Enums != nil {
   135  		ruleValues := make([]*rules.Lit, 0)
   136  		for _, e := range vs.Enums {
   137  			ruleValues = append(ruleValues, rules.NewLiteral([]byte(e)))
   138  		}
   139  		r.ValueMatrix = [][]*rules.Lit{ruleValues}
   140  	}
   141  
   142  	r.Params = []rules.Node{
   143  		rules.NewLiteral([]byte(vs.LenMode.String())),
   144  	}
   145  
   146  	if vs.Pattern != nil {
   147  		r.Pattern = vs.Pattern
   148  	}
   149  
   150  	r.Range = RangeFromUint(vs.MinLength, vs.MaxLength)
   151  
   152  	return string(r.Bytes())
   153  }