elvish/eval/raw_options.go

53 lines
1.3 KiB
Go
Raw Normal View History

2018-02-15 17:16:41 +08:00
package eval
import (
"errors"
"reflect"
2018-09-27 08:48:44 +08:00
"github.com/elves/elvish/eval/vals"
2018-02-15 17:16:41 +08:00
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
var ErrNoOptAccepted = errors.New("function does not accept any options")
type RawOptions map[string]interface{}
// Scan takes a pointer to a struct and scan options into it. A field named
// FieldName corresponds to the option named field-name, unless the field has a
// explicit "name" tag. Fields typed ParsedOptions are ignored.
func (rawOpts RawOptions) Scan(ptr interface{}) {
ptrValue := reflect.ValueOf(ptr)
2018-02-15 17:16:41 +08:00
if ptrValue.Kind() != reflect.Ptr || ptrValue.Elem().Kind() != reflect.Struct {
throwf("internal bug: need struct ptr to scan options, got %T", ptr)
2018-02-15 17:16:41 +08:00
}
struc := ptrValue.Elem()
// fieldIdxForOpt maps option name to the index of field in struc.
fieldIdxForOpt := make(map[string]int)
for i := 0; i < struc.Type().NumField(); i++ {
// ignore unexported fields
if !struc.Field(i).CanSet() {
continue
}
f := struc.Type().Field(i)
optName := f.Tag.Get("name")
if optName == "" {
optName = util.CamelToDashed(f.Name)
}
fieldIdxForOpt[optName] = i
}
for k, v := range rawOpts {
2018-02-15 17:16:41 +08:00
fieldIdx, ok := fieldIdxForOpt[k]
if !ok {
throwf("unknown option %s", parse.Quote(k))
}
2018-09-27 08:48:44 +08:00
err := vals.ScanToGo(v, struc.Field(fieldIdx).Addr().Interface())
if err != nil {
throw(err)
}
2018-02-15 17:16:41 +08:00
}
}