github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/env/env_decoder.go (about) 1 package env 2 3 import ( 4 "go/ast" 5 "reflect" 6 7 "github.com/machinefi/w3bstream/pkg/depends/base/types" 8 "github.com/machinefi/w3bstream/pkg/depends/x/reflectx" 9 "github.com/machinefi/w3bstream/pkg/depends/x/textx" 10 ) 11 12 type Decoder struct{ vars *Vars } 13 14 func NewDecoder(vs *Vars) *Decoder { return &Decoder{vars: vs} } 15 16 func (d *Decoder) Decode(v interface{}) error { 17 w := NewPathWalker() 18 19 rv, ok := v.(reflect.Value) 20 if !ok { 21 rv = reflect.ValueOf(v) 22 } 23 return d.scan(w, rv) 24 } 25 26 // scan scan and set value 27 func (d *Decoder) scan(w *PathWalker, rv reflect.Value) error { 28 kind := rv.Kind() 29 30 if kind != reflect.Ptr && rv.CanAddr() { 31 if v, ok := rv.Addr().Interface().(types.DefaultSetter); ok { 32 v.SetDefault() 33 } 34 } 35 36 switch kind { 37 case reflect.Ptr: 38 if rv.IsNil() { 39 rv.Set(reflectx.New(rv.Type())) 40 } 41 return d.scan(w, rv.Elem()) 42 case reflect.Func, reflect.Interface, reflect.Chan, reflect.Map: 43 // skip 44 default: 45 rt := rv.Type() 46 if rt.Implements(types.RTypeTextUnmarshaler) || 47 reflect.PtrTo(rt).Implements(types.RTypeTextUnmarshaler) { 48 if v := d.vars.Get(w.String()); v != nil && v.Value != "" { 49 return textx.UnmarshalText(rv, []byte(v.Value)) 50 } 51 return nil 52 } 53 switch kind { 54 case reflect.Array, reflect.Slice: 55 size := d.vars.Len(w.String()) 56 if kind == reflect.Slice && rv.IsNil() && size > 0 { 57 rv.Set(reflect.MakeSlice(rv.Type(), size, size)) 58 } 59 for i := 0; i < rv.Len(); i++ { 60 w.Enter(i) 61 if err := d.scan(w, rv.Index(i)); err != nil { 62 return err 63 } 64 w.Exit() 65 } 66 case reflect.Struct: 67 for i := 0; i < rv.NumField(); i++ { 68 var flags map[string]bool 69 ft := rt.Field(i) 70 name := ft.Name 71 if !ast.IsExported(name) { 72 continue 73 } 74 if tag, ok := ft.Tag.Lookup("env"); ok { 75 key, _flags := reflectx.TagValueAndFlags(tag) 76 if key == "-" { 77 continue 78 } 79 if key != "" { 80 name = key 81 } 82 flags = _flags 83 } 84 inline := flags == nil && ft.Anonymous && 85 reflectx.DeRef(ft.Type).Kind() == reflect.Struct 86 if !inline { 87 w.Enter(name) 88 } 89 if err := d.scan(w, rv.Field(i)); err != nil { 90 return err 91 } 92 if !inline { 93 w.Exit() 94 } 95 } 96 default: 97 if v := d.vars.Get(w.String()); v != nil && v.Value != "" { 98 return textx.UnmarshalText(rv, []byte(v.Value)) 99 } 100 } 101 } 102 return nil 103 }