github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/validator/validator__float.go (about) 1 package validator 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "strconv" 8 9 "github.com/machinefi/w3bstream/pkg/depends/kit/validator/errors" 10 "github.com/machinefi/w3bstream/pkg/depends/kit/validator/rules" 11 "github.com/machinefi/w3bstream/pkg/depends/x/ptrx" 12 "github.com/machinefi/w3bstream/pkg/depends/x/typesx" 13 ) 14 15 type Float struct { 16 MaxDigits uint 17 DecimalDigits *uint 18 19 Minimum *float64 20 Maximum *float64 21 ExclusiveMaximum bool 22 ExclusiveMinimum bool 23 24 MultipleOf float64 25 26 Enums map[float64]string 27 } 28 29 func init() { DefaultFactory.Register(&Float{}) } 30 31 func (vf *Float) SetDefault() { 32 if vf != nil { 33 if vf.MaxDigits == 0 { 34 vf.MaxDigits = 7 35 } 36 if vf.DecimalDigits == nil { 37 vf.DecimalDigits = ptrx.Uint(2) 38 } 39 } 40 } 41 42 func (Float) Names() []string { 43 return []string{"float", "double", "float32", "float64"} 44 } 45 46 var ( 47 TargetFloatValue = "float value" 48 TargetDecimalDigitsOfFloatValue = "decimal digits of float value" 49 TargetTotalDigitsOfFloatValue = "total digits of float value" 50 ) 51 52 func (vf *Float) Validate(v interface{}) error { 53 rv, ok := v.(reflect.Value) 54 if !ok { 55 rv = reflect.ValueOf(v) 56 } 57 58 if k := rv.Type().Kind(); !typesx.IsFloatReflectKind(k) { 59 return errors.NewUnsupportedTypeError(rv.Type().String(), vf.String()) 60 } 61 62 val := rv.Float() 63 decimal := *vf.DecimalDigits 64 65 m, d := FloatLengthOfDigit(val) 66 if m > vf.MaxDigits { 67 return &errors.OutOfRangeError{ 68 Target: TargetTotalDigitsOfFloatValue, 69 Current: m, 70 Maximum: vf.MaxDigits, 71 } 72 } 73 74 if d > decimal { 75 return &errors.OutOfRangeError{ 76 Target: TargetDecimalDigitsOfFloatValue, 77 Current: d, 78 Maximum: decimal, 79 } 80 } 81 82 if vf.Enums != nil { 83 if _, ok := vf.Enums[val]; !ok { 84 values := make([]interface{}, 0) 85 for _, v := range vf.Enums { 86 values = append(values, v) 87 } 88 89 return &errors.NotInEnumError{ 90 Target: TargetFloatValue, 91 Current: v, 92 Enums: values, 93 } 94 } 95 return nil 96 } 97 98 if vf.Minimum != nil { 99 minimum := *vf.Minimum 100 if (vf.ExclusiveMinimum && val == minimum) || val < minimum { 101 return &errors.OutOfRangeError{ 102 Target: TargetFloatValue, 103 Current: val, 104 Minimum: minimum, 105 ExclusiveMinimum: vf.ExclusiveMinimum, 106 } 107 } 108 } 109 110 if vf.Maximum != nil { 111 maximum := *vf.Maximum 112 if (vf.ExclusiveMaximum && val == maximum) || val > maximum { 113 return &errors.OutOfRangeError{ 114 Target: TargetFloatValue, 115 Current: val, 116 Maximum: maximum, 117 ExclusiveMaximum: vf.ExclusiveMaximum, 118 } 119 } 120 } 121 122 if vf.MultipleOf != 0 { 123 if !IsFloatMultipleOf(val, vf.MultipleOf, decimal) { 124 return &errors.MultipleOfError{ 125 Target: TargetFloatValue, 126 Current: val, 127 MultipleOf: vf.MultipleOf, 128 } 129 } 130 } 131 132 return nil 133 } 134 135 func (Float) New(ctx context.Context, r *Rule) (Validator, error) { 136 vf := &Float{} 137 138 switch r.Name { 139 case "float", "float32": 140 vf.MaxDigits = 7 141 case "double", "float64": 142 vf.MaxDigits = 15 143 } 144 145 // @float<max_digit,max_decimal> 146 // @float<5,2> 1.111(too many decimal) 12345.67 (too many digits) 147 if len(r.Params) > 0 { 148 digits, decimal, err := FloatRuleParam(r) 149 if err != nil { 150 return nil, err 151 } 152 vf.MaxDigits = uint(digits) 153 if decimal != nil { 154 vf.DecimalDigits = ptrx.Uint(uint(*decimal)) 155 } 156 } 157 158 vf.SetDefault() 159 vf.ExclusiveMinimum = r.ExclusiveMin 160 vf.ExclusiveMaximum = r.ExclusiveMax 161 162 // @float[min,max] 163 // @float(min,max] 164 // @float[min,max) 165 // @float(min,max) 166 min, max, err := FloatRuleRange(r, vf.MaxDigits, vf.DecimalDigits) 167 if err != nil { 168 return nil, err 169 } 170 vf.Minimum, vf.Maximum = min, max 171 172 // @float{1.1,2.2,3.3} should be one of these 173 // @float{%2.2} should be multiple of 2.2 174 multiple, enums, err := FloatRuleValues(r, vf.MaxDigits, vf.DecimalDigits) 175 if err != nil { 176 return nil, err 177 } 178 vf.MultipleOf = multiple 179 vf.Enums = enums 180 181 return vf, vf.TypeCheck(r) 182 } 183 184 func (vf *Float) TypeCheck(r *Rule) error { 185 switch r.Type.Kind() { 186 case reflect.Float32: 187 if vf.MaxDigits > 7 { 188 return fmt.Errorf("max digits too large for type %s", r) 189 } 190 return nil 191 case reflect.Float64: 192 return nil 193 } 194 return errors.NewUnsupportedTypeError(r.String(), vf.String()) 195 } 196 197 func (vf *Float) String() string { 198 vf.SetDefault() 199 200 decimal := *vf.DecimalDigits 201 rule := rules.NewRule(vf.Names()[0]) 202 rule.Params = []rules.Node{ 203 rules.NewLiteral([]byte(strconv.Itoa(int(vf.MaxDigits)))), 204 rules.NewLiteral([]byte(strconv.Itoa(int(decimal)))), 205 } 206 207 if vf.Minimum != nil || vf.Maximum != nil { 208 rule.Range = make([]*rules.Lit, 2) 209 210 if vf.Minimum != nil { 211 rule.Range[0] = rules.NewLiteral( 212 []byte(fmt.Sprintf("%."+strconv.Itoa(int(decimal))+"f", *vf.Minimum)), 213 ) 214 } 215 216 if vf.Maximum != nil { 217 rule.Range[1] = rules.NewLiteral( 218 []byte(fmt.Sprintf("%."+strconv.Itoa(int(decimal))+"f", *vf.Maximum)), 219 ) 220 } 221 222 rule.ExclusiveMin = vf.ExclusiveMinimum 223 rule.ExclusiveMax = vf.ExclusiveMaximum 224 } 225 226 if vf.MultipleOf != 0 { 227 rule.ValueMatrix = [][]*rules.Lit{{ 228 rules.NewLiteral([]byte("%" + fmt.Sprintf("%."+strconv.Itoa(int(decimal))+"f", vf.MultipleOf))), 229 }} 230 } else if vf.Enums != nil { 231 values := make([]*rules.Lit, 0) 232 for _, str := range vf.Enums { 233 values = append(values, rules.NewLiteral([]byte(str))) 234 } 235 rule.ValueMatrix = [][]*rules.Lit{values} 236 } 237 238 return string(rule.Bytes()) 239 }