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  }