github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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]any
    46  
    47  // GenerateFromModel takes the generic options, and tries to build a new
    48  // instance of the model's type by matching keys from the generic options to
    49  // fields in the model.
    50  //
    51  // The return value is of the same type than the model (including a potential
    52  // pointer qualifier).
    53  func GenerateFromModel(options Generic, model interface{}) (interface{}, error) {
    54  	modType := reflect.TypeOf(model)
    55  
    56  	// If the model is of pointer type, we need to dereference for New.
    57  	resType := reflect.TypeOf(model)
    58  	if modType.Kind() == reflect.Ptr {
    59  		resType = resType.Elem()
    60  	}
    61  
    62  	// Populate the result structure with the generic layout content.
    63  	res := reflect.New(resType)
    64  	for name, value := range options {
    65  		field := res.Elem().FieldByName(name)
    66  		if !field.IsValid() {
    67  			return nil, NoSuchFieldError{name, resType.String()}
    68  		}
    69  		if !field.CanSet() {
    70  			return nil, CannotSetFieldError{name, resType.String()}
    71  		}
    72  		if reflect.TypeOf(value) != field.Type() {
    73  			return nil, TypeMismatchError{name, field.Type().String(), reflect.TypeOf(value).String()}
    74  		}
    75  		field.Set(reflect.ValueOf(value))
    76  	}
    77  
    78  	// If the model is not of pointer type, return content of the result.
    79  	if modType.Kind() == reflect.Ptr {
    80  		return res.Interface(), nil
    81  	}
    82  	return res.Elem().Interface(), nil
    83  }