Skip to content

Commit bc6d729

Browse files
committed
Add support for embedded structs
1 parent 24a2c3f commit bc6d729

File tree

4 files changed

+113
-11
lines changed

4 files changed

+113
-11
lines changed

decoder.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ func (d *decoder) readDictionary() (map[string]interface{}, error) {
175175
if _, err := d.reader.ReadByte(); err != nil {
176176
return nil, err
177177
}
178+
178179
var v interface{}
179180
for {
180181
s, _ := d.readString()
@@ -201,6 +202,7 @@ func (d *decoder) readDictionary() (map[string]interface{}, error) {
201202
case reflect.Map:
202203
v, err = d.readDictionary()
203204
}
205+
204206
res[s] = v
205207
if err != nil {
206208
return res, err
@@ -238,8 +240,15 @@ func getStructFields(t reflect.Type) map[string]reflect.StructField {
238240
r := make(map[string]reflect.StructField)
239241
for i := 0; i < t.NumField(); i++ {
240242
f := t.Field(i)
241-
r[string(f.Tag.Get("bencode"))] = f
242-
}
243+
tag := string(f.Tag.Get("bencode"))
244+
if len(tag) == 0 {
245+
for et, ev := range getStructFields(f.Type) {
246+
r[et] = ev
247+
}
248+
continue
249+
}
250+
r[tag] = f
251+
}
243252
return r
244253
}
245254

decoder_test.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package bencode
22

33
import (
4-
"fmt"
54
"reflect"
65
"testing"
76
)
@@ -75,8 +74,50 @@ func TestDecodeMockTorrentFile(t *testing.T) {
7574
t.Error(err)
7675
}
7776
if !reflect.DeepEqual(have, want) {
78-
fmt.Println(have.Info)
79-
fmt.Println(want.Info)
8077
t.Errorf("Struct not properly hidrated: wanted %+v but have %+v", want, have)
8178
}
8279
}
80+
81+
func TestDecodeEmbeddedStruct(t *testing.T) {
82+
type base struct {
83+
Basefield string `bencode:"base"`
84+
}
85+
type extended struct {
86+
base
87+
Extendedfield string `bencode:"extended"`
88+
}
89+
have := &extended{}
90+
want := &extended{base{"base"}, "extended"}
91+
input := []byte("d4:base4:base8:extended8:extendede")
92+
err := Decode(input, have)
93+
if err != nil {
94+
t.Error(err)
95+
}
96+
if !reflect.DeepEqual(have, want) {
97+
t.Errorf("Struct not properly encoded: wanted %s but have %s", want, have)
98+
}
99+
}
100+
101+
func TestDecodeDoubleEmbeddedStruct(t *testing.T) {
102+
type base struct {
103+
Basefield string `bencode:"base"`
104+
}
105+
type extended struct {
106+
base
107+
Extendedfield string `bencode:"extended"`
108+
}
109+
type doubleExtended struct {
110+
extended
111+
DoubleExtendedField string `bencode:"doubleExtended"`
112+
}
113+
have := &doubleExtended{}
114+
want := &doubleExtended{extended{base{"base"}, "extended"}, "doubleExtended"}
115+
input := []byte("d4:base4:base14:doubleExtended14:doubleExtended8:extended8:extendede")
116+
err := Decode(input, have)
117+
if err != nil {
118+
t.Error(err)
119+
}
120+
if !reflect.DeepEqual(have, want) {
121+
t.Errorf("Struct not properly encoded: wanted %s but have %s", want, have)
122+
}
123+
}

encoder.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,37 @@ func (e *encoder) encodeList(rv reflect.Value) {
4343

4444
func (e *encoder) encodeDict(rv reflect.Value) error {
4545
e.output.WriteByte('d')
46+
e.traverseStruct(rv)
47+
e.output.WriteByte('e')
48+
return nil
49+
}
50+
51+
func (e *encoder) traverseStruct(rv reflect.Value) error {
4652
indirect := reflect.Indirect(rv)
4753
for i := 0; i < indirect.NumField(); i++ {
54+
key := indirect.Type().Field(i).Tag.Get("bencode")
4855
switch indirect.Type().Field(i).Type.Kind() {
4956
case reflect.Uint64:
50-
e.encodeString(indirect.Type().Field(i).Tag.Get("bencode"))
57+
e.encodeString(key)
5158
e.encodeUint(indirect.Field(i).Interface().(uint64))
5259
case reflect.String:
53-
e.encodeString(indirect.Type().Field(i).Tag.Get("bencode"))
60+
e.encodeString(key)
5461
e.encodeString(indirect.Field(i).Interface().(string))
5562
case reflect.Struct:
56-
e.encodeString(indirect.Type().Field(i).Tag.Get("bencode"))
57-
if err := e.encodeDict(indirect.Field(i).Addr()); err != nil {
63+
str := indirect.Field(i).Addr()
64+
if len(key) == 0 {
65+
e.traverseStruct(str)
66+
continue
67+
}
68+
e.encodeString(key)
69+
if err := e.encodeDict(str); err != nil {
5870
return err
5971
}
6072
case reflect.Slice:
61-
e.encodeString(indirect.Type().Field(i).Tag.Get("bencode"))
73+
e.encodeString(key)
6274
e.encodeList(indirect.Field(i).Addr())
6375
}
6476
}
65-
e.output.WriteByte('e')
6677
return nil
6778
}
6879

encoder_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,44 @@ func TestEncodeMockTorrentFile(t *testing.T) {
7171
t.Errorf("Struct not properly encoded: wanted %s but have %s", want, have)
7272
}
7373
}
74+
75+
func TestEncodeEmbeddedStruct(t *testing.T) {
76+
type base struct {
77+
Basefield string `bencode:"base"`
78+
}
79+
type extended struct {
80+
base
81+
Extendedfield string `bencode:"extended"`
82+
}
83+
have, err := Encode(&extended{base{"base"}, "extended"})
84+
want := []byte("d4:base4:base8:extended8:extendede")
85+
if err != nil {
86+
t.Error(err)
87+
}
88+
if !reflect.DeepEqual(have, want) {
89+
t.Errorf("Struct not properly encoded: wanted %s but have %s", want, have)
90+
}
91+
}
92+
93+
func TestEncodeDoubleEmbeddedStruct(t *testing.T) {
94+
type base struct {
95+
Basefield string `bencode:"base"`
96+
}
97+
type extended struct {
98+
base
99+
Extendedfield string `bencode:"extended"`
100+
}
101+
type doubleExtended struct {
102+
extended
103+
DoubleExtendedField string `bencode:"doubleExtended"`
104+
}
105+
have, err := Encode(&doubleExtended{extended{base{"base"}, "extended"}, "doubleExtended"})
106+
want := []byte("d4:base4:base8:extended8:extended14:doubleExtended14:doubleExtendede")
107+
if err != nil {
108+
t.Error(err)
109+
}
110+
if !reflect.DeepEqual(have, want) {
111+
t.Errorf("Struct not properly encoded: wanted %s but have %s", want, have)
112+
}
113+
}
114+

0 commit comments

Comments
 (0)