21
vendor/github.com/mitchellh/pointerstructure/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mitchellh/pointerstructure/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Mitchell Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
102
vendor/github.com/mitchellh/pointerstructure/README.md
generated
vendored
Normal file
102
vendor/github.com/mitchellh/pointerstructure/README.md
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
# pointerstructure [](https://godoc.org/github.com/mitchellh/pointerstructure)
|
||||
|
||||
pointerstructure is a Go library for identifying a specific value within
|
||||
any Go structure using a string syntax.
|
||||
|
||||
pointerstructure is based on
|
||||
[JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901), but
|
||||
reimplemented for Go.
|
||||
|
||||
The goal of pointerstructure is to provide a single, well-known format
|
||||
for addressing a specific value. This can be useful for user provided
|
||||
input on structures, diffs of structures, etc.
|
||||
|
||||
## Features
|
||||
|
||||
* Get the value for an address
|
||||
|
||||
* Set the value for an address within an existing structure
|
||||
|
||||
* Delete the value at an address
|
||||
|
||||
* Sorting a list of addresses
|
||||
|
||||
## Installation
|
||||
|
||||
Standard `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/mitchellh/pointerstructure
|
||||
```
|
||||
|
||||
## Usage & Example
|
||||
|
||||
For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/pointerstructure).
|
||||
|
||||
A quick code example is shown below:
|
||||
|
||||
```go
|
||||
complex := map[string]interface{}{
|
||||
"alice": 42,
|
||||
"bob": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "Bob",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
value, err := pointerstructure.Get(complex, "/bob/0/name")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s", value)
|
||||
// Output:
|
||||
// Bob
|
||||
```
|
||||
|
||||
Continuing the example above, you can also set values:
|
||||
|
||||
```go
|
||||
value, err = pointerstructure.Set(complex, "/bob/0/name", "Alice")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
value, err = pointerstructure.Get(complex, "/bob/0/name")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s", value)
|
||||
// Output:
|
||||
// Alice
|
||||
```
|
||||
|
||||
The library also supports `Get` operations on structs including using the `pointer`
|
||||
struct tag to override struct field names:
|
||||
|
||||
```go
|
||||
input := struct {
|
||||
Values map[string]interface{} `pointer:"embedded"`
|
||||
}{
|
||||
Values: map[string]interface{}{
|
||||
"alice": 42,
|
||||
"bob": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "Bob",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
value, err := Get(input, "/embedded/bob/0/name")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s", value)
|
||||
// Output:
|
||||
// Bob
|
||||
```
|
||||
|
||||
112
vendor/github.com/mitchellh/pointerstructure/delete.go
generated
vendored
Normal file
112
vendor/github.com/mitchellh/pointerstructure/delete.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Delete deletes the value specified by the pointer p in structure s.
|
||||
//
|
||||
// When deleting a slice index, all other elements will be shifted to
|
||||
// the left. This is specified in RFC6902 (JSON Patch) and not RFC6901 since
|
||||
// RFC6901 doesn't specify operations on pointers. If you don't want to
|
||||
// shift elements, you should use Set to set the slice index to the zero value.
|
||||
//
|
||||
// The structures s must have non-zero values set up to this pointer.
|
||||
// For example, if deleting "/bob/0/name", then "/bob/0" must be set already.
|
||||
//
|
||||
// The returned value is potentially a new value if this pointer represents
|
||||
// the root document. Otherwise, the returned value will always be s.
|
||||
func (p *Pointer) Delete(s interface{}) (interface{}, error) {
|
||||
// if we represent the root doc, we've deleted everything
|
||||
if len(p.Parts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Save the original since this is going to be our return value
|
||||
originalS := s
|
||||
|
||||
// Get the parent value
|
||||
var err error
|
||||
s, err = p.Parent().Get(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Map for lookup of getter to call for type
|
||||
funcMap := map[reflect.Kind]deleteFunc{
|
||||
reflect.Array: p.deleteSlice,
|
||||
reflect.Map: p.deleteMap,
|
||||
reflect.Slice: p.deleteSlice,
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(s)
|
||||
for val.Kind() == reflect.Interface {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for val.Kind() == reflect.Ptr {
|
||||
val = reflect.Indirect(val)
|
||||
}
|
||||
|
||||
f, ok := funcMap[val.Kind()]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("delete %s: %w: %s", p, ErrInvalidKind, val.Kind())
|
||||
}
|
||||
|
||||
result, err := f(originalS, val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("delete %s: %s", p, err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type deleteFunc func(interface{}, reflect.Value) (interface{}, error)
|
||||
|
||||
func (p *Pointer) deleteMap(root interface{}, m reflect.Value) (interface{}, error) {
|
||||
part := p.Parts[len(p.Parts)-1]
|
||||
key, err := coerce(reflect.ValueOf(part), m.Type().Key())
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// Delete the key
|
||||
var elem reflect.Value
|
||||
m.SetMapIndex(key, elem)
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (p *Pointer) deleteSlice(root interface{}, s reflect.Value) (interface{}, error) {
|
||||
// Coerce the key to an int
|
||||
part := p.Parts[len(p.Parts)-1]
|
||||
idxVal, err := coerce(reflect.ValueOf(part), reflect.TypeOf(42))
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
idx := int(idxVal.Int())
|
||||
|
||||
// Verify we're within bounds
|
||||
if idx < 0 || idx >= s.Len() {
|
||||
return root, fmt.Errorf(
|
||||
"index %d is %w (length = %d)", idx, ErrOutOfRange, s.Len())
|
||||
}
|
||||
|
||||
// Mimicing the following with reflection to do this:
|
||||
//
|
||||
// copy(a[i:], a[i+1:])
|
||||
// a[len(a)-1] = nil // or the zero value of T
|
||||
// a = a[:len(a)-1]
|
||||
|
||||
// copy(a[i:], a[i+1:])
|
||||
reflect.Copy(s.Slice(idx, s.Len()), s.Slice(idx+1, s.Len()))
|
||||
|
||||
// a[len(a)-1] = nil // or the zero value of T
|
||||
s.Index(s.Len() - 1).Set(reflect.Zero(s.Type().Elem()))
|
||||
|
||||
// a = a[:len(a)-1]
|
||||
s = s.Slice(0, s.Len()-1)
|
||||
|
||||
// set the slice back on the parent
|
||||
return p.Parent().Set(root, s.Interface())
|
||||
}
|
||||
22
vendor/github.com/mitchellh/pointerstructure/errors.go
generated
vendored
Normal file
22
vendor/github.com/mitchellh/pointerstructure/errors.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package pointerstructure
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrNotFound is returned if a key in a query can't be found
|
||||
ErrNotFound = errors.New("couldn't find key")
|
||||
|
||||
// ErrParse is returned if the query cannot be parsed
|
||||
ErrParse = errors.New("first char must be '/'")
|
||||
|
||||
// ErrOutOfRange is returned if a query is referencing a slice
|
||||
// or array and the requested index is not in the range [0,len(item))
|
||||
ErrOutOfRange = errors.New("out of range")
|
||||
|
||||
// ErrInvalidKind is returned if the item is not a map, slice,
|
||||
// array, or struct
|
||||
ErrInvalidKind = errors.New("invalid value kind")
|
||||
|
||||
// ErrConvert is returned if an item is not of a requested type
|
||||
ErrConvert = errors.New("couldn't convert value")
|
||||
)
|
||||
165
vendor/github.com/mitchellh/pointerstructure/get.go
generated
vendored
Normal file
165
vendor/github.com/mitchellh/pointerstructure/get.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Get reads the value out of the total value v.
|
||||
//
|
||||
// For struct values a `pointer:"<name>"` tag on the struct's
|
||||
// fields may be used to override that field's name for lookup purposes.
|
||||
// Alternatively the tag name used can be overridden in the `Config`.
|
||||
func (p *Pointer) Get(v interface{}) (interface{}, error) {
|
||||
// fast-path the empty address case to avoid reflect.ValueOf below
|
||||
if len(p.Parts) == 0 {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Map for lookup of getter to call for type
|
||||
funcMap := map[reflect.Kind]func(string, reflect.Value) (reflect.Value, error){
|
||||
reflect.Array: p.getSlice,
|
||||
reflect.Map: p.getMap,
|
||||
reflect.Slice: p.getSlice,
|
||||
reflect.Struct: p.getStruct,
|
||||
}
|
||||
|
||||
currentVal := reflect.ValueOf(v)
|
||||
for i, part := range p.Parts {
|
||||
for currentVal.Kind() == reflect.Interface {
|
||||
currentVal = currentVal.Elem()
|
||||
}
|
||||
|
||||
for currentVal.Kind() == reflect.Ptr {
|
||||
currentVal = reflect.Indirect(currentVal)
|
||||
}
|
||||
|
||||
f, ok := funcMap[currentVal.Kind()]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(
|
||||
"%s: at part %d, %w: %s", p, i, ErrInvalidKind, currentVal.Kind())
|
||||
}
|
||||
|
||||
var err error
|
||||
currentVal, err = f(part, currentVal)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s at part %d: %w", p, i, err)
|
||||
}
|
||||
if p.Config.ValueTransformationHook != nil {
|
||||
currentVal = p.Config.ValueTransformationHook(currentVal)
|
||||
if currentVal == reflect.ValueOf(nil) {
|
||||
return nil, fmt.Errorf("%s at part %d: ValueTransformationHook returned the value of a nil interface", p, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentVal.Interface(), nil
|
||||
}
|
||||
|
||||
func (p *Pointer) getMap(part string, m reflect.Value) (reflect.Value, error) {
|
||||
var zeroValue reflect.Value
|
||||
|
||||
// Coerce the string part to the correct key type
|
||||
key, err := coerce(reflect.ValueOf(part), m.Type().Key())
|
||||
if err != nil {
|
||||
return zeroValue, err
|
||||
}
|
||||
|
||||
// Verify that the key exists
|
||||
found := false
|
||||
for _, k := range m.MapKeys() {
|
||||
if k.Interface() == key.Interface() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return zeroValue, fmt.Errorf("%w %#v", ErrNotFound, key.Interface())
|
||||
}
|
||||
|
||||
// Get the key
|
||||
return m.MapIndex(key), nil
|
||||
}
|
||||
|
||||
func (p *Pointer) getSlice(part string, v reflect.Value) (reflect.Value, error) {
|
||||
var zeroValue reflect.Value
|
||||
|
||||
// Coerce the key to an int
|
||||
idxVal, err := coerce(reflect.ValueOf(part), reflect.TypeOf(42))
|
||||
if err != nil {
|
||||
return zeroValue, err
|
||||
}
|
||||
idx := int(idxVal.Int())
|
||||
|
||||
// Verify we're within bounds
|
||||
if idx < 0 || idx >= v.Len() {
|
||||
return zeroValue, fmt.Errorf(
|
||||
"index %d is %w (length = %d)", idx, ErrOutOfRange, v.Len())
|
||||
}
|
||||
|
||||
// Get the key
|
||||
return v.Index(idx), nil
|
||||
}
|
||||
|
||||
func (p *Pointer) getStruct(part string, m reflect.Value) (reflect.Value, error) {
|
||||
var foundField reflect.Value
|
||||
var found bool
|
||||
var ignored bool
|
||||
typ := m.Type()
|
||||
|
||||
tagName := p.Config.TagName
|
||||
if tagName == "" {
|
||||
tagName = "pointer"
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
if field.PkgPath != "" {
|
||||
// this is an unexported field so ignore it
|
||||
continue
|
||||
}
|
||||
|
||||
fieldTag := field.Tag.Get(tagName)
|
||||
|
||||
if fieldTag != "" {
|
||||
if idx := strings.Index(fieldTag, ","); idx != -1 {
|
||||
fieldTag = fieldTag[0:idx]
|
||||
}
|
||||
|
||||
if strings.Contains(fieldTag, "|") {
|
||||
// should this panic instead?
|
||||
return foundField, fmt.Errorf("pointer struct tag cannot contain the '|' character")
|
||||
}
|
||||
|
||||
if fieldTag == "-" {
|
||||
// we should ignore this field but cannot immediately return because its possible another
|
||||
// field has a tag that would allow it to assume this ones name.
|
||||
|
||||
if field.Name == part {
|
||||
found = true
|
||||
ignored = true
|
||||
}
|
||||
continue
|
||||
} else if fieldTag == part {
|
||||
// we can go ahead and return now as the tag is enough to
|
||||
// indicate that this is the correct field
|
||||
return m.Field(i), nil
|
||||
}
|
||||
} else if field.Name == part {
|
||||
foundField = m.Field(i)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return reflect.Value{}, fmt.Errorf("couldn't find struct field with name %q", part)
|
||||
}
|
||||
|
||||
if ignored {
|
||||
return reflect.Value{}, fmt.Errorf("struct field %q is ignored and cannot be used", part)
|
||||
}
|
||||
|
||||
return foundField, nil
|
||||
}
|
||||
57
vendor/github.com/mitchellh/pointerstructure/parse.go
generated
vendored
Normal file
57
vendor/github.com/mitchellh/pointerstructure/parse.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parse parses a pointer from the input string. The input string
|
||||
// is expected to follow the format specified by RFC 6901: '/'-separated
|
||||
// parts. Each part can contain escape codes to contain '/' or '~'.
|
||||
func Parse(input string) (*Pointer, error) {
|
||||
// Special case the empty case
|
||||
if input == "" {
|
||||
return &Pointer{}, nil
|
||||
}
|
||||
|
||||
// We expect the first character to be "/"
|
||||
if input[0] != '/' {
|
||||
return nil, fmt.Errorf(
|
||||
"parse Go pointer %q: %w", input, ErrParse)
|
||||
}
|
||||
|
||||
// Trim out the first slash so we don't have to +1 every index
|
||||
input = input[1:]
|
||||
|
||||
// Parse out all the parts
|
||||
var parts []string
|
||||
lastSlash := -1
|
||||
for i, r := range input {
|
||||
if r == '/' {
|
||||
parts = append(parts, input[lastSlash+1:i])
|
||||
lastSlash = i
|
||||
}
|
||||
}
|
||||
|
||||
// Add last part
|
||||
parts = append(parts, input[lastSlash+1:])
|
||||
|
||||
// Process each part for string replacement
|
||||
for i, p := range parts {
|
||||
// Replace ~1 followed by ~0 as specified by the RFC
|
||||
parts[i] = strings.Replace(
|
||||
strings.Replace(p, "~1", "/", -1), "~0", "~", -1)
|
||||
}
|
||||
|
||||
return &Pointer{Parts: parts}, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the input cannot be parsed.
|
||||
func MustParse(input string) *Pointer {
|
||||
p, err := Parse(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
145
vendor/github.com/mitchellh/pointerstructure/pointer.go
generated
vendored
Normal file
145
vendor/github.com/mitchellh/pointerstructure/pointer.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Package pointerstructure provides functions for identifying a specific
|
||||
// value within any Go structure using a string syntax.
|
||||
//
|
||||
// The syntax used is based on JSON Pointer (RFC 6901).
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// ValueTransformationHookFn transforms a Go data structure into another.
|
||||
// This is useful for situations where you want the JSON Pointer to not be an
|
||||
// exact match to the structure of the Go struct or map, for example when
|
||||
// working with protocol buffers' well-known types.
|
||||
type ValueTransformationHookFn func(reflect.Value) reflect.Value
|
||||
|
||||
type Config struct {
|
||||
// The tag name that pointerstructure reads for field names. This
|
||||
// defaults to "pointer"
|
||||
TagName string
|
||||
// ValueTransformationHook is called on each reference token within the
|
||||
// provided JSON Pointer when Get is used. The returned value from this
|
||||
// hook is then used for matching for all following parts of the JSON
|
||||
// Pointer. If this returns a nil interface Get will return an error.
|
||||
ValueTransformationHook ValueTransformationHookFn
|
||||
}
|
||||
|
||||
// Pointer represents a pointer to a specific value. You can construct
|
||||
// a pointer manually or use Parse.
|
||||
type Pointer struct {
|
||||
// Parts are the pointer parts. No escape codes are processed here.
|
||||
// The values are expected to be exact. If you have escape codes, use
|
||||
// the Parse functions.
|
||||
Parts []string
|
||||
|
||||
// Config is the configuration controlling how items are looked up
|
||||
// in structures.
|
||||
Config Config
|
||||
}
|
||||
|
||||
// Get reads the value at the given pointer.
|
||||
//
|
||||
// This is a shorthand for calling Parse on the pointer and then calling Get
|
||||
// on that result. An error will be returned if the value cannot be found or
|
||||
// there is an error with the format of pointer.
|
||||
func Get(value interface{}, pointer string) (interface{}, error) {
|
||||
p, err := Parse(pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.Get(value)
|
||||
}
|
||||
|
||||
// Set sets the value at the given pointer.
|
||||
//
|
||||
// This is a shorthand for calling Parse on the pointer and then calling Set
|
||||
// on that result. An error will be returned if the value cannot be found or
|
||||
// there is an error with the format of pointer.
|
||||
//
|
||||
// Set returns the complete document, which might change if the pointer value
|
||||
// points to the root ("").
|
||||
func Set(doc interface{}, pointer string, value interface{}) (interface{}, error) {
|
||||
p, err := Parse(pointer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.Set(doc, value)
|
||||
}
|
||||
|
||||
// String returns the string value that can be sent back to Parse to get
|
||||
// the same Pointer result.
|
||||
func (p *Pointer) String() string {
|
||||
if len(p.Parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Copy the parts so we can convert back the escapes
|
||||
result := make([]string, len(p.Parts))
|
||||
copy(result, p.Parts)
|
||||
for i, p := range p.Parts {
|
||||
result[i] = strings.Replace(
|
||||
strings.Replace(p, "~", "~0", -1), "/", "~1", -1)
|
||||
|
||||
}
|
||||
|
||||
return "/" + strings.Join(result, "/")
|
||||
}
|
||||
|
||||
// Parent returns a pointer to the parent element of this pointer.
|
||||
//
|
||||
// If Pointer represents the root (empty parts), a pointer representing
|
||||
// the root is returned. Therefore, to check for the root, IsRoot() should be
|
||||
// called.
|
||||
func (p *Pointer) Parent() *Pointer {
|
||||
// If this is root, then we just return a new root pointer. We allocate
|
||||
// a new one though so this can still be modified.
|
||||
if p.IsRoot() {
|
||||
return &Pointer{}
|
||||
}
|
||||
|
||||
parts := make([]string, len(p.Parts)-1)
|
||||
copy(parts, p.Parts[:len(p.Parts)-1])
|
||||
return &Pointer{
|
||||
Parts: parts,
|
||||
Config: p.Config,
|
||||
}
|
||||
}
|
||||
|
||||
// IsRoot returns true if this pointer represents the root document.
|
||||
func (p *Pointer) IsRoot() bool {
|
||||
return len(p.Parts) == 0
|
||||
}
|
||||
|
||||
// coerce is a helper to coerce a value to a specific type if it must
|
||||
// and if its possible. If it isn't possible, an error is returned.
|
||||
func coerce(value reflect.Value, to reflect.Type) (reflect.Value, error) {
|
||||
// If the value is already assignable to the type, then let it go
|
||||
if value.Type().AssignableTo(to) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// If a direct conversion is possible, do that
|
||||
if value.Type().ConvertibleTo(to) {
|
||||
return value.Convert(to), nil
|
||||
}
|
||||
|
||||
// Create a new value to hold our result
|
||||
result := reflect.New(to)
|
||||
|
||||
// Decode
|
||||
if err := mapstructure.WeakDecode(value.Interface(), result.Interface()); err != nil {
|
||||
return result, fmt.Errorf(
|
||||
"%w %#v to type %s", ErrConvert,
|
||||
value.Interface(), to.String())
|
||||
}
|
||||
|
||||
// We need to indirect the value since reflect.New always creates a pointer
|
||||
return reflect.Indirect(result), nil
|
||||
}
|
||||
122
vendor/github.com/mitchellh/pointerstructure/set.go
generated
vendored
Normal file
122
vendor/github.com/mitchellh/pointerstructure/set.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Set writes a value v to the pointer p in structure s.
|
||||
//
|
||||
// The structures s must have non-zero values set up to this pointer.
|
||||
// For example, if setting "/bob/0/name", then "/bob/0" must be set already.
|
||||
//
|
||||
// The returned value is potentially a new value if this pointer represents
|
||||
// the root document. Otherwise, the returned value will always be s.
|
||||
func (p *Pointer) Set(s, v interface{}) (interface{}, error) {
|
||||
// if we represent the root doc, return that
|
||||
if len(p.Parts) == 0 {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Save the original since this is going to be our return value
|
||||
originalS := s
|
||||
|
||||
// Get the parent value
|
||||
var err error
|
||||
s, err = p.Parent().Get(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Map for lookup of getter to call for type
|
||||
funcMap := map[reflect.Kind]setFunc{
|
||||
reflect.Array: p.setSlice,
|
||||
reflect.Map: p.setMap,
|
||||
reflect.Slice: p.setSlice,
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(s)
|
||||
for val.Kind() == reflect.Interface {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for val.Kind() == reflect.Ptr {
|
||||
val = reflect.Indirect(val)
|
||||
}
|
||||
|
||||
f, ok := funcMap[val.Kind()]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("set %s: %w: %s", p, ErrInvalidKind, val.Kind())
|
||||
}
|
||||
|
||||
result, err := f(originalS, val, reflect.ValueOf(v))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("set %s: %w", p, err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type setFunc func(interface{}, reflect.Value, reflect.Value) (interface{}, error)
|
||||
|
||||
func (p *Pointer) setMap(root interface{}, m, value reflect.Value) (interface{}, error) {
|
||||
part := p.Parts[len(p.Parts)-1]
|
||||
key, err := coerce(reflect.ValueOf(part), m.Type().Key())
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
|
||||
elem, err := coerce(value, m.Type().Elem())
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// Set the key
|
||||
m.SetMapIndex(key, elem)
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (p *Pointer) setSlice(root interface{}, s, value reflect.Value) (interface{}, error) {
|
||||
// Coerce the value, we'll need that no matter what
|
||||
value, err := coerce(value, s.Type().Elem())
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// If the part is the special "-", that means to append it (RFC6901 4.)
|
||||
part := p.Parts[len(p.Parts)-1]
|
||||
if part == "-" {
|
||||
return p.setSliceAppend(root, s, value)
|
||||
}
|
||||
|
||||
// Coerce the key to an int
|
||||
idxVal, err := coerce(reflect.ValueOf(part), reflect.TypeOf(42))
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
idx := int(idxVal.Int())
|
||||
|
||||
// Verify we're within bounds
|
||||
if idx < 0 || idx >= s.Len() {
|
||||
return root, fmt.Errorf(
|
||||
"index %d is %w (length = %d)", idx, ErrOutOfRange, s.Len())
|
||||
}
|
||||
|
||||
// Set the key
|
||||
s.Index(idx).Set(value)
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (p *Pointer) setSliceAppend(root interface{}, s, value reflect.Value) (interface{}, error) {
|
||||
// Coerce the value, we'll need that no matter what. This should
|
||||
// be a no-op since we expect it to be done already, but there is
|
||||
// a fast-path check for that in coerce so do it anyways.
|
||||
value, err := coerce(value, s.Type().Elem())
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
|
||||
// We can assume "s" is the parent of pointer value. We need to actually
|
||||
// write s back because Append can return a new slice.
|
||||
return p.Parent().Set(root, reflect.Append(s, value).Interface())
|
||||
}
|
||||
42
vendor/github.com/mitchellh/pointerstructure/sort.go
generated
vendored
Normal file
42
vendor/github.com/mitchellh/pointerstructure/sort.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package pointerstructure
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Sort does an in-place sort of the pointers so that they are in order
|
||||
// of least specific to most specific alphabetized. For example:
|
||||
// "/foo", "/foo/0", "/qux"
|
||||
//
|
||||
// This ordering is ideal for applying the changes in a way that ensures
|
||||
// that parents are set first.
|
||||
func Sort(p []*Pointer) { sort.Sort(PointerSlice(p)) }
|
||||
|
||||
// PointerSlice is a slice of pointers that adheres to sort.Interface
|
||||
type PointerSlice []*Pointer
|
||||
|
||||
func (p PointerSlice) Len() int { return len(p) }
|
||||
func (p PointerSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
func (p PointerSlice) Less(i, j int) bool {
|
||||
// Equal number of parts, do a string compare per part
|
||||
for idx, ival := range p[i].Parts {
|
||||
// If we're passed the length of p[j] parts, then we're done
|
||||
if idx >= len(p[j].Parts) {
|
||||
break
|
||||
}
|
||||
|
||||
// Compare the values if they're not equal
|
||||
jval := p[j].Parts[idx]
|
||||
if ival != jval {
|
||||
return ival < jval
|
||||
}
|
||||
}
|
||||
|
||||
// Equal prefix, take the shorter
|
||||
if len(p[i].Parts) != len(p[j].Parts) {
|
||||
return len(p[i].Parts) < len(p[j].Parts)
|
||||
}
|
||||
|
||||
// Equal, it doesn't matter
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user