github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/validator/validator__map.go (about) 1 package validator 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 8 "github.com/machinefi/w3bstream/pkg/depends/kit/validator/errors" 9 "github.com/machinefi/w3bstream/pkg/depends/kit/validator/rules" 10 ) 11 12 var ( 13 TargetMapLength = "map length" 14 ) 15 16 type Map struct { 17 MinProperties uint64 18 MaxProperties *uint64 19 20 KeyValidator Validator 21 ElemValidator Validator 22 } 23 24 func init() { DefaultFactory.Register(&Map{}) } 25 26 func (Map) Names() []string { return []string{"map"} } 27 28 func (vm *Map) Validate(v interface{}) error { 29 switch rv := v.(type) { 30 case reflect.Value: 31 return vm.ValidateReflectValue(rv) 32 default: 33 return vm.ValidateReflectValue(reflect.ValueOf(v)) 34 } 35 } 36 37 func (vm *Map) ValidateReflectValue(rv reflect.Value) error { 38 length := uint64(0) 39 if !rv.IsNil() { 40 length = uint64(rv.Len()) 41 } 42 43 if length < vm.MinProperties { 44 return &errors.OutOfRangeError{ 45 Target: TargetMapLength, 46 Current: rv.Interface(), 47 Minimum: vm.MinProperties, 48 } 49 } 50 51 if vm.MaxProperties != nil && length > *vm.MaxProperties { 52 return &errors.OutOfRangeError{ 53 Target: TargetMapLength, 54 Current: rv.Interface(), 55 Maximum: vm.MaxProperties, 56 } 57 } 58 59 if vm.KeyValidator != nil || vm.ElemValidator != nil { 60 errs := errors.NewErrorSet() 61 for _, key := range rv.MapKeys() { 62 vk := key.Interface() 63 if vm.KeyValidator != nil { 64 err := vm.KeyValidator.Validate(vk) 65 if err != nil { 66 errs.AddErr(err, fmt.Sprintf("%v/key", vk)) 67 } 68 } 69 if vm.ElemValidator != nil { 70 err := vm.ElemValidator.Validate(rv.MapIndex(key).Interface()) 71 if err != nil { 72 errs.AddErr(err, fmt.Sprintf("%v", vk)) 73 } 74 } 75 } 76 return errs.Err() 77 } 78 79 return nil 80 } 81 82 func (vm *Map) New(ctx context.Context, r *Rule) (Validator, error) { 83 if r.Type.Kind() != reflect.Map { 84 return nil, errors.NewUnsupportedTypeError(r.String(), vm.String()) 85 } 86 87 ret := &Map{} 88 89 if r.ExclusiveMin || r.ExclusiveMax { 90 return nil, errors.NewSyntaxError( 91 "range mark of %s should not be `(` or `)`", ret.Names()[0], 92 ) 93 } 94 95 min, max, err := UintRuleRange(r, "size of map", 64) 96 if err != nil { 97 return nil, err 98 } 99 ret.MinProperties, ret.MaxProperties = min, max 100 101 k, v, err := MapRuleParam(ctx, r) 102 if err != nil { 103 return nil, err 104 } 105 ret.KeyValidator = k 106 ret.ElemValidator = v 107 108 return ret, nil 109 } 110 111 func (vm *Map) String() string { 112 rule := rules.NewRule(vm.Names()[0]) 113 114 if vm.KeyValidator != nil || vm.ElemValidator != nil { 115 rule.Params = make([]rules.Node, 2) 116 117 if vm.KeyValidator != nil { 118 rule.Params[0] = rules.NewLiteral([]byte(vm.KeyValidator.String())) 119 } 120 121 if vm.ElemValidator != nil { 122 rule.Params[1] = rules.NewLiteral([]byte(vm.ElemValidator.String())) 123 } 124 } 125 126 rule.Range = RangeFromUint(vm.MinProperties, vm.MaxProperties) 127 128 return string(rule.Bytes()) 129 }