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

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