github.com/vmware/govmomi@v0.51.0/object/option_value_list.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package object
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"slices"
    11  	"strings"
    12  
    13  	"github.com/vmware/govmomi/vim25/types"
    14  )
    15  
    16  // OptionValueList simplifies manipulation of properties that are arrays of
    17  // types.BaseOptionValue, such as ExtraConfig.
    18  type OptionValueList []types.BaseOptionValue
    19  
    20  // OptionValueListFromMap returns a new OptionValueList object from the provided
    21  // map.
    22  func OptionValueListFromMap[T any](in map[string]T) OptionValueList {
    23  	if len(in) == 0 {
    24  		return nil
    25  	}
    26  	var (
    27  		i   int
    28  		out = make(OptionValueList, len(in))
    29  	)
    30  	for k, v := range in {
    31  		out[i] = &types.OptionValue{Key: k, Value: v}
    32  		i++
    33  	}
    34  	return out
    35  }
    36  
    37  // IsTrue returns true if the specified key exists with an empty value or value
    38  // equal to 1, "1", "on", "t", true, "true", "y", or "yes".
    39  // All string comparisons are case-insensitive.
    40  func (ov OptionValueList) IsTrue(key string) bool {
    41  	return ov.isTrueOrFalse(key, true, 1, "", "1", "on", "t", "true", "y", "yes")
    42  }
    43  
    44  // IsFalse returns true if the specified key exists and has a value equal to
    45  // 0, "0", "f", false, "false", "n", "no", or "off".
    46  // All string comparisons are case-insensitive.
    47  func (ov OptionValueList) IsFalse(key string) bool {
    48  	return ov.isTrueOrFalse(key, false, 0, "0", "f", "false", "n", "no", "off")
    49  }
    50  
    51  func (ov OptionValueList) isTrueOrFalse(
    52  	key string,
    53  	boolVal bool,
    54  	numVal int,
    55  	strVals ...string) bool {
    56  
    57  	val, ok := ov.Get(key)
    58  	if !ok {
    59  		return false
    60  	}
    61  
    62  	switch tval := val.(type) {
    63  	case string:
    64  		return slices.Contains(strVals, strings.ToLower(tval))
    65  	case bool:
    66  		return tval == boolVal
    67  	case uint:
    68  		return tval == uint(numVal)
    69  	case uint8:
    70  		return tval == uint8(numVal)
    71  	case uint16:
    72  		return tval == uint16(numVal)
    73  	case uint32:
    74  		return tval == uint32(numVal)
    75  	case uint64:
    76  		return tval == uint64(numVal)
    77  	case int:
    78  		return tval == int(numVal)
    79  	case int8:
    80  		return tval == int8(numVal)
    81  	case int16:
    82  		return tval == int16(numVal)
    83  	case int32:
    84  		return tval == int32(numVal)
    85  	case int64:
    86  		return tval == int64(numVal)
    87  	case float32:
    88  		return tval == float32(numVal)
    89  	case float64:
    90  		return tval == float64(numVal)
    91  	}
    92  
    93  	return false
    94  }
    95  
    96  // Get returns the value if exists, otherwise nil is returned. The second return
    97  // value is a flag indicating whether the value exists or nil was the actual
    98  // value.
    99  func (ov OptionValueList) Get(key string) (any, bool) {
   100  	if ov == nil {
   101  		return nil, false
   102  	}
   103  	for i := range ov {
   104  		if optVal := ov[i].GetOptionValue(); optVal != nil {
   105  			if optVal.Key == key {
   106  				return optVal.Value, true
   107  			}
   108  		}
   109  	}
   110  	return nil, false
   111  }
   112  
   113  // GetString returns the value as a string if the value exists.
   114  func (ov OptionValueList) GetString(key string) (string, bool) {
   115  	if ov == nil {
   116  		return "", false
   117  	}
   118  	for i := range ov {
   119  		if optVal := ov[i].GetOptionValue(); optVal != nil {
   120  			if optVal.Key == key {
   121  				return getOptionValueAsString(optVal.Value), true
   122  			}
   123  		}
   124  	}
   125  	return "", false
   126  }
   127  
   128  // Additions returns a diff that includes only the elements from the provided
   129  // list that do not already exist.
   130  func (ov OptionValueList) Additions(in ...types.BaseOptionValue) OptionValueList {
   131  	return ov.diff(in, true)
   132  }
   133  
   134  // Diff returns a diff that includes the elements from the provided list that do
   135  // not already exist or have different values.
   136  func (ov OptionValueList) Diff(in ...types.BaseOptionValue) OptionValueList {
   137  	return ov.diff(in, false)
   138  }
   139  
   140  func (ov OptionValueList) diff(in OptionValueList, addOnly bool) OptionValueList {
   141  	if ov == nil && in == nil {
   142  		return nil
   143  	}
   144  	var (
   145  		out         OptionValueList
   146  		leftOptVals = ov.Map()
   147  	)
   148  	for i := range in {
   149  		if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil {
   150  			k, v := rightOptVal.Key, rightOptVal.Value
   151  			if ov == nil {
   152  				out = append(out, &types.OptionValue{Key: k, Value: v})
   153  			} else if leftOptVal, ok := leftOptVals[k]; !ok {
   154  				out = append(out, &types.OptionValue{Key: k, Value: v})
   155  			} else if !addOnly && v != leftOptVal {
   156  				out = append(out, &types.OptionValue{Key: k, Value: v})
   157  			}
   158  		}
   159  	}
   160  	if len(out) == 0 {
   161  		return nil
   162  	}
   163  	return out
   164  }
   165  
   166  // Join combines this list with the provided one and returns the result, joining
   167  // the two lists on their shared keys.
   168  // Please note, Join(left, right) means the values from right will be appended
   169  // to left, without overwriting any values that have shared keys. To overwrite
   170  // the shared keys in left from right, use Join(right, left) instead.
   171  func (ov OptionValueList) Join(in ...types.BaseOptionValue) OptionValueList {
   172  	var (
   173  		out     OptionValueList
   174  		outKeys map[string]struct{}
   175  	)
   176  
   177  	// Init the out slice from the left side.
   178  	if len(ov) > 0 {
   179  		outKeys = map[string]struct{}{}
   180  		for i := range ov {
   181  			if optVal := ov[i].GetOptionValue(); optVal != nil {
   182  				kv := &types.OptionValue{Key: optVal.Key, Value: optVal.Value}
   183  				out = append(out, kv)
   184  				outKeys[optVal.Key] = struct{}{}
   185  			}
   186  		}
   187  	}
   188  
   189  	// Join the values from the right side.
   190  	for i := range in {
   191  		if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil {
   192  			k, v := rightOptVal.Key, rightOptVal.Value
   193  			if _, ok := outKeys[k]; !ok {
   194  				out = append(out, &types.OptionValue{Key: k, Value: v})
   195  			}
   196  		}
   197  	}
   198  
   199  	if len(out) == 0 {
   200  		return nil
   201  	}
   202  
   203  	return out
   204  }
   205  
   206  // Map returns the list of option values as a map. A nil value is returned if
   207  // the list is empty.
   208  func (ov OptionValueList) Map() map[string]any {
   209  	if len(ov) == 0 {
   210  		return nil
   211  	}
   212  	out := map[string]any{}
   213  	for i := range ov {
   214  		if optVal := ov[i].GetOptionValue(); optVal != nil {
   215  			out[optVal.Key] = optVal.Value
   216  		}
   217  	}
   218  	if len(out) == 0 {
   219  		return nil
   220  	}
   221  	return out
   222  }
   223  
   224  // StringMap returns the list of option values as a map where the values are
   225  // strings. A nil value is returned if the list is empty.
   226  func (ov OptionValueList) StringMap() map[string]string {
   227  	if len(ov) == 0 {
   228  		return nil
   229  	}
   230  	out := map[string]string{}
   231  	for i := range ov {
   232  		if optVal := ov[i].GetOptionValue(); optVal != nil {
   233  			out[optVal.Key] = getOptionValueAsString(optVal.Value)
   234  		}
   235  	}
   236  	if len(out) == 0 {
   237  		return nil
   238  	}
   239  	return out
   240  }
   241  
   242  func getOptionValueAsString(val any) string {
   243  	switch tval := val.(type) {
   244  	case string:
   245  		return tval
   246  	default:
   247  		if rv := reflect.ValueOf(val); rv.Kind() == reflect.Pointer {
   248  			if rv.IsNil() {
   249  				return ""
   250  			}
   251  			return fmt.Sprintf("%v", rv.Elem().Interface())
   252  		}
   253  		return fmt.Sprintf("%v", tval)
   254  	}
   255  }