forked from vmware/govmomi
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch introduces the type OptionValueList in the object package. This new type simplifies working with []vimtypes.BaseOptionValue properties such as ExtraConfig.
- Loading branch information
Showing
2 changed files
with
809 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/* | ||
Copyright (c) 2024-2024 VMware, Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package object | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
|
||
"github.com/vmware/govmomi/vim25/types" | ||
) | ||
|
||
// OptionValueList simplifies manipulation of properties that are arrays of | ||
// types.BaseOptionValue, such as ExtraConfig. | ||
type OptionValueList []types.BaseOptionValue | ||
|
||
// OptionValueListFromMap returns a new OptionValueList object from the provided | ||
// map. | ||
func OptionValueListFromMap[T any](in map[string]T) OptionValueList { | ||
if len(in) == 0 { | ||
return nil | ||
} | ||
var ( | ||
i int | ||
out = make(OptionValueList, len(in)) | ||
) | ||
for k, v := range in { | ||
out[i] = &types.OptionValue{Key: k, Value: v} | ||
i++ | ||
} | ||
return out | ||
} | ||
|
||
// Get returns the value if exists, otherwise nil is returned. The second return | ||
// value is a flag indicating whether the value exists or nil was the actual | ||
// value. | ||
func (ov OptionValueList) Get(key string) (any, bool) { | ||
if ov == nil { | ||
return nil, false | ||
} | ||
for i := range ov { | ||
if optVal := ov[i].GetOptionValue(); optVal != nil { | ||
if optVal.Key == key { | ||
return optVal.Value, true | ||
} | ||
} | ||
} | ||
return nil, false | ||
} | ||
|
||
// GetString returns the value as a string if the value exists. | ||
func (ov OptionValueList) GetString(key string) (string, bool) { | ||
if ov == nil { | ||
return "", false | ||
} | ||
for i := range ov { | ||
if optVal := ov[i].GetOptionValue(); optVal != nil { | ||
if optVal.Key == key { | ||
return getOptionValueAsString(optVal.Value), true | ||
} | ||
} | ||
} | ||
return "", false | ||
} | ||
|
||
// Additions returns a diff that includes only the elements from the provided | ||
// list that do not already exist. | ||
func (ov OptionValueList) Additions(in ...types.BaseOptionValue) OptionValueList { | ||
return ov.diff(in, true) | ||
} | ||
|
||
// Diff returns a diff that includes the elements from the provided list that do | ||
// not already exist or have different values. | ||
func (ov OptionValueList) Diff(in ...types.BaseOptionValue) OptionValueList { | ||
return ov.diff(in, false) | ||
} | ||
|
||
func (ov OptionValueList) diff(in OptionValueList, addOnly bool) OptionValueList { | ||
if ov == nil && in == nil { | ||
return nil | ||
} | ||
var ( | ||
out OptionValueList | ||
leftOptVals = ov.Map() | ||
) | ||
for i := range in { | ||
if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil { | ||
k, v := rightOptVal.Key, rightOptVal.Value | ||
if ov == nil { | ||
out = append(out, &types.OptionValue{Key: k, Value: v}) | ||
} else if leftOptVal, ok := leftOptVals[k]; !ok { | ||
out = append(out, &types.OptionValue{Key: k, Value: v}) | ||
} else if !addOnly && v != leftOptVal { | ||
out = append(out, &types.OptionValue{Key: k, Value: v}) | ||
} | ||
} | ||
} | ||
if len(out) == 0 { | ||
return nil | ||
} | ||
return out | ||
} | ||
|
||
// Join combines this list with the provided one and returns the result, joining | ||
// the two lists on their shared keys. | ||
// Please note, Join(left, right) means the values from right will be appended | ||
// to left, without overwriting any values that have shared keys. To overwrite | ||
// the shared keys in left from right, use Join(right, left) instead. | ||
func (ov OptionValueList) Join(in ...types.BaseOptionValue) OptionValueList { | ||
var ( | ||
out OptionValueList | ||
outKeys map[string]struct{} | ||
) | ||
|
||
// Init the out slice from the left side. | ||
if len(ov) > 0 { | ||
outKeys = map[string]struct{}{} | ||
for i := range ov { | ||
if optVal := ov[i].GetOptionValue(); optVal != nil { | ||
kv := &types.OptionValue{Key: optVal.Key, Value: optVal.Value} | ||
out = append(out, kv) | ||
outKeys[optVal.Key] = struct{}{} | ||
} | ||
} | ||
} | ||
|
||
// Join the values from the right side. | ||
for i := range in { | ||
if rightOptVal := in[i].GetOptionValue(); rightOptVal != nil { | ||
k, v := rightOptVal.Key, rightOptVal.Value | ||
if _, ok := outKeys[k]; !ok { | ||
out = append(out, &types.OptionValue{Key: k, Value: v}) | ||
} | ||
} | ||
} | ||
|
||
if len(out) == 0 { | ||
return nil | ||
} | ||
|
||
return out | ||
} | ||
|
||
// Map returns the list of option values as a map. A nil value is returned if | ||
// the list is empty. | ||
func (ov OptionValueList) Map() map[string]any { | ||
if len(ov) == 0 { | ||
return nil | ||
} | ||
out := map[string]any{} | ||
for i := range ov { | ||
if optVal := ov[i].GetOptionValue(); optVal != nil { | ||
out[optVal.Key] = optVal.Value | ||
} | ||
} | ||
if len(out) == 0 { | ||
return nil | ||
} | ||
return out | ||
} | ||
|
||
// StringMap returns the list of option values as a map where the values are | ||
// strings. A nil value is returned if the list is empty. | ||
func (ov OptionValueList) StringMap() map[string]string { | ||
if len(ov) == 0 { | ||
return nil | ||
} | ||
out := map[string]string{} | ||
for i := range ov { | ||
if optVal := ov[i].GetOptionValue(); optVal != nil { | ||
out[optVal.Key] = getOptionValueAsString(optVal.Value) | ||
} | ||
} | ||
if len(out) == 0 { | ||
return nil | ||
} | ||
return out | ||
} | ||
|
||
func getOptionValueAsString(val any) string { | ||
switch tval := val.(type) { | ||
case string: | ||
return tval | ||
default: | ||
if rv := reflect.ValueOf(val); rv.Kind() == reflect.Pointer { | ||
if rv.IsNil() { | ||
return "" | ||
} | ||
return fmt.Sprintf("%v", rv.Elem().Interface()) | ||
} | ||
return fmt.Sprintf("%v", tval) | ||
} | ||
} |
Oops, something went wrong.