1 /**
2 * Copyright 2016 IBM Corp.
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 sl has convenience functions for returning pointers to values
18 package sl
19 20 import (
21 "reflect"
22 "strings"
23 "time"
24 25 "github.com/softlayer/softlayer-go/datatypes"
26 )
27 28 // Int returns a pointer to the int value provided
29 func Int(v int) *int {
30 return &v
31 }
32 33 // Uint returns a pointer to the uint value provided
34 func Uint(v uint) *uint {
35 return &v
36 }
37 38 // String returns a pointer to the string value provided
39 func String(v string) *string {
40 return &v
41 }
42 43 // Bool returns a pointer to the bool value provided
44 func Bool(v bool) *bool {
45 return &v
46 }
47 48 // Time converts the time.Time value provided to a datatypes.Time value,
49 // and returns a pointer to it
50 func Time(v time.Time) *datatypes.Time {
51 r := datatypes.Time{Time: v}
52 return &r
53 }
54 55 // Float converts the float value provided to a datatypes.Float64 value,
56 // and returns a pointer to it
57 func Float(v float64) *datatypes.Float64 {
58 r := datatypes.Float64(v)
59 return &r
60 }
61 62 // Convenience functions to simplify dereference of datatype properties
63 64 // Get returns the value of p, either p itself, or, if p is a pointer, the
65 // value that p points to. d is an optional default value to be returned
66 // in the event that p is nil. If d is not specified, and p is nil, a
67 // type-appropriate zero-value is returned instead.
68 func Get(p interface{}, d ...interface{}) interface{} {
69 var (
70 val interface{}
71 ok bool
72 )
73 74 if val, ok = GetOk(p); ok {
75 return val
76 }
77 78 if len(d) > 0 {
79 return d[0]
80 }
81 82 return val
83 }
84 85 // GetOk returns the value of p, either p itself, or, if p is a pointer, the
86 // value that p points to. If p is nil, a type-appropriate zero-value is
87 // returned instead. If p is a value or non-nil pointer, the second return
88 // value will be true. Otherwise, it will be false.
89 func GetOk(p interface{}) (interface{}, bool) {
90 t := reflect.TypeOf(p)
91 92 // if p is a non-pointer, just return it
93 if t.Kind() != reflect.Ptr {
94 return p, true
95 }
96 97 // p is a pointer. If non-nil, return the value pointed to
98 v := reflect.Indirect(reflect.ValueOf(p))
99 if v.IsValid() {
100 return v.Interface(), true
101 }
102 103 // p is a nil pointer. Return the zero value for the pointed-to type
104 return reflect.Zero(t.Elem()).Interface(), false
105 }
106 107 // Grab returns the value specified by the path given,
108 // starting from the struct s.
109 // If at any point in the path the lookup falls short
110 // (i.e. a field is not found), or if the last field in the path is nil
111 // itself, a type-appropriate zero-value is returned.
112 // This behavior can be overidden by providing a default value.
113 //
114 // This is useful for getting values our of deeply nested structures
115 // Example: val := sl.Grab(virtualGuest, "Datacenter.Name")
116 func Grab(s interface{}, path string, d ...interface{}) interface{} {
117 var (
118 val interface{}
119 ok bool
120 )
121 122 if val, ok = GrabOk(s, path); ok {
123 return val
124 }
125 126 if len(d) > 0 {
127 return d[0]
128 }
129 130 return val
131 }
132 133 // GrabOk returns the value specified by the path given,
134 // starting from the struct s.
135 // If at any point in the path the lookup falls short
136 // (i.e. a field is not found), or if the last field in the path is nil
137 // itself, a type-appropriate zero-value is returned.
138 // It returns a second value, a boolean, which will be false if it failed
139 // to lookup the value, including if the last field in the path was nil.
140 //
141 // This is useful for getting values our of deeply nested structures
142 // Example: val, ok := sl.GrabOk(virtualGuest, "Datacenter.Name")
143 func GrabOk(s interface{}, path string) (interface{}, bool) {
144 t := reflect.TypeOf(s)
145 if t.Kind() != reflect.Struct {
146 return nil, false
147 }
148 149 dotIndex := strings.Index(path, ".")
150 if dotIndex == -1 {
151 dotIndex = len(path)
152 }
153 154 fieldName := path[0:dotIndex]
155 val := reflect.ValueOf(s)
156 fieldVal := val.FieldByName(fieldName)
157 if fieldVal.Kind() == reflect.Ptr {
158 if fieldVal.IsNil() {
159 return reflect.Zero(fieldVal.Type().Elem()).Interface(), false
160 }
161 162 fieldVal = reflect.Indirect(fieldVal)
163 }
164 165 result, ok := GetOk(fieldVal.Interface())
166 if !ok {
167 return result, ok
168 }
169 170 if dotIndex == len(path) {
171 return result, ok
172 }
173 174 return GrabOk(result, path[dotIndex+1:len(path)])
175 }
176