package bencode
-import "bytes"
-import "bufio"
-import "reflect"
-import "strconv"
-import "io"
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+
+ "github.com/anacrolix/missinggo/expect"
+)
//----------------------------------------------------------------------------
// Errors
//----------------------------------------------------------------------------
-// In case if marshaler cannot encode a type in bencode, it will return this
-// error. Typical example of such type is float32/float64 which has no bencode
-// representation
+// In case if marshaler cannot encode a type, it will return this error. Typical
+// example of such type is float32/float64 which has no bencode representation.
type MarshalTypeError struct {
Type reflect.Type
}
-func (this *MarshalTypeError) Error() string {
- return "bencode: unsupported type: " + this.Type.String()
+func (e *MarshalTypeError) Error() string {
+ return "bencode: unsupported type: " + e.Type.String()
}
// Unmarshal argument must be a non-nil value of some pointer type.
return "bencode: Unmarshal(nil " + e.Type.String() + ")"
}
-// Unmarshaler spotted a value that was not appropriate for a given specific Go
-// value
+// Unmarshaler spotted a value that was not appropriate for a given Go value.
type UnmarshalTypeError struct {
- Value string
- Type reflect.Type
+ BencodeTypeName string
+ UnmarshalTargetType reflect.Type
}
+// This could probably be a value type, but we may already have users assuming
+// that it's passed by pointer.
func (e *UnmarshalTypeError) Error() string {
- return "bencode: value (" + e.Value + ") is not appropriate for type: " +
- e.Type.String()
+ return fmt.Sprintf(
+ "can't unmarshal a bencode %v into a %v",
+ e.BencodeTypeName,
+ e.UnmarshalTargetType,
+ )
}
// Unmarshaler tried to write to an unexported (therefore unwritable) field.
e.Field.Name + "\" in type: " + e.Type.String()
}
+// Malformed bencode input, unmarshaler failed to parse it.
type SyntaxError struct {
- Offset int64 // location of the error
- what string // error description
+ Offset int64 // location of the error
+ What error // error description
}
func (e *SyntaxError) Error() string {
- return "bencode: syntax error (offset: " +
- strconv.FormatInt(e.Offset, 10) +
- "): " + e.what
+ return fmt.Sprintf("bencode: syntax error (offset: %d): %s", e.Offset, e.What)
+}
+
+// A non-nil error was returned after calling MarshalBencode on a type which
+// implements the Marshaler interface.
+type MarshalerError struct {
+ Type reflect.Type
+ Err error
+}
+
+func (e *MarshalerError) Error() string {
+ return "bencode: error calling MarshalBencode for type " + e.Type.String() + ": " + e.Err.Error()
+}
+
+// A non-nil error was returned after calling UnmarshalBencode on a type which
+// implements the Unmarshaler interface.
+type UnmarshalerError struct {
+ Type reflect.Type
+ Err error
+}
+
+func (e *UnmarshalerError) Error() string {
+ return "bencode: error calling UnmarshalBencode for type " + e.Type.String() + ": " + e.Err.Error()
}
//----------------------------------------------------------------------------
// Interfaces
//----------------------------------------------------------------------------
-// unused for now (TODO)
+// Any type which implements this interface, will be marshaled using the
+// specified method.
type Marshaler interface {
MarshalBencode() ([]byte, error)
}
-// unused for now (TODO)
+// Any type which implements this interface, will be unmarshaled using the
+// specified method.
type Unmarshaler interface {
UnmarshalBencode([]byte) error
}
-//----------------------------------------------------------------------------
-// Stateless interface
-//----------------------------------------------------------------------------
-
+// Marshal the value 'v' to the bencode form, return the result as []byte and
+// an error if any.
func Marshal(v interface{}) ([]byte, error) {
var buf bytes.Buffer
- e := encoder{Writer: bufio.NewWriter(&buf)}
- err := e.encode(v)
+ e := Encoder{w: &buf}
+ err := e.Encode(v)
if err != nil {
return nil, err
}
- err = e.Flush()
- return buf.Bytes(), err
+ return buf.Bytes(), nil
}
-func Unmarshal(data []byte, v interface{}) error {
- e := decoder{Reader: bufio.NewReader(bytes.NewBuffer(data))}
- return e.decode(v)
+func MustMarshal(v interface{}) []byte {
+ b, err := Marshal(v)
+ expect.Nil(err)
+ return b
}
-//----------------------------------------------------------------------------
-// Stateful interface
-//----------------------------------------------------------------------------
-
-type Decoder struct {
- d decoder
+// Unmarshal the bencode value in the 'data' to a value pointed by the 'v' pointer, return a non-nil
+// error if any. If there are trailing bytes, this results in ErrUnusedTrailingBytes, but the value
+// will be valid. It's probably more consistent to use Decoder.Decode if you want to rely on this
+// behaviour (inspired by Rust's serde here).
+func Unmarshal(data []byte, v interface{}) (err error) {
+ buf := bytes.NewReader(data)
+ e := Decoder{r: buf}
+ err = e.Decode(v)
+ if err == nil && buf.Len() != 0 {
+ err = ErrUnusedTrailingBytes{buf.Len()}
+ }
+ return
}
-func NewDecoder(r io.Reader) *Decoder {
- return &Decoder{decoder{Reader: bufio.NewReader(r)}}
+type ErrUnusedTrailingBytes struct {
+ NumUnusedBytes int
}
-func (d *Decoder) Decode(v interface{}) error {
- return d.d.decode(v)
+func (me ErrUnusedTrailingBytes) Error() string {
+ return fmt.Sprintf("%d unused trailing bytes", me.NumUnusedBytes)
}
-type Encoder struct {
- e encoder
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: &scanner{r: r}}
}
func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{encoder{Writer: bufio.NewWriter(w)}}
-}
-
-func (e *Encoder) Encode(v interface{}) error {
- err := e.e.encode(v)
- if err != nil {
- return err
- }
- return e.e.Flush()
+ return &Encoder{w: w}
}