now marshaller respects options like 'omitempty'

This commit is contained in:
Vincent Batts 2014-08-14 21:05:31 -04:00
parent 058076e94f
commit e27d7cfab2
3 changed files with 71 additions and 3 deletions

View file

@ -424,7 +424,7 @@ func bencodeKey(field reflect.StructField) (key string) {
} }
} }
} }
return return key
} }
func writeStruct(w io.Writer, val reflect.Value) (err error) { func writeStruct(w io.Writer, val reflect.Value) (err error) {
@ -440,7 +440,11 @@ func writeStruct(w io.Writer, val reflect.Value) (err error) {
for i := 0; i < numFields; i++ { for i := 0; i < numFields; i++ {
field := typ.Field(i) field := typ.Field(i)
svList[i].key = bencodeKey(field) key, opts := parseTag(bencodeKey(field))
if key == "-" || opts.Contains("omitempty") && isEmptyValue(val.Field(i)) {
continue
}
svList[i].key = key
svList[i].value = val.Field(i) svList[i].value = val.Field(i)
} }
@ -456,6 +460,59 @@ func writeStruct(w io.Writer, val reflect.Value) (err error) {
return return
} }
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains reports whether a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}
func writeValue(w io.Writer, val reflect.Value) (err error) { func writeValue(w io.Writer, val reflect.Value) (err error) {
if !val.IsValid() { if !val.IsValid() {
err = errors.New("Can't write null value") err = errors.New("Can't write null value")

View file

@ -1,12 +1,14 @@
package bencode package bencode
import ( import (
"bytes"
"testing" "testing"
) )
type testStruct struct { type testStruct struct {
Field1 string `bencode:"my field1"` Field1 string `bencode:"my field1"`
Field2 int64 `bencode:"my field2"` Field2 int64 `bencode:"my field2"`
Field3 int64 `bencode:"my field3,omitempty"`
} }
type testOldTag struct { type testOldTag struct {
@ -15,12 +17,16 @@ type testOldTag struct {
} }
func TestMarshalling(t *testing.T) { func TestMarshalling(t *testing.T) {
ts1 := testStruct{"foo", 123456} ts1 := testStruct{Field1: "foo", Field2: 123456}
buf, err := Marshal(ts1) buf, err := Marshal(ts1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if bytes.Contains(buf, []byte("omitempty")) || bytes.Contains(buf, []byte("field3")) {
t.Errorf("should not have the string 'omitempty' or 'field3' in %q", buf)
}
ts2 := testStruct{} ts2 := testStruct{}
err = Unmarshal(buf, &ts2) err = Unmarshal(buf, &ts2)
if err != nil { if err != nil {

View file

@ -1,6 +1,7 @@
package torrent package torrent
import ( import (
"bytes"
"github.com/vbatts/go-bt/bencode" "github.com/vbatts/go-bt/bencode"
"testing" "testing"
) )
@ -19,6 +20,10 @@ func TestFileMarshal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if bytes.Contains(buf, []byte("omitempty")) || bytes.Contains(buf, []byte("created by")) {
t.Errorf("should not have the string 'omitempty' or 'created by' in %q", buf)
}
f2 := File{} f2 := File{}
err = bencode.Unmarshal(buf, &f2) err = bencode.Unmarshal(buf, &f2)
if err != nil { if err != nil {