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 }