bencode: Support anonymous embedded struct pointers
More to come if this line of improvement is retained.
This commit is contained in:
parent
259356ccd6
commit
25d2eea12d
|
@ -243,21 +243,27 @@ func getDictField(dict reflect.Type, key string) dictField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type structField struct {
|
|
||||||
r reflect.StructField
|
|
||||||
tag tag
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
structFieldsMu sync.Mutex
|
structFieldsMu sync.Mutex
|
||||||
structFields = map[reflect.Type]map[string]dictField{}
|
structFields = map[reflect.Type]map[string]dictField{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseStructFields(struct_ reflect.Type, each func(string, dictField)) {
|
func parseStructFields(struct_ reflect.Type, each func(key string, df dictField)) {
|
||||||
for _i, n := 0, struct_.NumField(); _i < n; _i++ {
|
for _i, n := 0, struct_.NumField(); _i < n; _i++ {
|
||||||
i := _i
|
i := _i
|
||||||
f := struct_.Field(i)
|
f := struct_.Field(i)
|
||||||
if f.Anonymous {
|
if f.Anonymous {
|
||||||
|
parseStructFields(f.Type.Elem(), func(key string, df dictField) {
|
||||||
|
innerGet := df.Get
|
||||||
|
df.Get = func(value reflect.Value) func(reflect.Value) {
|
||||||
|
anonPtr := value.Field(i)
|
||||||
|
if anonPtr.IsNil() {
|
||||||
|
anonPtr.Set(reflect.New(f.Type.Elem()))
|
||||||
|
}
|
||||||
|
return innerGet(anonPtr.Elem())
|
||||||
|
}
|
||||||
|
each(key, df)
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tagStr := f.Tag.Get("bencode")
|
tagStr := f.Tag.Get("bencode")
|
||||||
|
|
|
@ -133,13 +133,16 @@ func (e *Encoder) reflectValue(v reflect.Value) {
|
||||||
e.reflectString(v.String())
|
e.reflectString(v.String())
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
e.writeString("d")
|
e.writeString("d")
|
||||||
for _, ef := range encodeFields(v.Type()) {
|
for _, ef := range getEncodeFields(v.Type()) {
|
||||||
field_value := v.Field(ef.i)
|
fieldValue := ef.i(v)
|
||||||
if ef.omit_empty && isEmptyValue(field_value) {
|
if !fieldValue.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ef.omitEmpty && isEmptyValue(fieldValue) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
e.reflectString(ef.tag)
|
e.reflectString(ef.tag)
|
||||||
e.reflectValue(field_value)
|
e.reflectValue(fieldValue)
|
||||||
}
|
}
|
||||||
e.writeString("e")
|
e.writeString("e")
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
|
@ -190,9 +193,9 @@ func (e *Encoder) reflectValue(v reflect.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type encodeField struct {
|
type encodeField struct {
|
||||||
i int
|
i func(v reflect.Value) reflect.Value
|
||||||
tag string
|
tag string
|
||||||
omit_empty bool
|
omitEmpty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type encodeFieldsSortType []encodeField
|
type encodeFieldsSortType []encodeField
|
||||||
|
@ -206,31 +209,47 @@ var (
|
||||||
encodeFieldsCache = make(map[reflect.Type][]encodeField)
|
encodeFieldsCache = make(map[reflect.Type][]encodeField)
|
||||||
)
|
)
|
||||||
|
|
||||||
func encodeFields(t reflect.Type) []encodeField {
|
func getEncodeFields(t reflect.Type) []encodeField {
|
||||||
typeCacheLock.RLock()
|
typeCacheLock.RLock()
|
||||||
fs, ok := encodeFieldsCache[t]
|
fs, ok := encodeFieldsCache[t]
|
||||||
typeCacheLock.RUnlock()
|
typeCacheLock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
fs = makeEncodeFields(t)
|
||||||
typeCacheLock.Lock()
|
typeCacheLock.Lock()
|
||||||
defer typeCacheLock.Unlock()
|
defer typeCacheLock.Unlock()
|
||||||
fs, ok = encodeFieldsCache[t]
|
encodeFieldsCache[t] = fs
|
||||||
if ok {
|
return fs
|
||||||
return fs
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for i, n := 0, t.NumField(); i < n; i++ {
|
func makeEncodeFields(t reflect.Type) (fs []encodeField) {
|
||||||
|
for _i, n := 0, t.NumField(); _i < n; _i++ {
|
||||||
|
i := _i
|
||||||
f := t.Field(i)
|
f := t.Field(i)
|
||||||
if f.PkgPath != "" {
|
if f.PkgPath != "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if f.Anonymous {
|
if f.Anonymous {
|
||||||
|
anonEFs := makeEncodeFields(f.Type.Elem())
|
||||||
|
for aefi := range anonEFs {
|
||||||
|
anonEF := anonEFs[aefi]
|
||||||
|
bottomField := anonEF
|
||||||
|
bottomField.i = func(v reflect.Value) reflect.Value {
|
||||||
|
v = v.Field(i)
|
||||||
|
if v.IsNil() {
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
|
return anonEF.i(v.Elem())
|
||||||
|
}
|
||||||
|
fs = append(fs, bottomField)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var ef encodeField
|
var ef encodeField
|
||||||
ef.i = i
|
ef.i = func(v reflect.Value) reflect.Value {
|
||||||
|
return v.Field(i)
|
||||||
|
}
|
||||||
ef.tag = f.Name
|
ef.tag = f.Name
|
||||||
|
|
||||||
tv := getTag(f.Tag)
|
tv := getTag(f.Tag)
|
||||||
|
@ -240,11 +259,10 @@ func encodeFields(t reflect.Type) []encodeField {
|
||||||
if tv.Key() != "" {
|
if tv.Key() != "" {
|
||||||
ef.tag = tv.Key()
|
ef.tag = tv.Key()
|
||||||
}
|
}
|
||||||
ef.omit_empty = tv.OmitEmpty()
|
ef.omitEmpty = tv.OmitEmpty()
|
||||||
fs = append(fs, ef)
|
fs = append(fs, ef)
|
||||||
}
|
}
|
||||||
fss := encodeFieldsSortType(fs)
|
fss := encodeFieldsSortType(fs)
|
||||||
sort.Sort(fss)
|
sort.Sort(fss)
|
||||||
encodeFieldsCache[t] = fs
|
|
||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue