-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlist.go
118 lines (104 loc) · 2.93 KB
/
list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package myflags
import (
"encoding"
// "flag"
"fmt"
"reflect"
"strings"
flag "github.com/hujun-open/pflag"
)
// this is to support slice and array
type listType struct {
val reflect.Value //need to be a pointer to slice/array
tags reflect.StructTag
conv RegisteredConverters //converter for the element
}
func (list *listType) String() string {
// fmt.Println("type", typeToStr(slice.val.Interface()))
r := ""
if !list.val.IsValid() {
return ""
}
if list.val.Elem().Len() == 0 {
return r
}
for i := 0; i < list.val.Elem().Len(); i++ {
elemVal := list.val.Elem().Index(i).Interface()
if list.val.Elem().Index(i).Kind() == reflect.Pointer {
if list.val.Elem().Index(i).IsNil() {
r += ","
continue
}
} else {
elemVal = list.val.Elem().Index(i).Addr().Interface()
}
r += list.conv.ToStr(elemVal, list.tags) + ","
}
return r[:len(r)-1]
}
func (list *listType) Type() string {
t := list.val.Type()
if list.val.Kind() == reflect.Pointer {
t = list.val.Elem().Type()
}
return t.String()
}
func (list *listType) Set(s string) error {
//check if the slice's element is pointer
isElmPointer := list.val.Type().Elem().Elem().Kind() == reflect.Pointer
isArray := list.val.Type().Elem().Kind() == reflect.Array
list.val.Elem().SetZero()
for i, ns := range strings.FieldsFunc(s, func(c rune) bool { return c == ',' }) {
ns = strings.TrimSpace(ns)
n, err := list.conv.FromStr(ns, list.tags)
if err != nil {
return err
}
if !isArray {
//slice
if !isElmPointer {
list.val.Elem().Set(reflect.Append(list.val.Elem(), reflect.ValueOf(n)))
} else {
newval := reflect.New(list.val.Type().Elem().Elem().Elem())
newval.Elem().Set(reflect.ValueOf(n))
list.val.Elem().Set(reflect.Append(list.val.Elem(), newval))
}
} else {
//array
if !isElmPointer {
list.val.Elem().Index(i).Set(reflect.ValueOf(n))
} else {
newval := reflect.New(list.val.Type().Elem().Elem().Elem())
newval.Elem().Set(reflect.ValueOf(n))
list.val.Elem().Index(i).Set(newval)
}
}
}
return nil
}
func processList(fs *flag.FlagSet, ref reflect.Value, tag reflect.StructTag, name, usage string) error {
rconv := globalRegistry.GetViaType(ref.Type().Elem().Elem())
var newval listType
if rconv == nil {
var unm reflect.Value
if ref.Type().Elem().Elem().Implements(textEncodingInt) {
//list of pointer to textmarshalce
unm = reflect.New(ref.Type().Elem().Elem().Elem())
} else {
if reflect.PointerTo(ref.Type().Elem().Elem()).Implements(textEncodingInt) {
//list of textmarshalce
unm = reflect.New(ref.Type().Elem().Elem())
}
}
if unm.IsValid() {
newval = listType{val: ref, tags: tag,
conv: &textMarshalConverter{unmarshaller: unm.Interface().(encoding.TextUnmarshaler)}}
} else {
return fmt.Errorf("%v is not registered", ref.Type().Elem().Elem())
}
} else {
newval = listType{val: ref, tags: tag, conv: rconv}
}
fs.Var(&newval, name, usage)
return nil
}