diff options
Diffstat (limited to 'vendor/github.com/alexflint/go-arg/reflect.go')
| -rw-r--r-- | vendor/github.com/alexflint/go-arg/reflect.go | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/vendor/github.com/alexflint/go-arg/reflect.go b/vendor/github.com/alexflint/go-arg/reflect.go new file mode 100644 index 0000000..cd80be7 --- /dev/null +++ b/vendor/github.com/alexflint/go-arg/reflect.go | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | package arg | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "encoding" | ||
| 5 | "fmt" | ||
| 6 | "reflect" | ||
| 7 | "unicode" | ||
| 8 | "unicode/utf8" | ||
| 9 | |||
| 10 | scalar "github.com/alexflint/go-scalar" | ||
| 11 | ) | ||
| 12 | |||
| 13 | var textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem() | ||
| 14 | |||
| 15 | // cardinality tracks how many tokens are expected for a given spec | ||
| 16 | // - zero is a boolean, which does to expect any value | ||
| 17 | // - one is an ordinary option that will be parsed from a single token | ||
| 18 | // - multiple is a slice or map that can accept zero or more tokens | ||
| 19 | type cardinality int | ||
| 20 | |||
| 21 | const ( | ||
| 22 | zero cardinality = iota | ||
| 23 | one | ||
| 24 | multiple | ||
| 25 | unsupported | ||
| 26 | ) | ||
| 27 | |||
| 28 | func (k cardinality) String() string { | ||
| 29 | switch k { | ||
| 30 | case zero: | ||
| 31 | return "zero" | ||
| 32 | case one: | ||
| 33 | return "one" | ||
| 34 | case multiple: | ||
| 35 | return "multiple" | ||
| 36 | case unsupported: | ||
| 37 | return "unsupported" | ||
| 38 | default: | ||
| 39 | return fmt.Sprintf("unknown(%d)", int(k)) | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | // cardinalityOf returns true if the type can be parsed from a string | ||
| 44 | func cardinalityOf(t reflect.Type) (cardinality, error) { | ||
| 45 | if scalar.CanParse(t) { | ||
| 46 | if isBoolean(t) { | ||
| 47 | return zero, nil | ||
| 48 | } | ||
| 49 | return one, nil | ||
| 50 | } | ||
| 51 | |||
| 52 | // look inside pointer types | ||
| 53 | if t.Kind() == reflect.Ptr { | ||
| 54 | t = t.Elem() | ||
| 55 | } | ||
| 56 | |||
| 57 | // look inside slice and map types | ||
| 58 | switch t.Kind() { | ||
| 59 | case reflect.Slice: | ||
| 60 | if !scalar.CanParse(t.Elem()) { | ||
| 61 | return unsupported, fmt.Errorf("cannot parse into %v because %v not supported", t, t.Elem()) | ||
| 62 | } | ||
| 63 | return multiple, nil | ||
| 64 | case reflect.Map: | ||
| 65 | if !scalar.CanParse(t.Key()) { | ||
| 66 | return unsupported, fmt.Errorf("cannot parse into %v because key type %v not supported", t, t.Elem()) | ||
| 67 | } | ||
| 68 | if !scalar.CanParse(t.Elem()) { | ||
| 69 | return unsupported, fmt.Errorf("cannot parse into %v because value type %v not supported", t, t.Elem()) | ||
| 70 | } | ||
| 71 | return multiple, nil | ||
| 72 | default: | ||
| 73 | return unsupported, fmt.Errorf("cannot parse into %v", t) | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | // isBoolean returns true if the type can be parsed from a single string | ||
| 78 | func isBoolean(t reflect.Type) bool { | ||
| 79 | switch { | ||
| 80 | case t.Implements(textUnmarshalerType): | ||
| 81 | return false | ||
| 82 | case t.Kind() == reflect.Bool: | ||
| 83 | return true | ||
| 84 | case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Bool: | ||
| 85 | return true | ||
| 86 | default: | ||
| 87 | return false | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | // isExported returns true if the struct field name is exported | ||
| 92 | func isExported(field string) bool { | ||
| 93 | r, _ := utf8.DecodeRuneInString(field) // returns RuneError for empty string or invalid UTF8 | ||
| 94 | return unicode.IsLetter(r) && unicode.IsUpper(r) | ||
| 95 | } | ||
| 96 | |||
| 97 | // isZero returns true if v contains the zero value for its type | ||
| 98 | func isZero(v reflect.Value) bool { | ||
| 99 | t := v.Type() | ||
| 100 | if t.Kind() == reflect.Slice || t.Kind() == reflect.Map { | ||
| 101 | return v.IsNil() | ||
| 102 | } | ||
| 103 | if !t.Comparable() { | ||
| 104 | return false | ||
| 105 | } | ||
| 106 | return v.Interface() == reflect.Zero(t).Interface() | ||
| 107 | } | ||
