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  }