open-consul/vendor/github.com/softlayer/softlayer-go/sl/helpers.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)])
}