src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/options.go (about)

     1  package eval
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"src.elv.sh/pkg/eval/vals"
     7  	"src.elv.sh/pkg/parse"
     8  )
     9  
    10  // UnknownOption is thrown by a native function when called with an unknown option.
    11  type UnknownOption struct {
    12  	OptName string
    13  }
    14  
    15  // Error implements the error interface.
    16  func (e UnknownOption) Error() string {
    17  	return "unknown option: " + parse.Quote(e.OptName)
    18  }
    19  
    20  // RawOptions is the type of an argument a Go-native function can take to
    21  // declare that it wants to parse options itself. See the doc of NewGoFn for
    22  // details.
    23  type RawOptions map[string]any
    24  
    25  // Takes a raw option map and a pointer to a struct, and populate the struct
    26  // with options. A field named FieldName corresponds to the option named
    27  // field-name. Options that don't have corresponding fields in the struct causes
    28  // an error.
    29  //
    30  // Similar to vals.ScanMapToGo, but requires rawOpts to contain a subset of keys
    31  // supported by the struct.
    32  func scanOptions(rawOpts RawOptions, ptr any) error {
    33  	_, keyIdx := vals.StructFieldsInfo(reflect.TypeOf(ptr).Elem())
    34  	structValue := reflect.ValueOf(ptr).Elem()
    35  	for k, v := range rawOpts {
    36  		fieldIdx, ok := keyIdx[k]
    37  		if !ok {
    38  			return UnknownOption{k}
    39  		}
    40  
    41  		err := vals.ScanToGo(v, structValue.Field(fieldIdx).Addr().Interface())
    42  		if err != nil {
    43  			return err
    44  		}
    45  	}
    46  	return nil
    47  }