176 lines
4.6 KiB
Go
176 lines
4.6 KiB
Go
|
/**
|
||
|
* Copyright 2016 IBM Corp.
|
||
|
*
|
||
|
* 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 sl has convenience functions for returning pointers to values
|
||
|
package sl
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/softlayer/softlayer-go/datatypes"
|
||
|
)
|
||
|
|
||
|
// Int returns a pointer to the int value provided
|
||
|
func Int(v int) *int {
|
||
|
return &v
|
||
|
}
|
||
|
|
||
|
// Uint returns a pointer to the uint value provided
|
||
|
func Uint(v uint) *uint {
|
||
|
return &v
|
||
|
}
|
||
|
|
||
|
// String returns a pointer to the string value provided
|
||
|
func String(v string) *string {
|
||
|
return &v
|
||
|
}
|
||
|
|
||
|
// Bool returns a pointer to the bool value provided
|
||
|
func Bool(v bool) *bool {
|
||
|
return &v
|
||
|
}
|
||
|
|
||
|
// Time converts the time.Time value provided to a datatypes.Time value,
|
||
|
// and returns a pointer to it
|
||
|
func Time(v time.Time) *datatypes.Time {
|
||
|
r := datatypes.Time{Time: v}
|
||
|
return &r
|
||
|
}
|
||
|
|
||
|
// Float converts the float value provided to a datatypes.Float64 value,
|
||
|
// and returns a pointer to it
|
||
|
func Float(v float64) *datatypes.Float64 {
|
||
|
r := datatypes.Float64(v)
|
||
|
return &r
|
||
|
}
|
||
|
|
||
|
// Convenience functions to simplify dereference of datatype properties
|
||
|
|
||
|
// Get returns the value of p, either p itself, or, if p is a pointer, the
|
||
|
// value that p points to. d is an optional default value to be returned
|
||
|
// in the event that p is nil. If d is not specified, and p is nil, a
|
||
|
// type-appropriate zero-value is returned instead.
|
||
|
func Get(p interface{}, d ...interface{}) interface{} {
|
||
|
var (
|
||
|
val interface{}
|
||
|
ok bool
|
||
|
)
|
||
|
|
||
|
if val, ok = GetOk(p); ok {
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
if len(d) > 0 {
|
||
|
return d[0]
|
||
|
}
|
||
|
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
// GetOk returns the value of p, either p itself, or, if p is a pointer, the
|
||
|
// value that p points to. If p is nil, a type-appropriate zero-value is
|
||
|
// returned instead. If p is a value or non-nil pointer, the second return
|
||
|
// value will be true. Otherwise, it will be false.
|
||
|
func GetOk(p interface{}) (interface{}, bool) {
|
||
|
t := reflect.TypeOf(p)
|
||
|
|
||
|
// if p is a non-pointer, just return it
|
||
|
if t.Kind() != reflect.Ptr {
|
||
|
return p, true
|
||
|
}
|
||
|
|
||
|
// p is a pointer. If non-nil, return the value pointed to
|
||
|
v := reflect.Indirect(reflect.ValueOf(p))
|
||
|
if v.IsValid() {
|
||
|
return v.Interface(), true
|
||
|
}
|
||
|
|
||
|
// p is a nil pointer. Return the zero value for the pointed-to type
|
||
|
return reflect.Zero(t.Elem()).Interface(), false
|
||
|
}
|
||
|
|
||
|
// Grab returns the value specified by the path given,
|
||
|
// starting from the struct s.
|
||
|
// If at any point in the path the lookup falls short
|
||
|
// (i.e. a field is not found), or if the last field in the path is nil
|
||
|
// itself, a type-appropriate zero-value is returned.
|
||
|
// This behavior can be overidden by providing a default value.
|
||
|
//
|
||
|
// This is useful for getting values our of deeply nested structures
|
||
|
// Example: val := sl.Grab(virtualGuest, "Datacenter.Name")
|
||
|
func Grab(s interface{}, path string, d ...interface{}) interface{} {
|
||
|
var (
|
||
|
val interface{}
|
||
|
ok bool
|
||
|
)
|
||
|
|
||
|
if val, ok = GrabOk(s, path); ok {
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
if len(d) > 0 {
|
||
|
return d[0]
|
||
|
}
|
||
|
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
// GrabOk returns the value specified by the path given,
|
||
|
// starting from the struct s.
|
||
|
// If at any point in the path the lookup falls short
|
||
|
// (i.e. a field is not found), or if the last field in the path is nil
|
||
|
// itself, a type-appropriate zero-value is returned.
|
||
|
// It returns a second value, a boolean, which will be false if it failed
|
||
|
// to lookup the value, including if the last field in the path was nil.
|
||
|
//
|
||
|
// This is useful for getting values our of deeply nested structures
|
||
|
// Example: val, ok := sl.GrabOk(virtualGuest, "Datacenter.Name")
|
||
|
func GrabOk(s interface{}, path string) (interface{}, bool) {
|
||
|
t := reflect.TypeOf(s)
|
||
|
if t.Kind() != reflect.Struct {
|
||
|
return nil, false
|
||
|
}
|
||
|
|
||
|
dotIndex := strings.Index(path, ".")
|
||
|
if dotIndex == -1 {
|
||
|
dotIndex = len(path)
|
||
|
}
|
||
|
|
||
|
fieldName := path[0:dotIndex]
|
||
|
val := reflect.ValueOf(s)
|
||
|
fieldVal := val.FieldByName(fieldName)
|
||
|
if fieldVal.Kind() == reflect.Ptr {
|
||
|
if fieldVal.IsNil() {
|
||
|
return reflect.Zero(fieldVal.Type().Elem()).Interface(), false
|
||
|
}
|
||
|
|
||
|
fieldVal = reflect.Indirect(fieldVal)
|
||
|
}
|
||
|
|
||
|
result, ok := GetOk(fieldVal.Interface())
|
||
|
if !ok {
|
||
|
return result, ok
|
||
|
}
|
||
|
|
||
|
if dotIndex == len(path) {
|
||
|
return result, ok
|
||
|
}
|
||
|
|
||
|
return GrabOk(result, path[dotIndex+1:len(path)])
|
||
|
}
|