github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/libnetwork/options/options.go (about)

     1  // Package options provides a way to pass unstructured sets of options to a
     2  // component expecting a strongly-typed configuration structure.
     3  package options
     4  
     5  import (
     6  	"fmt"
     7  	"reflect"
     8  )
     9  
    10  // NoSuchFieldError is the error returned when the generic parameters hold a
    11  // value for a field absent from the destination structure.
    12  type NoSuchFieldError struct {
    13  	Field string
    14  	Type  string
    15  }
    16  
    17  func (e NoSuchFieldError) Error() string {
    18  	return fmt.Sprintf("no field %q in type %q", e.Field, e.Type)
    19  }
    20  
    21  // CannotSetFieldError is the error returned when the generic parameters hold a
    22  // value for a field that cannot be set in the destination structure.
    23  type CannotSetFieldError struct {
    24  	Field string
    25  	Type  string
    26  }
    27  
    28  func (e CannotSetFieldError) Error() string {
    29  	return fmt.Sprintf("cannot set field %q of type %q", e.Field, e.Type)
    30  }
    31  
    32  // TypeMismatchError is the error returned when the type of the generic value
    33  // for a field mismatches the type of the destination structure.
    34  type TypeMismatchError struct {
    35  	Field      string
    36  	ExpectType string
    37  	ActualType string
    38  }
    39  
    40  func (e TypeMismatchError) Error() string {
    41  	return fmt.Sprintf("type mismatch, field %s require type %v, actual type %v", e.Field, e.ExpectType, e.ActualType)
    42  }
    43  
    44  // Generic is a basic type to store arbitrary settings.
    45  type Generic map[string]interface{}
    46  
    47  // NewGeneric returns a new Generic instance.
    48  func NewGeneric() Generic {
    49  	return make(Generic)
    50  }
    51  
    52  // GenerateFromModel takes the generic options, and tries to build a new
    53  // instance of the model's type by matching keys from the generic options to
    54  // fields in the model.
    55  //
    56  // The return value is of the same type than the model (including a potential
    57  // pointer qualifier).
    58  func GenerateFromModel(options Generic, model interface{}) (interface{}, error) {
    59  	modType := reflect.TypeOf(model)
    60  
    61  	// If the model is of pointer type, we need to dereference for New.
    62  	resType := reflect.TypeOf(model)
    63  	if modType.Kind() == reflect.Ptr {
    64  		resType = resType.Elem()
    65  	}
    66  
    67  	// Populate the result structure with the generic layout content.
    68  	res := reflect.New(resType)
    69  	for name, value := range options {
    70  		field := res.Elem().FieldByName(name)
    71  		if !field.IsValid() {
    72  			return nil, NoSuchFieldError{name, resType.String()}
    73  		}
    74  		if !field.CanSet() {
    75  			return nil, CannotSetFieldError{name, resType.String()}
    76  		}
    77  		if reflect.TypeOf(value) != field.Type() {
    78  			return nil, TypeMismatchError{name, field.Type().String(), reflect.TypeOf(value).String()}
    79  		}
    80  		field.Set(reflect.ValueOf(value))
    81  	}
    82  
    83  	// If the model is not of pointer type, return content of the result.
    84  	if modType.Kind() == reflect.Ptr {
    85  		return res.Interface(), nil
    86  	}
    87  	return res.Elem().Interface(), nil
    88  }