github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/options.go (about)

     1  package eval
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"src.elv.sh/pkg/eval/vals"
     8  	"src.elv.sh/pkg/parse"
     9  	"src.elv.sh/pkg/strutil"
    10  )
    11  
    12  // RawOptions is the type of an argument a Go-native function can take to
    13  // declare that it wants to parse options itself. See the doc of NewGoFn for
    14  // details.
    15  type RawOptions map[string]interface{}
    16  
    17  // Takes a raw option map and a pointer to a struct, and populate the struct
    18  // with options. A field named FieldName corresponds to the option named
    19  // field-name, unless the field has a explicit "name" tag. Fields typed
    20  // ParsedOptions are ignored.
    21  func scanOptions(rawOpts RawOptions, ptr interface{}) error {
    22  	ptrValue := reflect.ValueOf(ptr)
    23  	if ptrValue.Kind() != reflect.Ptr || ptrValue.Elem().Kind() != reflect.Struct {
    24  		return fmt.Errorf(
    25  			"internal bug: need struct ptr to scan options, got %T", ptr)
    26  	}
    27  
    28  	// fieldIdxForOpt maps option name to the index of field in `struc`.
    29  	fieldIdxForOpt := make(map[string]int)
    30  	struc := ptrValue.Elem()
    31  	for i := 0; i < struc.Type().NumField(); i++ {
    32  		if !struc.Field(i).CanSet() {
    33  			continue // ignore unexported fields
    34  		}
    35  
    36  		f := struc.Type().Field(i)
    37  		optName := f.Tag.Get("name")
    38  		if optName == "" {
    39  			optName = strutil.CamelToDashed(f.Name)
    40  		}
    41  		fieldIdxForOpt[optName] = i
    42  	}
    43  
    44  	for k, v := range rawOpts {
    45  		fieldIdx, ok := fieldIdxForOpt[k]
    46  		if !ok {
    47  			return fmt.Errorf("unknown option %s", parse.Quote(k))
    48  		}
    49  		err := vals.ScanToGo(v, struc.Field(fieldIdx).Addr().Interface())
    50  		if err != nil {
    51  			return err
    52  		}
    53  	}
    54  	return nil
    55  }