diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/converters.go b/converters.go new file mode 100644 index 0000000..aaec516 --- /dev/null +++ b/converters.go @@ -0,0 +1,89 @@ +package envvars + +import ( + "errors" + "strconv" + "unicode/utf8" +) + +func ConvertString(s string) (string, error) { + return s, nil +} + +func ConvertRune(s string) (rune, error) { + rn, _ := utf8.DecodeRuneInString(s) + if rn == utf8.RuneError { + return 0, errors.New("rune decoding failed") + } + return rn, nil +} + +func ConvertInt64(s string) (int64, error) { + return strconv.ParseInt(s, 10, 64) +} + +func ConvertInt32(s string) (int32, error) { + v, err := strconv.ParseInt(s, 10, 32) + return int32(v), err +} + +func ConvertInt16(s string) (int16, error) { + v, err := strconv.ParseInt(s, 10, 16) + return int16(v), err +} + +func ConvertInt8(s string) (int8, error) { + v, err := strconv.ParseInt(s, 10, 8) + return int8(v), err +} + +func ConvertInt(s string) (int, error) { + v, err := strconv.ParseInt(s, 10, 64) + return int(v), err +} + +func ConvertUint64(s string) (uint64, error) { + return strconv.ParseUint(s, 10, 64) +} + +func ConvertUint32(s string) (uint32, error) { + v, err := strconv.ParseUint(s, 10, 32) + return uint32(v), err +} + +func ConvertUint16(s string) (uint16, error) { + v, err := strconv.ParseUint(s, 10, 16) + return uint16(v), err +} + +func ConvertUint8(s string) (uint8, error) { + v, err := strconv.ParseUint(s, 10, 8) + return uint8(v), err +} + +func ConvertUint(s string) (uint, error) { + v, err := strconv.ParseUint(s, 10, 64) + return uint(v), err +} + +func ConvertFloat64(s string) (float64, error) { + return strconv.ParseFloat(s, 64) +} + +func ConvertFloat32(s string) (float32, error) { + v, err := strconv.ParseFloat(s, 32) + return float32(v), err +} + +func ConvertComplex128(s string) (complex128, error) { + return strconv.ParseComplex(s, 128) +} + +func ConvertComplex64(s string) (complex64, error) { + v, err := strconv.ParseComplex(s, 64) + return complex64(v), err +} + +func ConvertBool(s string) (bool, error) { + return strconv.ParseBool(s) +} diff --git a/object.go b/object.go new file mode 100644 index 0000000..478476c --- /dev/null +++ b/object.go @@ -0,0 +1,34 @@ +package envvars + +import ( + "os" + "strings" +) + +func Object[T any](key string, defaultValue T, converter func(string) (T, error)) T { + if v, ok := os.LookupEnv(key); ok { + if v2, err := converter(v); err == nil { + return v2 + } + } + return defaultValue +} + +func ObjectSlice[T any](key, sep string, defaultValue []T, converter func(string) (T, error)) []T { + return Object(key, defaultValue, func(s string) ([]T, error) { + if s == "" { + return []T{}, nil + } + + splits := strings.Split(s, sep) + values := make([]T, 0, len(splits)) + for _, s := range splits { + v, err := converter(s) + if err != nil { + return values, err + } + values = append(values, v) + } + return values, nil + }) +} diff --git a/slices.go b/slices.go index eabe60f..9204814 100644 --- a/slices.go +++ b/slices.go @@ -1,172 +1,79 @@ package envvars -import ( - "os" - "strconv" - "strings" -) +import "time" -func StringSlice(key, sep string) []string { - if v, ok := os.LookupEnv(key); ok && strings.TrimSpace(v) != "" { - return strings.Split(v, sep) - } - return []string{} +func StringSlice(key, sep string, defaultValue []string) []string { + return ObjectSlice(key, sep, defaultValue, ConvertString) } -func ByteSlice(key, sep string) []byte { - return []byte(String(key, "")) +func ByteSlice(key, sep string, defaultValue []byte) []byte { + return Uint8Slice(key, sep, defaultValue) } -func RuneSlice(key, sep string) []rune { - return []rune(String(key, "")) +func RuneSlice(key, sep string, defaultValue []rune) []rune { + return ObjectSlice(key, sep, defaultValue, ConvertRune) } -func IntSlice(key, sep string) []int { - res := make([]int, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseInt(s, 10, 64); err == nil { - res = append(res, int(v)) - } - } - return res +func IntSlice(key, sep string, defaultValue []int) []int { + return ObjectSlice(key, sep, defaultValue, ConvertInt) } -func Int8Slice(key, sep string) []int8 { - res := make([]int8, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseInt(s, 10, 64); err == nil { - res = append(res, int8(v)) - } - } - return res +func Int8Slice(key, sep string, defaultValue []int8) []int8 { + return ObjectSlice(key, sep, defaultValue, ConvertInt8) } -func Int16Slice(key, sep string) []int16 { - res := make([]int16, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseInt(s, 10, 64); err == nil { - res = append(res, int16(v)) - } - } - return res +func Int16Slice(key, sep string, defaultValue []int16) []int16 { + return ObjectSlice(key, sep, defaultValue, ConvertInt16) } -func Int32Slice(key, sep string) []int32 { - res := make([]int32, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseInt(s, 10, 64); err == nil { - res = append(res, int32(v)) - } - } - return res +func Int32Slice(key, sep string, defaultValue []int32) []int32 { + return ObjectSlice(key, sep, defaultValue, ConvertInt32) } -func Int64Slice(key, sep string) []int64 { - res := make([]int64, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseInt(s, 10, 64); err == nil { - res = append(res, v) - } - } - return res +func Int64Slice(key, sep string, defaultValue []int64) []int64 { + return ObjectSlice(key, sep, defaultValue, ConvertInt64) } -func Uint8Slice(key, sep string) []uint8 { - res := make([]uint8, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseUint(s, 10, 64); err == nil { - res = append(res, uint8(v)) - } - } - return res +func Uint8Slice(key, sep string, defaultValue []uint8) []uint8 { + return ObjectSlice(key, sep, defaultValue, ConvertUint8) } -func Uint16Slice(key, sep string) []uint16 { - res := make([]uint16, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseUint(s, 10, 64); err == nil { - res = append(res, uint16(v)) - } - } - return res +func Uint16Slice(key, sep string, defaultValue []uint16) []uint16 { + return ObjectSlice(key, sep, defaultValue, ConvertUint16) } -func Uint32Slice(key, sep string) []uint32 { - res := make([]uint32, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseUint(s, 10, 64); err == nil { - res = append(res, uint32(v)) - } - } - return res +func Uint32Slice(key, sep string, defaultValue []uint32) []uint32 { + return ObjectSlice(key, sep, defaultValue, ConvertUint32) } -func Uint64Slice(key, sep string) []uint64 { - res := make([]uint64, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseUint(s, 10, 64); err == nil { - res = append(res, v) - } - } - return res +func Uint64Slice(key, sep string, defaultValue []uint64) []uint64 { + return ObjectSlice(key, sep, defaultValue, ConvertUint64) } -func Float32Slice(key, sep string) []float32 { - res := make([]float32, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseFloat(s, 64); err == nil { - res = append(res, float32(v)) - } - } - return res +func Float32Slice(key, sep string, defaultValue []float32) []float32 { + return ObjectSlice(key, sep, defaultValue, ConvertFloat32) } -func Float64Slice(key, sep string) []float64 { - res := make([]float64, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseFloat(s, 64); err == nil { - res = append(res, v) - } - } - return res +func Float64Slice(key, sep string, defaultValue []float64) []float64 { + return ObjectSlice(key, sep, defaultValue, ConvertFloat64) } -func Complex64Slice(key, sep string) []complex64 { - res := make([]complex64, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseComplex(s, 64); err == nil { - res = append(res, complex64(v)) - } - } - return res +func Complex64Slice(key, sep string, defaultValue []complex64) []complex64 { + return ObjectSlice(key, sep, defaultValue, ConvertComplex64) } -func Complex128Slice(key, sep string) []complex128 { - res := make([]complex128, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseComplex(s, 64); err == nil { - res = append(res, v) - } - } - return res +func Complex128Slice(key, sep string, defaultValue []complex128) []complex128 { + return ObjectSlice(key, sep, defaultValue, ConvertComplex128) } -func BoolSlice(key, sep string) []bool { - res := make([]bool, 0) - for _, s := range StringSlice(key, sep) { - if v, err := strconv.ParseBool(s); err == nil { - res = append(res, v) - } - } - return res +func BoolSlice(key, sep string, defaultValue []bool) []bool { + return ObjectSlice(key, sep, defaultValue, ConvertBool) } -func ObjectSlice[T any](key, sep string, converter func(string) (T, error)) []T { - res := make([]T, 0) - for _, s := range StringSlice(key, sep) { - if v, err := converter(s); err == nil { - res = append(res, v) - } - } - return res +func TimeSlice(key, sep string, defaultValue []time.Time, layout string) []time.Time { + return ObjectSlice(key, sep, defaultValue, func(s string) (time.Time, error) { return time.Parse(layout, s) }) +} + +func DurationSlice(key, sep string, defaultValue []time.Duration) []time.Duration { + return ObjectSlice(key, sep, defaultValue, time.ParseDuration) } diff --git a/vars.go b/vars.go index 74062da..591dbd3 100644 --- a/vars.go +++ b/vars.go @@ -1,15 +1,9 @@ package envvars -import ( - "os" - "strconv" -) +import "time" func String(key, defaultValue string) string { - if v, ok := os.LookupEnv(key); ok { - return v - } - return defaultValue + return Object(key, defaultValue, ConvertString) } func Byte(key string, defaultValue byte) byte { @@ -17,143 +11,73 @@ func Byte(key string, defaultValue byte) byte { } func Rune(key string, defaultValue rune) rune { - for _, rn := range String(key, string(defaultValue)) { - return rn - } - return defaultValue -} - -func Int(key string, defaultValue int) int { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseInt(v, 10, 64); err == nil { - return int(v2) - } - } - return defaultValue -} - -func Int8(key string, defaultValue int8) int8 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseInt(v, 10, 64); err == nil { - return int8(v2) - } - } - return defaultValue -} - -func Int16(key string, defaultValue int16) int16 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseInt(v, 10, 64); err == nil { - return int16(v2) - } - } - return defaultValue -} - -func Int32(key string, defaultValue int32) int32 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseInt(v, 10, 64); err == nil { - return int32(v2) - } - } - return defaultValue + return Object(key, defaultValue, ConvertRune) } func Int64(key string, defaultValue int64) int64 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseInt(v, 10, 64); err == nil { - return v2 - } - } - return defaultValue + return Object(key, defaultValue, ConvertInt64) } -func Uint8(key string, defaultValue uint8) uint8 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseUint(v, 10, 64); err == nil { - return uint8(v2) - } - } - return defaultValue +func Int32(key string, defaultValue int32) int32 { + return Object(key, defaultValue, ConvertInt32) } -func Uint16(key string, defaultValue uint16) uint16 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseUint(v, 10, 64); err == nil { - return uint16(v2) - } - } - return defaultValue +func Int16(key string, defaultValue int16) int16 { + return Object(key, defaultValue, ConvertInt16) } -func Uint32(key string, defaultValue uint32) uint32 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseUint(v, 10, 64); err == nil { - return uint32(v2) - } - } - return defaultValue +func Int8(key string, defaultValue int8) int8 { + return Object(key, defaultValue, ConvertInt8) +} + +func Int(key string, defaultValue int) int { + return Object(key, defaultValue, ConvertInt) } func Uint64(key string, defaultValue uint64) uint64 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseUint(v, 10, 64); err == nil { - return v2 - } - } - return defaultValue + return Object(key, defaultValue, ConvertUint64) } -func Float32(key string, defaultValue float32) float32 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseFloat(v, 64); err == nil { - return float32(v2) - } - } - return defaultValue +func Uint32(key string, defaultValue uint32) uint32 { + return Object(key, defaultValue, ConvertUint32) +} + +func Uint16(key string, defaultValue uint16) uint16 { + return Object(key, defaultValue, ConvertUint16) +} + +func Uint8(key string, defaultValue uint8) uint8 { + return Object(key, defaultValue, ConvertUint8) +} + +func Uint(key string, defaultValue uint) uint { + return Object(key, defaultValue, ConvertUint) } func Float64(key string, defaultValue float64) float64 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseFloat(v, 64); err == nil { - return v2 - } - } - return defaultValue + return Object(key, defaultValue, ConvertFloat64) } -func Complex64(key string, defaultValue complex64) complex64 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseComplex(v, 64); err == nil { - return complex64(v2) - } - } - return defaultValue +func Float32(key string, defaultValue float32) float32 { + return Object(key, defaultValue, ConvertFloat32) } func Complex128(key string, defaultValue complex128) complex128 { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseComplex(v, 64); err == nil { - return v2 - } - } - return defaultValue + return Object(key, defaultValue, ConvertComplex128) +} + +func Complex64(key string, defaultValue complex64) complex64 { + return Object(key, defaultValue, ConvertComplex64) } func Bool(key string, defaultValue bool) bool { - if v, ok := os.LookupEnv(key); ok { - if v2, err := strconv.ParseBool(v); err == nil { - return v2 - } - } - return defaultValue + return Object(key, defaultValue, ConvertBool) } -func Object[T any](key string, defaultValue T, converter func(string) (T, error)) T { - if v, ok := os.LookupEnv(key); ok { - if v2, err := converter(v); err == nil { - return v2 - } - } - return defaultValue +func Time(key string, defaultValue time.Time, layout string) time.Time { + return Object(key, defaultValue, func(s string) (time.Time, error) { return time.Parse(layout, s) }) +} + +func Duration(key string, defaultValue time.Duration) time.Duration { + return Object(key, defaultValue, time.ParseDuration) }