github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/raw_options.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "reflect" 6 7 "github.com/u-root/u-root/cmds/core/elvish/parse" 8 "github.com/u-root/u-root/cmds/core/elvish/util" 9 ) 10 11 type RawOptions map[string]interface{} 12 13 // Scan takes a pointer to a struct and scan options into it. A field 14 // named FieldName corresponds to the option named field-name, unless the field 15 // has a explicit "name" tag. 16 func (rawOpts RawOptions) Scan(ptr interface{}) { 17 ptrValue := reflect.ValueOf(ptr) 18 if ptrValue.Kind() != reflect.Ptr || ptrValue.Elem().Kind() != reflect.Struct { 19 throwf("internal bug: need struct ptr to scan options, got %T", ptr) 20 } 21 struc := ptrValue.Elem() 22 23 // fieldIdxForOpt maps option name to the index of field in struc. 24 fieldIdxForOpt := make(map[string]int) 25 for i := 0; i < struc.Type().NumField(); i++ { 26 // ignore unexported fields 27 if !struc.Field(i).CanSet() { 28 continue 29 } 30 31 f := struc.Type().Field(i) 32 optName := f.Tag.Get("name") 33 if optName == "" { 34 optName = util.CamelToDashed(f.Name) 35 } 36 fieldIdxForOpt[optName] = i 37 } 38 39 for k, v := range rawOpts { 40 fieldIdx, ok := fieldIdxForOpt[k] 41 if !ok { 42 throwf("unknown option %s", parse.Quote(k)) 43 } 44 mustScanToGo(v, struc.Field(fieldIdx).Addr().Interface()) 45 } 46 } 47 48 var ErrNoOptAccepted = errors.New("no option accepted") 49 50 func TakeNoOpt(opts map[string]interface{}) { 51 if len(opts) > 0 { 52 throw(ErrNoOptAccepted) 53 } 54 }