zeebo / bencode Goto Github PK
View Code? Open in Web Editor NEWGo bencode marshal/unmarshal library
Home Page: http://godoc.org/github.com/zeebo/bencode
License: MIT License
Go bencode marshal/unmarshal library
Home Page: http://godoc.org/github.com/zeebo/bencode
License: MIT License
code at https://github.com/zeebo/bencode/blob/master/decode_test.go#L241 and https://github.com/zeebo/bencode/blob/master/decode_test.go#L242 should be
{"d1:Yi10e1:X1:a3:zff1:ce", new(dT), dT{}, true, true},
{"d3:zff1:c1:Yi10e1:X1:ae", new(dT), dT{}, true, true},
Currently travis CI is missing, I would recommend to add it (or any other CI that you would wish to use for this project).
I think it would be good to add some sort of helper function in the form:
func NewDecoderFromBytes(data []byte) *Decoder {
reader := bytes.NewBuffer(data)
return NewDecoder(reader)
}
I frequently find myself using this and it would assist in shorthand for RawMessage processing.
There are helper functions for encoding and decoding strings but not for bytes:
func DecodeString(in string, val interface{}) error
func EncodeString(val interface{}) (string, error)
If you don't have any objection, I would like to implement
func DecodeBytes(b []byte, val interface{}) error
func EncodeBytes(val interface{}) ([]byte, error)
functions and send you a pull request, OK?
Currently it is not possible to control how a type is to be encoded (and decoded again). However similar to other packages (YAML/JSON), it would be quite useful to be able to control this for certain types.
As you seem to take inspiration from the std JSON package I think we can keep the Marshaler as simple as:
// Marshaler is the interface implemented by types
// that can marshal themselves into valid bencode.
type Marshaler interface {
MarshalBencode() ([]byte, error)
}
I think implementing that could be as simple as:
diff --git a/encode.go b/encode.go
index eac347a..3ca2e40 100644
--- a/encode.go
+++ b/encode.go
@@ -29,6 +29,12 @@ func (p sortFields) Less(i, j int) bool {
}
func (p sortFields) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+// Marshaler is the interface implemented by types
+// that can marshal themselves into valid bencode.
+type Marshaler interface {
+ MarshalBencode() ([]byte, error)
+}
+
//An Encoder writes bencoded objects to an output stream.
type Encoder struct {
w io.Writer
@@ -81,6 +87,18 @@ func encodeValue(w io.Writer, val reflect.Value) error {
return nil
}
+ // marshal a type using the Marshaler type
+ // if it implements that interface.
+ if marshaler, ok := v.Interface().(Marshaler); ok {
+ bytes, err := marshaler.MarshalBencode()
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(bytes)
+ return err
+ }
+
//send in a raw message if we have that type
if rm, ok := v.Interface().(RawMessage); ok {
_, err := io.Copy(w, bytes.NewReader(rm))
But feel free to correct me, in case I'm missing any complexities though.
For the Unmarshaler things get however a bit more complicated. I would propose to again keep the interface as simple as:
// Unmarshaler is the interface implemented by types that can unmarshal
// a bencode description of themselves.
// The input can be assumed to be a valid encoding of a bencode value.
// UnmarshalBencode must copy the bencode data if it wishes to retain the data after returning.
type Unmarshaler interface {
UnmarshalBencode([]byte) error
}
However implementing it is a bit more complicated than I had imagined, due to the fact that the code doesn't seem to have taken that possibility into account. The std encoding/json
package seems to resolve this by having a handy function available called next()
which returns the next available JSON value from the available buffer, however such a utility function doesn't seem to be available in your decoder.
So perhaps you have an idea on how we could resolve this?
Thank you for providing this package though, a couple of months ago I was almost implementing my own bencode package from scratch, until I found yours, so this saved me a lot of work, for which lots of thanks! The package works great, But I now have a scenario where I could really use the possibility to provide my own encode/decode logic (using a marshaler/unmarshaler), such that I can encode my struct as a custom string value rather than a dictionary.
As we now also support full Marshaler/Unmarshaler interfaces, it would also make sense to support encoding.TextUnmarshaler
and encoding.TextMarshaler
. Similar to JSON it can be used to automatically decode/encode the value from a bencode string, and let the value take it from there. It's a neat interface, as it allows a type to be (un)marshalled, regardless of the encoding format. Making it much easier than having to support 3 different interfaces for a single type.
Seems like a nil
values are not properly decoded. Rather than the decoded value being nil
, it is initialized with the given type.
Here's a test case to re-produce:
import (
"testing"
"github.com/zeebo/bencode"
)
type TT struct {
Name string
}
type TestStruct struct {
T *TT
}
func Test_Bencode(t *testing.T) {
var val TestStruct
b, err := bencode.EncodeBytes(&val)
if err != nil {
t.Fatal(err)
}
var v1 TestStruct
if err = bencode.DecodeBytes(b, &v1); err != nil {
t.Fatal(err)
}
if v1.T != nil {
t.Fatalf("v1.T should be nil. got: %#v", v1.T)
}
}
Pretty much what the title says.
Encoding e.g. []byte{'1','2','3'}
results in li49ei50ei51ee
, while 3:123 would be much more suitable. Actually, one of the biggest points of bencode is binary safety, i.e. you can encode arbitrary binary strings without escaping or other transformation; encoding []byte
the way it is done now is not making advantage of this.
Of course it currently works, however performance could be improved by doing this right.
Workaround: cast every []byte
to a string
. Not pretty though.
we need to be careful around our usage of indirect and checking if the value implements some interface during encoding. i suspect there are some bugs.
package main
import (
"fmt"
"github.com/zeebo/bencode"
)
type Bug struct {
Name string `bencode:"name"`
NameUtf8 string `bencode:"name.utf-8"`
}
func main() {
b := map[string]string{
"name": "name",
"name.utf-8": "name.utf-8",
}
str, _ := bencode.EncodeString(&b)
fmt.Println(str)
bug := new(Bug)
bencode.DecodeString(str, bug)
fmt.Printf("%+v\n", bug)
}
The Go encoding/json package has support for post-processing of data using a type json.RawMessage. When decoding into a struct, if a type is of json.RawMessage, the []byte data is put into that for post-processing. This is useful when you don't know the type in advance (such as in the net/rpc package).
Line 412 in a0e3ea0
f.PkgPath != "" && !f.Anonymous
PR #19 introduced this issue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.