"Fossies" - the Fresh Open Source Software Archive

Member "buildah-1.27.2/tests/tools/vendor/github.com/stretchr/objx/accessors.go" (20 Sep 2022, 4782 Bytes) of package /linux/misc/buildah-1.27.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "accessors.go": 1.26.4_vs_1.27.0.

    1 package objx
    2 
    3 import (
    4     "reflect"
    5     "regexp"
    6     "strconv"
    7     "strings"
    8 )
    9 
   10 const (
   11     // PathSeparator is the character used to separate the elements
   12     // of the keypath.
   13     //
   14     // For example, `location.address.city`
   15     PathSeparator string = "."
   16 
   17     // arrayAccesRegexString is the regex used to extract the array number
   18     // from the access path
   19     arrayAccesRegexString = `^(.+)\[([0-9]+)\]$`
   20 
   21     // mapAccessRegexString is the regex used to extract the map key
   22     // from the access path
   23     mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$`
   24 )
   25 
   26 // arrayAccesRegex is the compiled arrayAccesRegexString
   27 var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString)
   28 
   29 // mapAccessRegex is the compiled mapAccessRegexString
   30 var mapAccessRegex = regexp.MustCompile(mapAccessRegexString)
   31 
   32 // Get gets the value using the specified selector and
   33 // returns it inside a new Obj object.
   34 //
   35 // If it cannot find the value, Get will return a nil
   36 // value inside an instance of Obj.
   37 //
   38 // Get can only operate directly on map[string]interface{} and []interface.
   39 //
   40 // Example
   41 //
   42 // To access the title of the third chapter of the second book, do:
   43 //
   44 //    o.Get("books[1].chapters[2].title")
   45 func (m Map) Get(selector string) *Value {
   46     rawObj := access(m, selector, nil, false)
   47     return &Value{data: rawObj}
   48 }
   49 
   50 // Set sets the value using the specified selector and
   51 // returns the object on which Set was called.
   52 //
   53 // Set can only operate directly on map[string]interface{} and []interface
   54 //
   55 // Example
   56 //
   57 // To set the title of the third chapter of the second book, do:
   58 //
   59 //    o.Set("books[1].chapters[2].title","Time to Go")
   60 func (m Map) Set(selector string, value interface{}) Map {
   61     access(m, selector, value, true)
   62     return m
   63 }
   64 
   65 // getIndex returns the index, which is hold in s by two braches.
   66 // It also returns s withour the index part, e.g. name[1] will return (1, name).
   67 // If no index is found, -1 is returned
   68 func getIndex(s string) (int, string) {
   69     arrayMatches := arrayAccesRegex.FindStringSubmatch(s)
   70     if len(arrayMatches) > 0 {
   71         // Get the key into the map
   72         selector := arrayMatches[1]
   73         // Get the index into the array at the key
   74         // We know this cannt fail because arrayMatches[2] is an int for sure
   75         index, _ := strconv.Atoi(arrayMatches[2])
   76         return index, selector
   77     }
   78     return -1, s
   79 }
   80 
   81 // getKey returns the key which is held in s by two brackets.
   82 // It also returns the next selector.
   83 func getKey(s string) (string, string) {
   84     selSegs := strings.SplitN(s, PathSeparator, 2)
   85     thisSel := selSegs[0]
   86     nextSel := ""
   87 
   88     if len(selSegs) > 1 {
   89         nextSel = selSegs[1]
   90     }
   91 
   92     mapMatches := mapAccessRegex.FindStringSubmatch(s)
   93     if len(mapMatches) > 0 {
   94         if _, err := strconv.Atoi(mapMatches[2]); err != nil {
   95             thisSel = mapMatches[1]
   96             nextSel = "[" + mapMatches[2] + "]" + mapMatches[3]
   97 
   98             if thisSel == "" {
   99                 thisSel = mapMatches[2]
  100                 nextSel = mapMatches[3]
  101             }
  102 
  103             if nextSel == "" {
  104                 selSegs = []string{"", ""}
  105             } else if nextSel[0] == '.' {
  106                 nextSel = nextSel[1:]
  107             }
  108         }
  109     }
  110 
  111     return thisSel, nextSel
  112 }
  113 
  114 // access accesses the object using the selector and performs the
  115 // appropriate action.
  116 func access(current interface{}, selector string, value interface{}, isSet bool) interface{} {
  117     thisSel, nextSel := getKey(selector)
  118 
  119     indexes := []int{}
  120     for strings.Contains(thisSel, "[") {
  121         prevSel := thisSel
  122         index := -1
  123         index, thisSel = getIndex(thisSel)
  124         indexes = append(indexes, index)
  125         if prevSel == thisSel {
  126             break
  127         }
  128     }
  129 
  130     if curMap, ok := current.(Map); ok {
  131         current = map[string]interface{}(curMap)
  132     }
  133     // get the object in question
  134     switch current.(type) {
  135     case map[string]interface{}:
  136         curMSI := current.(map[string]interface{})
  137         if nextSel == "" && isSet {
  138             curMSI[thisSel] = value
  139             return nil
  140         }
  141 
  142         _, ok := curMSI[thisSel].(map[string]interface{})
  143         if !ok {
  144             _, ok = curMSI[thisSel].(Map)
  145         }
  146 
  147         if (curMSI[thisSel] == nil || !ok) && len(indexes) == 0 && isSet {
  148             curMSI[thisSel] = map[string]interface{}{}
  149         }
  150 
  151         current = curMSI[thisSel]
  152     default:
  153         current = nil
  154     }
  155 
  156     // do we need to access the item of an array?
  157     if len(indexes) > 0 {
  158         num := len(indexes)
  159         for num > 0 {
  160             num--
  161             index := indexes[num]
  162             indexes = indexes[:num]
  163             if array, ok := interSlice(current); ok {
  164                 if index < len(array) {
  165                     current = array[index]
  166                 } else {
  167                     current = nil
  168                     break
  169                 }
  170             }
  171         }
  172     }
  173 
  174     if nextSel != "" {
  175         current = access(current, nextSel, value, isSet)
  176     }
  177     return current
  178 }
  179 
  180 func interSlice(slice interface{}) ([]interface{}, bool) {
  181     if array, ok := slice.([]interface{}); ok {
  182         return array, ok
  183     }
  184 
  185     s := reflect.ValueOf(slice)
  186     if s.Kind() != reflect.Slice {
  187         return nil, false
  188     }
  189 
  190     ret := make([]interface{}, s.Len())
  191 
  192     for i := 0; i < s.Len(); i++ {
  193         ret[i] = s.Index(i).Interface()
  194     }
  195 
  196     return ret, true
  197 }