OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / stretchr / testify / vendor / github.com / stretchr / objx / accessors.go
1 package objx
2
3 import (
4         "fmt"
5         "regexp"
6         "strconv"
7         "strings"
8 )
9
10 // arrayAccesRegexString is the regex used to extract the array number
11 // from the access path
12 const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
13
14 // arrayAccesRegex is the compiled arrayAccesRegexString
15 var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
16
17 // Get gets the value using the specified selector and
18 // returns it inside a new Obj object.
19 //
20 // If it cannot find the value, Get will return a nil
21 // value inside an instance of Obj.
22 //
23 // Get can only operate directly on map[string]interface{} and []interface.
24 //
25 // Example
26 //
27 // To access the title of the third chapter of the second book, do:
28 //
29 //    o.Get("books[1].chapters[2].title")
30 func (m Map) Get(selector string) *Value {
31         rawObj := access(m, selector, nil, false, false)
32         return &Value{data: rawObj}
33 }
34
35 // Set sets the value using the specified selector and
36 // returns the object on which Set was called.
37 //
38 // Set can only operate directly on map[string]interface{} and []interface
39 //
40 // Example
41 //
42 // To set the title of the third chapter of the second book, do:
43 //
44 //    o.Set("books[1].chapters[2].title","Time to Go")
45 func (m Map) Set(selector string, value interface{}) Map {
46         access(m, selector, value, true, false)
47         return m
48 }
49
50 // access accesses the object using the selector and performs the
51 // appropriate action.
52 func access(current, selector, value interface{}, isSet, panics bool) interface{} {
53
54         switch selector.(type) {
55         case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
56
57                 if array, ok := current.([]interface{}); ok {
58                         index := intFromInterface(selector)
59
60                         if index >= len(array) {
61                                 if panics {
62                                         panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
63                                 }
64                                 return nil
65                         }
66
67                         return array[index]
68                 }
69
70                 return nil
71
72         case string:
73
74                 selStr := selector.(string)
75                 selSegs := strings.SplitN(selStr, PathSeparator, 2)
76                 thisSel := selSegs[0]
77                 index := -1
78                 var err error
79
80                 // https://github.com/stretchr/objx/issues/12
81                 if strings.Contains(thisSel, "[") {
82
83                         arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
84
85                         if len(arrayMatches) > 0 {
86
87                                 // Get the key into the map
88                                 thisSel = arrayMatches[1]
89
90                                 // Get the index into the array at the key
91                                 index, err = strconv.Atoi(arrayMatches[2])
92
93                                 if err != nil {
94                                         // This should never happen. If it does, something has gone
95                                         // seriously wrong. Panic.
96                                         panic("objx: Array index is not an integer.  Must use array[int].")
97                                 }
98
99                         }
100                 }
101
102                 if curMap, ok := current.(Map); ok {
103                         current = map[string]interface{}(curMap)
104                 }
105
106                 // get the object in question
107                 switch current.(type) {
108                 case map[string]interface{}:
109                         curMSI := current.(map[string]interface{})
110                         if len(selSegs) <= 1 && isSet {
111                                 curMSI[thisSel] = value
112                                 return nil
113                         } else {
114                                 current = curMSI[thisSel]
115                         }
116                 default:
117                         current = nil
118                 }
119
120                 if current == nil && panics {
121                         panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
122                 }
123
124                 // do we need to access the item of an array?
125                 if index > -1 {
126                         if array, ok := current.([]interface{}); ok {
127                                 if index < len(array) {
128                                         current = array[index]
129                                 } else {
130                                         if panics {
131                                                 panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
132                                         }
133                                         current = nil
134                                 }
135                         }
136                 }
137
138                 if len(selSegs) > 1 {
139                         current = access(current, selSegs[1], value, isSet, panics)
140                 }
141
142         }
143
144         return current
145
146 }
147
148 // intFromInterface converts an interface object to the largest
149 // representation of an unsigned integer using a type switch and
150 // assertions
151 func intFromInterface(selector interface{}) int {
152         var value int
153         switch selector.(type) {
154         case int:
155                 value = selector.(int)
156         case int8:
157                 value = int(selector.(int8))
158         case int16:
159                 value = int(selector.(int16))
160         case int32:
161                 value = int(selector.(int32))
162         case int64:
163                 value = int(selector.(int64))
164         case uint:
165                 value = int(selector.(uint))
166         case uint8:
167                 value = int(selector.(uint8))
168         case uint16:
169                 value = int(selector.(uint16))
170         case uint32:
171                 value = int(selector.(uint32))
172         case uint64:
173                 value = int(selector.(uint64))
174         default:
175                 panic("objx: array access argument is not an integer type (this should never happen)")
176         }
177
178         return value
179 }