v1
This commit is contained in:
127
value.go
Normal file
127
value.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCouldNotConvert = errors.New("conf: could not cast one or more values to required type")
|
||||
)
|
||||
|
||||
const (
|
||||
separatorSlice = ","
|
||||
separatorMap = ":"
|
||||
)
|
||||
|
||||
type Value string
|
||||
|
||||
// Map tries to interpret value as "key: value" pairs
|
||||
// separated by comma like in the following string:
|
||||
// "key1: value1, key2: value2, key3: value3".
|
||||
func (v Value) Map() (Map, error) {
|
||||
split := tidySplit(v, separatorSlice)
|
||||
|
||||
m := make(Map, len(split))
|
||||
|
||||
for i := range split {
|
||||
k, v, ok := toKV(split[i], separatorMap)
|
||||
if !ok {
|
||||
return nil, ErrCouldNotConvert
|
||||
}
|
||||
|
||||
m[k] = Value(v)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// String returns Value as string
|
||||
func (v Value) String() string {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// Int converts Value to int. Returned error
|
||||
// will be non nil if convesion failed.
|
||||
func (v Value) Int() (int, error) {
|
||||
return parseValue(v, strconv.Atoi) // Atoi in fact checks int size, no need to use ParseInt
|
||||
}
|
||||
|
||||
// IntSlice splits Value (separator is ",") and adds
|
||||
// each of resulting values to []int if possible.
|
||||
// Returns nil and non-nil error on first failure to convert.
|
||||
func (v Value) IntSlice() ([]int, error) {
|
||||
return parseSlice(v, strconv.Atoi)
|
||||
}
|
||||
|
||||
// Float64 converts Value to float64. Returned error
|
||||
// will be non nil if convesion failed.
|
||||
func (v Value) Float64() (float64, error) {
|
||||
return parseValue(v, parseFloat64)
|
||||
}
|
||||
|
||||
// Float64Slice splits Value (separator is ",") and adds
|
||||
// each of resulting values to []float64 if possible.
|
||||
// Returns nil and non-nil error on first failure to convert.
|
||||
func (v Value) Float64Slice() ([]float64, error) {
|
||||
return parseSlice(v, parseFloat64)
|
||||
}
|
||||
|
||||
// StringSlice splits Value (separator is ",") and adds
|
||||
// each of resulting values to []string trimming leading and trailing spaces
|
||||
// from each string.
|
||||
func (v Value) StringSlice() []string {
|
||||
return tidySplit(v, separatorSlice)
|
||||
}
|
||||
|
||||
// Bool tries to interpret Value as bool
|
||||
// "1", "t", "T", true", "True", "TRUE" yields true
|
||||
// "0", "f", "F, "false", "False", "FALSE" yields false
|
||||
// If nothing matches will return false and conf.ErrCouldNotConvert.
|
||||
func (v Value) Bool() (bool, error) {
|
||||
return parseValue(v, strconv.ParseBool)
|
||||
}
|
||||
|
||||
// URL tries to interpret value as url.URL
|
||||
func (v Value) URL() (*url.URL, error) {
|
||||
return parseValue(v, url.Parse)
|
||||
}
|
||||
|
||||
func parseSlice[T any, S ~string](s S, f func(string) (T, error)) ([]T, error) {
|
||||
split := tidySplit(s, separatorSlice)
|
||||
|
||||
list := make([]T, 0, len(split))
|
||||
for _, str := range split {
|
||||
v, err := parseValue(str, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = append(list, v)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func parseValue[T any, S ~string](s S, f func(string) (T, error)) (T, error) {
|
||||
v, err := f(string(s))
|
||||
if err != nil {
|
||||
return v, errors.Join(ErrCouldNotConvert, err)
|
||||
}
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
func tidySplit[S ~string](s S, sep string) []string {
|
||||
splitted := strings.Split(string(s), sep)
|
||||
for i, str := range splitted {
|
||||
splitted[i] = trim(str)
|
||||
}
|
||||
return splitted
|
||||
}
|
||||
|
||||
func parseFloat64(s string) (float64, error) {
|
||||
return strconv.ParseFloat(s, 64)
|
||||
}
|
Reference in New Issue
Block a user