10 // arrayAccesRegexString is the regex used to extract the array number
11 // from the access path
12 const arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
14 // arrayAccesRegex is the compiled arrayAccesRegexString
15 var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
17 // Get gets the value using the specified selector and
18 // returns it inside a new Obj object.
20 // If it cannot find the value, Get will return a nil
21 // value inside an instance of Obj.
23 // Get can only operate directly on map[string]interface{} and []interface.
27 // To access the title of the third chapter of the second book, do:
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}
35 // Set sets the value using the specified selector and
36 // returns the object on which Set was called.
38 // Set can only operate directly on map[string]interface{} and []interface
42 // To set the title of the third chapter of the second book, do:
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)
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{} {
54 switch selector.(type) {
55 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
57 if array, ok := current.([]interface{}); ok {
58 index := intFromInterface(selector)
60 if index >= len(array) {
62 panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
74 selStr := selector.(string)
75 selSegs := strings.SplitN(selStr, PathSeparator, 2)
80 // https://github.com/stretchr/objx/issues/12
81 if strings.Contains(thisSel, "[") {
83 arrayMatches := arrayAccesRegex.FindStringSubmatch(thisSel)
85 if len(arrayMatches) > 0 {
87 // Get the key into the map
88 thisSel = arrayMatches[1]
90 // Get the index into the array at the key
91 index, err = strconv.Atoi(arrayMatches[2])
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].")
102 if curMap, ok := current.(Map); ok {
103 current = map[string]interface{}(curMap)
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
114 current = curMSI[thisSel]
120 if current == nil && panics {
121 panic(fmt.Sprintf("objx: '%v' invalid on object.", selector))
124 // do we need to access the item of an array?
126 if array, ok := current.([]interface{}); ok {
127 if index < len(array) {
128 current = array[index]
131 panic(fmt.Sprintf("objx: Index %d is out of range. Slice only contains %d items.", index, len(array)))
138 if len(selSegs) > 1 {
139 current = access(current, selSegs[1], value, isSet, panics)
148 // intFromInterface converts an interface object to the largest
149 // representation of an unsigned integer using a type switch and
151 func intFromInterface(selector interface{}) int {
153 switch selector.(type) {
155 value = selector.(int)
157 value = int(selector.(int8))
159 value = int(selector.(int16))
161 value = int(selector.(int32))
163 value = int(selector.(int64))
165 value = int(selector.(uint))
167 value = int(selector.(uint8))
169 value = int(selector.(uint16))
171 value = int(selector.(uint32))
173 value = int(selector.(uint64))
175 panic("objx: array access argument is not an integer type (this should never happen)")