]> Sergey Matveev's repositories - btrtrc.git/blobdiff - bencode/encode.go
Drop support for go 1.20
[btrtrc.git] / bencode / encode.go
index f25cfef82bdf4ed70df4728f5f3bf119a9a1c462..5e80cb16f5c60cc7c5c720cbd04e49479f3bcd33 100644 (file)
@@ -64,16 +64,18 @@ func (e *Encoder) writeString(s string) {
 }
 
 func (e *Encoder) reflectString(s string) {
-       b := strconv.AppendInt(e.scratch[:0], int64(len(s)), 10)
-       e.write(b)
-       e.writeString(":")
+       e.writeStringPrefix(int64(len(s)))
        e.writeString(s)
 }
 
-func (e *Encoder) reflectByteSlice(s []byte) {
-       b := strconv.AppendInt(e.scratch[:0], int64(len(s)), 10)
+func (e *Encoder) writeStringPrefix(l int64) {
+       b := strconv.AppendInt(e.scratch[:0], l, 10)
        e.write(b)
        e.writeString(":")
+}
+
+func (e *Encoder) reflectByteSlice(s []byte) {
+       e.writeStringPrefix(int64(len(s)))
        e.write(s)
 }
 
@@ -96,10 +98,9 @@ func (e *Encoder) reflectMarshaler(v reflect.Value) bool {
        return true
 }
 
-var bigIntType = reflect.TypeOf(big.Int{})
+var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
 
 func (e *Encoder) reflectValue(v reflect.Value) {
-
        if e.reflectMarshaler(v) {
                return
        }
@@ -161,23 +162,8 @@ func (e *Encoder) reflectValue(v reflect.Value) {
                        e.reflectValue(v.MapIndex(key))
                }
                e.writeString("e")
-       case reflect.Slice:
-               if v.Type().Elem().Kind() == reflect.Uint8 {
-                       s := v.Bytes()
-                       e.reflectByteSlice(s)
-                       break
-               }
-               if v.IsNil() {
-                       e.writeString("le")
-                       break
-               }
-               fallthrough
-       case reflect.Array:
-               e.writeString("l")
-               for i, n := 0, v.Len(); i < n; i++ {
-                       e.reflectValue(v.Index(i))
-               }
-               e.writeString("e")
+       case reflect.Slice, reflect.Array:
+               e.reflectSequence(v)
        case reflect.Interface:
                e.reflectValue(v.Elem())
        case reflect.Ptr:
@@ -192,6 +178,37 @@ func (e *Encoder) reflectValue(v reflect.Value) {
        }
 }
 
+func (e *Encoder) reflectSequence(v reflect.Value) {
+       // Use bencode string-type
+       if v.Type().Elem().Kind() == reflect.Uint8 {
+               if v.Kind() != reflect.Slice {
+                       // Can't use []byte optimization
+                       if !v.CanAddr() {
+                               e.writeStringPrefix(int64(v.Len()))
+                               for i := 0; i < v.Len(); i++ {
+                                       var b [1]byte
+                                       b[0] = byte(v.Index(i).Uint())
+                                       e.write(b[:])
+                               }
+                               return
+                       }
+                       v = v.Slice(0, v.Len())
+               }
+               s := v.Bytes()
+               e.reflectByteSlice(s)
+               return
+       }
+       if v.IsNil() {
+               e.writeString("le")
+               return
+       }
+       e.writeString("l")
+       for i, n := 0, v.Len(); i < n; i++ {
+               e.reflectValue(v.Index(i))
+       }
+       e.writeString("e")
+}
+
 type encodeField struct {
        i         func(v reflect.Value) reflect.Value
        tag       string
@@ -231,16 +248,24 @@ func makeEncodeFields(t reflect.Type) (fs []encodeField) {
                        continue
                }
                if f.Anonymous {
-                       anonEFs := makeEncodeFields(f.Type.Elem())
+                       t := f.Type
+                       if t.Kind() == reflect.Ptr {
+                               t = t.Elem()
+                       }
+                       anonEFs := makeEncodeFields(t)
                        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{}
+                                       if v.Kind() == reflect.Ptr {
+                                               if v.IsNil() {
+                                                       // This will skip serializing this value.
+                                                       return reflect.Value{}
+                                               }
+                                               v = v.Elem()
                                        }
-                                       return anonEF.i(v.Elem())
+                                       return anonEF.i(v)
                                }
                                fs = append(fs, bottomField)
                        }