github.com/awesome-flow/flow@v0.0.3-0.20190918184116-508d75d68a2c/pkg/cast/converter.go (about) 1 package cast 2 3 import ( 4 "strconv" 5 6 "github.com/awesome-flow/flow/pkg/types" 7 ) 8 9 // Converter is a primary interface for converting actors. It represents an 10 // act of best-effort converstion: either converts or gives up. 11 type Converter interface { 12 // Convert is the function a Converter is expected to define. Returns 13 // a converted value and a boolean flag indicating whether the conversion 14 // took a place. 15 Convert(kv *types.KeyValue) (*types.KeyValue, bool) 16 } 17 18 // IdentityConverter represents an identity function returning the original 19 // value and a success flag. 20 type IdentityConverter struct{} 21 22 var _ Converter = (*IdentityConverter)(nil) 23 24 // Convert returns the kv pair itself and true, no matter what value is provided. 25 func (*IdentityConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 26 return kv, true 27 } 28 29 // IntPtrToIntConverter performs conversion from an int pointer to int. 30 type IntPtrToIntConverter struct{} 31 32 var _ Converter = (*IntPtrToIntConverter)(nil) 33 34 // Convert returns an integer and true if the argument value is a pointer to int. 35 // Returns nil, false if cast to *int fails. 36 func (*IntPtrToIntConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 37 if pv, ok := kv.Value.(*int); ok { 38 return &types.KeyValue{Key: kv.Key, Value: *pv}, true 39 } 40 return nil, false 41 } 42 43 // BoolPtrToBoolConverter performs conversion from a boolean pointer to boolean. 44 type BoolPtrToBoolConverter struct{} 45 46 var _ Converter = (*BoolPtrToBoolConverter)(nil) 47 48 // Convert returns a bool and true if the argument value is a poiter to bool. 49 // Returns nil, false if cast to *bool fails. 50 func (*BoolPtrToBoolConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 51 if pv, ok := kv.Value.(*bool); ok { 52 return &types.KeyValue{Key: kv.Key, Value: *pv}, true 53 } 54 return nil, false 55 } 56 57 // StrPtrToStrConverter performs conversion from a string pointer to string. 58 type StrPtrToStrConverter struct{} 59 60 var _ Converter = (*StrPtrToStrConverter)(nil) 61 62 // Convert returns a string and true if the argument value is a pointer to string. 63 // Returns nil, false if cast to *string fails. 64 func (*StrPtrToStrConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 65 if spv, ok := kv.Value.(*string); ok { 66 return &types.KeyValue{Key: kv.Key, Value: *spv}, true 67 } 68 return nil, false 69 } 70 71 // StrToBoolConverter performs conventional conversion from a string to a bool value. 72 type StrToBoolConverter struct{} 73 74 var _ Converter = (*StrToBoolConverter)(nil) 75 76 // Convert returns true, true for strings "true", "1", "y". 77 // For strings "false", "0" and "n" returns false, true. 78 // Returns false, false otherwise treating the case as non-successful conversion. 79 func (*StrToBoolConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 80 if sv, ok := kv.Value.(string); ok { 81 switch sv { 82 case "true", "1", "y": 83 return &types.KeyValue{Key: kv.Key, Value: true}, true 84 case "false", "0", "n": 85 return &types.KeyValue{Key: kv.Key, Value: false}, true 86 } 87 } 88 return nil, false 89 } 90 91 // StrToIntConverter performs conventional conversion from a string to int. 92 type StrToIntConverter struct{} 93 94 var _ Converter = (*StrToIntConverter)(nil) 95 96 // Convert returns an int, true if the argument value can be parsed with 97 // strconv.Atoi. Returns nil, false otherwise. 98 func (*StrToIntConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 99 if sv, ok := kv.Value.(string); ok { 100 s, err := strconv.Atoi(sv) 101 if err == nil { 102 return &types.KeyValue{Key: kv.Key, Value: s}, true 103 } 104 } 105 return nil, false 106 } 107 108 // IntToBoolConverter performs conventional conversion from an int to bool. 109 type IntToBoolConverter struct{} 110 111 var _ Converter = (*IntToBoolConverter)(nil) 112 113 // Convert returns false, true for the argument value = 0. 114 // Returns true, true for the argument value = 1. 115 // Returns nil, false otherwise. 116 func (*IntToBoolConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 117 if mv, ok := kv.Value.(int); ok { 118 var v bool 119 if mv == 0 { 120 v = false 121 } else if mv == 1 { 122 v = true 123 } else { 124 return nil, false 125 } 126 return &types.KeyValue{Key: kv.Key, Value: v}, true 127 } 128 return nil, false 129 } 130 131 // IntToStrConverter performs an int to string conversion. 132 type IntToStrConverter struct{} 133 134 var _ Converter = (*IntToStrConverter)(nil) 135 136 // Convert returns a string, false if the argument value is an int. 137 // Returns nil, false otherwise. 138 func (*IntToStrConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 139 if iv, ok := kv.Value.(int); ok { 140 return &types.KeyValue{Key: kv.Key, Value: strconv.Itoa(iv)}, true 141 } 142 return nil, false 143 } 144 145 // IfIntConverter performs int type enforcement: marks the conversion as 146 // successful if the value is already an int. 147 type IfIntConverter struct{} 148 149 var _ Converter = (*IfIntConverter)(nil) 150 151 // Convert returns int, true if the value is int. 152 // Returns nil, false otherwise. 153 func (*IfIntConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 154 if _, ok := kv.Value.(int); ok { 155 return kv, true 156 } 157 return nil, false 158 } 159 160 // IfStrConverter performs string type enforcement: marks the conversion as 161 // successful if the value is already a string. 162 type IfStrConverter struct{} 163 164 var _ Converter = (*IfStrConverter)(nil) 165 166 // Convert returns string, true if the argument value is a string. 167 // Returns nil, false otherwise. 168 func (*IfStrConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 169 if _, ok := kv.Value.(string); ok { 170 return kv, true 171 } 172 return nil, false 173 } 174 175 // IfBoolConverter performs bool type enforcement: marks the conversion as 176 // successfulk if the value is already a bool. 177 type IfBoolConverter struct{} 178 179 var _ Converter = (*IfBoolConverter)(nil) 180 181 // Convert returns bool, true if the value is a bool. 182 // Returns nil, false otherwise. 183 func (*IfBoolConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 184 if _, ok := kv.Value.(bool); ok { 185 return kv, true 186 } 187 return nil, false 188 } 189 190 //======== Composite converters ======= 191 192 // CompositionStrategy is a family of constants defining the logic of a 193 // composition chain. 194 type CompositionStrategy uint8 195 196 const ( 197 // CompNone means none of the chain components have to succeed. A no-op 198 // logic, the chain always returns success. 199 CompNone CompositionStrategy = iota 200 // CompAnd means all components of the chain have to succeed in order to 201 // mark the conversion successful. Returns the last successful conversion 202 // result. 203 CompAnd 204 // CompOr means at least 1 component of the chain have to succeed in order 205 // to mark the conversion successful. Returns the first successful conversion 206 // result. 207 CompOr 208 // CompFirst means the conversion is marked successful if at least 1 component 209 // returns success. Conversion chain terminates here. 210 CompFirst 211 // CompLast means the conversion tries to execute all chain components and 212 // returns the last successful result. 213 CompLast 214 ) 215 216 // CompositeConverter implements a composite conversion logic defined by some 217 // specific conversion strategy. 218 type CompositeConverter struct { 219 strategy CompositionStrategy 220 converters []Converter 221 } 222 223 // NewCompositeConverter is the constructor for a new CompositeStrategy chain. 224 // Accepts the conversion strategy and a list of conversion chain components. 225 func NewCompositeConverter(strategy CompositionStrategy, convs ...Converter) *CompositeConverter { 226 return &CompositeConverter{ 227 strategy: strategy, 228 converters: convs, 229 } 230 } 231 232 // Convert executes the conversion logic defined by the conversion strategy. 233 func (cc *CompositeConverter) Convert(kv *types.KeyValue) (*types.KeyValue, bool) { 234 switch cc.strategy { 235 case CompNone: 236 return kv, true 237 case CompAnd: 238 mkv := kv 239 var ok bool 240 for _, conv := range cc.converters { 241 mkv, ok = conv.Convert(mkv) 242 if !ok { 243 return nil, false 244 } 245 } 246 return mkv, ok 247 case CompFirst, CompOr: 248 for _, conv := range cc.converters { 249 if mkv, ok := conv.Convert(kv); ok { 250 return mkv, ok 251 } 252 } 253 return nil, false 254 case CompLast: 255 var res *types.KeyValue 256 var resok bool 257 for _, conv := range cc.converters { 258 if mkv, ok := conv.Convert(kv); ok { 259 res = mkv 260 resok = ok 261 } 262 } 263 return res, resok 264 } 265 return nil, false 266 } 267 268 var ( 269 // Identity is an initialized instance of IdentityConverter 270 Identity *IdentityConverter 271 272 // BoolPtrToBool is an initialized instance of BoolPtrToBoolConverter 273 BoolPtrToBool *BoolPtrToBoolConverter 274 // IntPtrToInt is an initialized instance of IntPtrToIntConverter 275 IntPtrToInt *IntPtrToIntConverter 276 // StrPtrToStr is an initialized instance of StrPtrToStrConverter 277 StrPtrToStr *StrPtrToStrConverter 278 279 // IntToBool is an initialized instance of IntToBoolConverter 280 IntToBool *IntToBoolConverter 281 // IntToStr is an initialized instance of IntToStrConverter 282 IntToStr *IntToStrConverter 283 // StrToBool is an initialized instance of StrToBoolConverter 284 StrToBool *StrToBoolConverter 285 // StrToInt is an initialized instance of StrToIntConveter 286 StrToInt *StrToIntConverter 287 288 // IfInt is an initialized instance of IfIntConverter 289 IfInt *IfIntConverter 290 // IfStr is an initialized instance of IfStrConverter 291 IfStr *IfStrConverter 292 // IfBool is an initialized instance of IfBoolConverter 293 IfBool *IfBoolConverter 294 295 // IntOrIntPtr is an instance of a composite converter enforcing an int or 296 // an *int to int type. 297 IntOrIntPtr *CompositeConverter 298 // StrOrStrPtr is an instance of a composite converter enforcing a string 299 // or a *string to string type. 300 StrOrStrPtr *CompositeConverter 301 // BoolOrBoolPtr is an instance of a composite converter enforcing a bool 302 // or a *bool to bool type. 303 BoolOrBoolPtr *CompositeConverter 304 305 // ToInt is an instance of a composite converter enforcing an int, *int or 306 // a string to int type. 307 ToInt *CompositeConverter 308 // ToStr is an instance of a composite converter enforcing a string, *string 309 // or an int to string type. 310 ToStr *CompositeConverter 311 // ToBool is an instance of a composite converter enforcing a bool, *bool, 312 // string or an int to bool value. 313 ToBool *CompositeConverter 314 ) 315 316 func init() { 317 IntOrIntPtr = NewCompositeConverter(CompOr, IfInt, IntPtrToInt) 318 StrOrStrPtr = NewCompositeConverter(CompOr, IfStr, StrPtrToStr) 319 BoolOrBoolPtr = NewCompositeConverter(CompOr, IfBool, BoolPtrToBool) 320 321 ToInt = NewCompositeConverter(CompOr, IntOrIntPtr, StrToInt) 322 ToStr = NewCompositeConverter(CompOr, StrOrStrPtr, IntToStr) 323 ToBool = NewCompositeConverter(CompOr, BoolOrBoolPtr, StrToBool, IntToBool) 324 }