reflect.go raw
1 package env
2
3 import (
4 "encoding"
5 "fmt"
6 "reflect"
7 "strconv"
8 "time"
9 )
10
11 var (
12 durationType = reflect.TypeOf(new(time.Duration)).Elem()
13 unmarshalerIface = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
14 )
15
16 func typeOf(v reflect.Value, types ...reflect.Type) bool {
17 for _, t := range types {
18 if t == v.Type() {
19 return true
20 }
21 }
22 return false
23 }
24
25 func kindOf(v reflect.Value, kinds ...reflect.Kind) bool {
26 for _, k := range kinds {
27 if k == v.Kind() {
28 return true
29 }
30 }
31 return false
32 }
33
34 func implements(v reflect.Value, ifaces ...reflect.Type) bool {
35 for _, iface := range ifaces {
36 if t := v.Type(); t.Implements(iface) || reflect.PtrTo(t).Implements(iface) {
37 return true
38 }
39 }
40 return false
41 }
42
43 func structPtr(v reflect.Value) bool {
44 return v.IsValid() && v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct && !v.IsNil()
45 }
46
47 func setValue(v reflect.Value, s string) error {
48 switch {
49 case typeOf(v, durationType):
50 return setDuration(v, s)
51 case implements(v, unmarshalerIface):
52 return setUnmarshaler(v, s)
53 case kindOf(v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64):
54 return setInt(v, s)
55 case kindOf(v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64):
56 return setUint(v, s)
57 case kindOf(v, reflect.Float32, reflect.Float64):
58 return setFloat(v, s)
59 case kindOf(v, reflect.Bool):
60 return setBool(v, s)
61 case kindOf(v, reflect.String):
62 return setString(v, s)
63 default:
64 panic(fmt.Sprintf("env: unsupported type `%s`", v.Type()))
65 }
66 }
67
68 func setInt(v reflect.Value, s string) error {
69 i, err := strconv.ParseInt(s, 10, v.Type().Bits())
70 if err != nil {
71 return fmt.Errorf("parsing int: %w", err)
72 }
73 v.SetInt(i)
74 return nil
75 }
76
77 func setUint(v reflect.Value, s string) error {
78 u, err := strconv.ParseUint(s, 10, v.Type().Bits())
79 if err != nil {
80 return fmt.Errorf("parsing uint: %w", err)
81 }
82 v.SetUint(u)
83 return nil
84 }
85
86 func setFloat(v reflect.Value, s string) error {
87 f, err := strconv.ParseFloat(s, v.Type().Bits())
88 if err != nil {
89 return fmt.Errorf("parsing float: %w", err)
90 }
91 v.SetFloat(f)
92 return nil
93 }
94
95 func setBool(v reflect.Value, s string) error {
96 b, err := strconv.ParseBool(s)
97 if err != nil {
98 return fmt.Errorf("parsing bool: %w", err)
99 }
100 v.SetBool(b)
101 return nil
102 }
103
104 func setString(v reflect.Value, s string) error {
105 v.SetString(s)
106 return nil
107 }
108
109 func setDuration(v reflect.Value, s string) error {
110 d, err := time.ParseDuration(s)
111 if err != nil {
112 return fmt.Errorf("parsing duration: %w", err)
113 }
114 v.Set(reflect.ValueOf(d))
115 return nil
116 }
117
118 func setUnmarshaler(v reflect.Value, s string) error {
119 u := v.Addr().Interface().(encoding.TextUnmarshaler)
120 if err := u.UnmarshalText([]byte(s)); err != nil {
121 return fmt.Errorf("unmarshaling text: %w", err)
122 }
123 return nil
124 }
125
126 func setSlice(v reflect.Value, s []string) error {
127 slice := reflect.MakeSlice(v.Type(), len(s), cap(s))
128 for i := 0; i < slice.Len(); i++ {
129 if err := setValue(slice.Index(i), s[i]); err != nil {
130 return err
131 }
132 }
133 v.Set(slice)
134 return nil
135 }
136