2016-02-25 22:59:38 +00:00
|
|
|
|
package pathmatch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
2019-06-21 04:20:17 +00:00
|
|
|
|
errExpectedAPointerToAStruct = newUnsupportedArgumentType("Expected a pointer to a struct, but wasn't.")
|
2016-02-25 22:59:38 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2019-07-11 15:42:02 +00:00
|
|
|
|
// FindAndLoad compares ‘path’ against its (compiled) pattern template; if it matches
|
|
|
|
|
// it loads the matches into ‘dest’, and then returns true.
|
|
|
|
|
//
|
|
|
|
|
// ‘dest’ can be a pointer struct, or a pointer to a []string.
|
|
|
|
|
//
|
|
|
|
|
// Find may set some, or all of the items or fields in ‘dest’ even if it returns false, and even if it returns an error.
|
|
|
|
|
func (pattern *Pattern) FindAndLoad(path string, dest interface{}) (bool, error) {
|
2019-06-21 20:37:53 +00:00
|
|
|
|
if nil == pattern {
|
|
|
|
|
return false, errNilReceiver
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pattern.mutex.RLock()
|
|
|
|
|
defer pattern.mutex.RUnlock()
|
2016-02-25 22:59:38 +00:00
|
|
|
|
|
|
|
|
|
//@TODO: Is it a good idea to be dynamically creating this?
|
|
|
|
|
//@TODO: Also, can the struct fields be put in here directly instead?
|
|
|
|
|
args := []interface{}{}
|
|
|
|
|
numNames := len(pattern.MatchNames())
|
|
|
|
|
for i:=0; i<numNames; i++ {
|
|
|
|
|
args = append(args, new(string))
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 04:51:32 +00:00
|
|
|
|
didMatch, err := pattern.Find(path, args...)
|
2016-02-25 22:59:38 +00:00
|
|
|
|
if nil != err {
|
|
|
|
|
return doesNotMatter, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !didMatch {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 15:42:02 +00:00
|
|
|
|
reflectedValue := reflect.ValueOf(dest)
|
2016-02-25 22:59:38 +00:00
|
|
|
|
if reflect.Ptr != reflectedValue.Kind() {
|
2019-07-11 15:42:02 +00:00
|
|
|
|
//@TODO: change error
|
2016-02-25 22:59:38 +00:00
|
|
|
|
return doesNotMatter, errExpectedAPointerToAStruct
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reflectedValueElem := reflectedValue.Elem()
|
2019-07-11 15:42:02 +00:00
|
|
|
|
switch reflectedValueElem.Kind() {
|
|
|
|
|
case reflect.Slice:
|
|
|
|
|
var a []string = make([]string, len(args))
|
|
|
|
|
for i, arg := range args {
|
|
|
|
|
a[i] = *(arg.(*string))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return loadSlice(dest, a...)
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
return pattern.loadStruct(reflectedValueElem, args)
|
|
|
|
|
default:
|
|
|
|
|
//@TODO: change error
|
|
|
|
|
return doesNotMatter, errExpectedAPointerToAStruct
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func loadSlice(dest interface{}, matches ...string) (bool, error) {
|
|
|
|
|
if nil == dest {
|
|
|
|
|
return false, errNilTarget
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target, casted := dest.(*[]string)
|
|
|
|
|
if !casted {
|
|
|
|
|
//@TODO: CHANGE ERROR! ============================
|
|
|
|
|
return false, errExpectedAPointerToAStruct
|
|
|
|
|
}
|
|
|
|
|
if nil == target {
|
|
|
|
|
return false, errNilTarget
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*target = (*target)[:0]
|
|
|
|
|
for _, match := range matches {
|
|
|
|
|
*target = append(*target, match)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pattern *Pattern) loadStruct(reflectedValueElem reflect.Value, args []interface{}) (bool, error) {
|
|
|
|
|
if nil == pattern {
|
|
|
|
|
return false, errNilReceiver
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 04:31:34 +00:00
|
|
|
|
if reflect.Struct != reflectedValueElem.Kind() {
|
|
|
|
|
return doesNotMatter, errExpectedAPointerToAStruct
|
|
|
|
|
}
|
2016-02-25 22:59:38 +00:00
|
|
|
|
|
|
|
|
|
reflectedValueElemType := reflectedValueElem.Type()
|
|
|
|
|
|
|
|
|
|
numFields := reflectedValueElemType.NumField()
|
|
|
|
|
for fieldNumber:=0; fieldNumber<numFields; fieldNumber++ {
|
|
|
|
|
//field := reflectedValueElemType.Field(fieldNumber)
|
|
|
|
|
|
|
|
|
|
//fieldTag := field.Tag
|
|
|
|
|
|
|
|
|
|
//name := fieldTag.Get(pattern.fieldTagName)
|
|
|
|
|
|
|
|
|
|
value := *(args[fieldNumber].(*string))
|
|
|
|
|
|
|
|
|
|
err := func(rValue reflect.Value, value string, matchName string) (err error) {
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
|
|
|
|
if r := recover(); nil != r {
|
|
|
|
|
// See if we received a message of the form:
|
|
|
|
|
//
|
|
|
|
|
// reflect.Set: value of type ??? is not assignable to type ???
|
|
|
|
|
//
|
|
|
|
|
// If we did then we interpret this as the programmer using this
|
|
|
|
|
// trying to load into a struct field of the wrong type.
|
|
|
|
|
//
|
|
|
|
|
// We return a special error for that.
|
|
|
|
|
if s, ok := r.(string); ok {
|
|
|
|
|
needle := "reflect.Set: value of type "
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix(s, needle) {
|
|
|
|
|
needle = " is not assignable to type "
|
|
|
|
|
|
|
|
|
|
if strings.Contains(s, needle) {
|
2019-06-21 04:24:04 +00:00
|
|
|
|
err = newStructFieldWrongType(matchName)
|
2016-02-25 22:59:38 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 00:10:46 +00:00
|
|
|
|
msg := fmt.Sprintf("%T %v", r, r)
|
2016-02-25 22:59:38 +00:00
|
|
|
|
|
|
|
|
|
err = errors.New( msg )
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
rValue.Set( reflect.ValueOf(value) )
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}(reflectedValueElem.Field(fieldNumber), value, pattern.fieldTagName)
|
|
|
|
|
if nil != err {
|
|
|
|
|
return doesNotMatter, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|