diff --git a/pkg/__test__/go.mod b/pkg/__test__/go.mod index 31a8e1e..daad059 100644 --- a/pkg/__test__/go.mod +++ b/pkg/__test__/go.mod @@ -3,18 +3,29 @@ module l12.xyz/dal/tests go 1.22.6 require l12.xyz/dal/builder v0.0.0 + replace l12.xyz/dal/builder v0.0.0 => ../builder replace l12.xyz/dal/utils v0.0.0 => ../utils require l12.xyz/dal/adapter v0.0.0 +require l12.xyz/dal/proto v0.0.0 + +require ( + github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect + github.com/tinylib/msgp v1.2.0 // indirect +) + replace l12.xyz/dal/adapter v0.0.0 => ../adapter + +replace l12.xyz/dal/proto v0.0.0 => ../proto + replace l12.xyz/dal/filters v0.0.0 => ../filters require ( github.com/mattn/go-sqlite3 v1.14.22 github.com/pkg/errors v0.9.1 // indirect - l12.xyz/dal/utils v0.0.0 // indirect l12.xyz/dal/filters v0.0.0 // indirect + l12.xyz/dal/utils v0.0.0 // indirect ) diff --git a/pkg/__test__/go.sum b/pkg/__test__/go.sum index acfeee2..5cf32ca 100644 --- a/pkg/__test__/go.sum +++ b/pkg/__test__/go.sum @@ -1,4 +1,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 h1:jYi87L8j62qkXzaYHAQAhEapgukhenIMZRBKTNRLHJ4= +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/tinylib/msgp v1.2.0 h1:0uKB/662twsVBpYUPbokj4sTSKhWFKB7LopO2kWK8lY= +github.com/tinylib/msgp v1.2.0/go.mod h1:2vIGs3lcUo8izAATNobrCHevYZC/LMsJtw4JPiYPHro= diff --git a/pkg/__test__/proto_test.go b/pkg/__test__/proto_test.go new file mode 100644 index 0000000..ea558f1 --- /dev/null +++ b/pkg/__test__/proto_test.go @@ -0,0 +1,32 @@ +package tests + +import ( + "os" + "testing" + + _ "github.com/mattn/go-sqlite3" + "l12.xyz/dal/adapter" + "l12.xyz/dal/proto" +) + +func TestProtoMessagePack(t *testing.T) { + message, err := os.ReadFile("proto_test.msgpack") + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + req := proto.Request{} + req.UnmarshalMsg(message) + query, err := req.Parse(adapter.SQLite{}) + if err != nil { + t.Fatalf("failed to parse query: %v", err) + } + db := "database.sqlite" + if query.Db != db { + t.Fatalf("expected db %s, got %s", db, query.Db) + } + expr := "SELECT * FROM data WHERE a = ? AND b > ?" + if query.Expression != expr { + t.Fatalf("expected expression %s, got %s", expr, query.Expression) + } + //fmt.Println(q) +} diff --git a/pkg/__test__/proto_test.msgpack b/pkg/__test__/proto_test.msgpack new file mode 100644 index 0000000..322ecf4 --- /dev/null +++ b/pkg/__test__/proto_test.msgpack @@ -0,0 +1 @@ +‚¢db¯database.sqlite¨commands’‚¦method¢In¤args‘¤data‚¦method¤Find¤args‘‚¡a¡b£$gt \ No newline at end of file diff --git a/pkg/__test__/proto_test.ts b/pkg/__test__/proto_test.ts new file mode 100644 index 0000000..737ce10 --- /dev/null +++ b/pkg/__test__/proto_test.ts @@ -0,0 +1,20 @@ +import { encode } from "https://deno.land/x/msgpack@v1.2/mod.ts"; + +const Query = { + "db": "database.sqlite", + "commands": [ + {"method": "In", "args": ["data"]}, + { + "method": "Find", + "args": [{ + "a": 1, + "b": { + "$gt": 2, + }, + }] + }, + ], +}; + +const encoded: Uint8Array = encode(Query); +Deno.writeFileSync("proto_test.msgpack", encoded); \ No newline at end of file diff --git a/pkg/filters/utils.go b/pkg/filters/utils.go index cdb6c93..8a32551 100644 --- a/pkg/filters/utils.go +++ b/pkg/filters/utils.go @@ -16,6 +16,9 @@ func FromJson[T IFilter](data interface{}) *T { } } m, ok := data.(Filter) + if !ok { + m, ok = data.(map[string]interface{}) + } if ok { s, err := json.Marshal(m) if err != nil { diff --git a/pkg/proto/go.mod b/pkg/proto/go.mod new file mode 100644 index 0000000..fb6793d --- /dev/null +++ b/pkg/proto/go.mod @@ -0,0 +1,24 @@ +module l12.xyz/dal/proto + +go 1.22.6 + +require l12.xyz/dal/builder v0.0.0 + +replace l12.xyz/dal/builder v0.0.0 => ../builder + +require github.com/tinylib/msgp v1.2.0 + +require github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect + +replace l12.xyz/dal/utils v0.0.0 => ../utils + +replace l12.xyz/dal/adapter v0.0.0 => ../adapter + +replace l12.xyz/dal/filters v0.0.0 => ../filters + +require ( + github.com/pkg/errors v0.9.1 // indirect + l12.xyz/dal/adapter v0.0.0 // indirect + l12.xyz/dal/filters v0.0.0 // indirect + l12.xyz/dal/utils v0.0.0 // indirect +) diff --git a/pkg/proto/go.sum b/pkg/proto/go.sum new file mode 100644 index 0000000..0faa69d --- /dev/null +++ b/pkg/proto/go.sum @@ -0,0 +1,6 @@ +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 h1:jYi87L8j62qkXzaYHAQAhEapgukhenIMZRBKTNRLHJ4= +github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/tinylib/msgp v1.2.0 h1:0uKB/662twsVBpYUPbokj4sTSKhWFKB7LopO2kWK8lY= +github.com/tinylib/msgp v1.2.0/go.mod h1:2vIGs3lcUo8izAATNobrCHevYZC/LMsJtw4JPiYPHro= diff --git a/pkg/proto/request.go b/pkg/proto/request.go new file mode 100644 index 0000000..07d1b81 --- /dev/null +++ b/pkg/proto/request.go @@ -0,0 +1,42 @@ +package proto + +import ( + "fmt" + "reflect" + + "l12.xyz/dal/adapter" + "l12.xyz/dal/builder" +) + +//go:generate msgp + +type BuildCmd struct { + Method string `msg:"method"` + Args []interface{} `msg:"args"` +} + +type Request struct { + Db string `msg:"db"` + Commands []BuildCmd `msg:"commands"` +} + +func (q *Request) Parse(dialect adapter.Dialect) (adapter.Query, error) { + b := builder.New(dialect) + for _, cmd := range q.Commands { + method := reflect.ValueOf(b).MethodByName(cmd.Method) + if !method.IsValid() { + return adapter.Query{}, fmt.Errorf("method %s not found", cmd.Method) + } + args := make([]reflect.Value, len(cmd.Args)) + for i, arg := range cmd.Args { + args[i] = reflect.ValueOf(arg) + } + method.Call(args) + } + expr, data := b.Sql() + return adapter.Query{ + Db: q.Db, + Expression: expr, + Data: data, + }, nil +} diff --git a/pkg/proto/request_gen.go b/pkg/proto/request_gen.go new file mode 100644 index 0000000..e4bec82 --- /dev/null +++ b/pkg/proto/request_gen.go @@ -0,0 +1,468 @@ +package proto + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *BuildCmd) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "method": + z.Method, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Method") + return + } + case "args": + var zb0002 uint32 + zb0002, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err, "Args") + return + } + if cap(z.Args) >= int(zb0002) { + z.Args = (z.Args)[:zb0002] + } else { + z.Args = make([]interface{}, zb0002) + } + for za0001 := range z.Args { + z.Args[za0001], err = dc.ReadIntf() + if err != nil { + err = msgp.WrapError(err, "Args", za0001) + return + } + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *BuildCmd) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 2 + // write "method" + err = en.Append(0x82, 0xa6, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64) + if err != nil { + return + } + err = en.WriteString(z.Method) + if err != nil { + err = msgp.WrapError(err, "Method") + return + } + // write "args" + err = en.Append(0xa4, 0x61, 0x72, 0x67, 0x73) + if err != nil { + return + } + err = en.WriteArrayHeader(uint32(len(z.Args))) + if err != nil { + err = msgp.WrapError(err, "Args") + return + } + for za0001 := range z.Args { + err = en.WriteIntf(z.Args[za0001]) + if err != nil { + err = msgp.WrapError(err, "Args", za0001) + return + } + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *BuildCmd) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 2 + // string "method" + o = append(o, 0x82, 0xa6, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64) + o = msgp.AppendString(o, z.Method) + // string "args" + o = append(o, 0xa4, 0x61, 0x72, 0x67, 0x73) + o = msgp.AppendArrayHeader(o, uint32(len(z.Args))) + for za0001 := range z.Args { + o, err = msgp.AppendIntf(o, z.Args[za0001]) + if err != nil { + err = msgp.WrapError(err, "Args", za0001) + return + } + } + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *BuildCmd) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "method": + z.Method, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Method") + return + } + case "args": + var zb0002 uint32 + zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Args") + return + } + if cap(z.Args) >= int(zb0002) { + z.Args = (z.Args)[:zb0002] + } else { + z.Args = make([]interface{}, zb0002) + } + for za0001 := range z.Args { + z.Args[za0001], bts, err = msgp.ReadIntfBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Args", za0001) + return + } + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *BuildCmd) Msgsize() (s int) { + s = 1 + 7 + msgp.StringPrefixSize + len(z.Method) + 5 + msgp.ArrayHeaderSize + for za0001 := range z.Args { + s += msgp.GuessSize(z.Args[za0001]) + } + return +} + +// DecodeMsg implements msgp.Decodable +func (z *Request) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "db": + z.Db, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Db") + return + } + case "commands": + var zb0002 uint32 + zb0002, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err, "Commands") + return + } + if cap(z.Commands) >= int(zb0002) { + z.Commands = (z.Commands)[:zb0002] + } else { + z.Commands = make([]BuildCmd, zb0002) + } + for za0001 := range z.Commands { + var zb0003 uint32 + zb0003, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + for zb0003 > 0 { + zb0003-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + switch msgp.UnsafeString(field) { + case "method": + z.Commands[za0001].Method, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Method") + return + } + case "args": + var zb0004 uint32 + zb0004, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args") + return + } + if cap(z.Commands[za0001].Args) >= int(zb0004) { + z.Commands[za0001].Args = (z.Commands[za0001].Args)[:zb0004] + } else { + z.Commands[za0001].Args = make([]interface{}, zb0004) + } + for za0002 := range z.Commands[za0001].Args { + z.Commands[za0001].Args[za0002], err = dc.ReadIntf() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args", za0002) + return + } + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + } + } + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *Request) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 2 + // write "db" + err = en.Append(0x82, 0xa2, 0x64, 0x62) + if err != nil { + return + } + err = en.WriteString(z.Db) + if err != nil { + err = msgp.WrapError(err, "Db") + return + } + // write "commands" + err = en.Append(0xa8, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73) + if err != nil { + return + } + err = en.WriteArrayHeader(uint32(len(z.Commands))) + if err != nil { + err = msgp.WrapError(err, "Commands") + return + } + for za0001 := range z.Commands { + // map header, size 2 + // write "method" + err = en.Append(0x82, 0xa6, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64) + if err != nil { + return + } + err = en.WriteString(z.Commands[za0001].Method) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Method") + return + } + // write "args" + err = en.Append(0xa4, 0x61, 0x72, 0x67, 0x73) + if err != nil { + return + } + err = en.WriteArrayHeader(uint32(len(z.Commands[za0001].Args))) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args") + return + } + for za0002 := range z.Commands[za0001].Args { + err = en.WriteIntf(z.Commands[za0001].Args[za0002]) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args", za0002) + return + } + } + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *Request) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 2 + // string "db" + o = append(o, 0x82, 0xa2, 0x64, 0x62) + o = msgp.AppendString(o, z.Db) + // string "commands" + o = append(o, 0xa8, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73) + o = msgp.AppendArrayHeader(o, uint32(len(z.Commands))) + for za0001 := range z.Commands { + // map header, size 2 + // string "method" + o = append(o, 0x82, 0xa6, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64) + o = msgp.AppendString(o, z.Commands[za0001].Method) + // string "args" + o = append(o, 0xa4, 0x61, 0x72, 0x67, 0x73) + o = msgp.AppendArrayHeader(o, uint32(len(z.Commands[za0001].Args))) + for za0002 := range z.Commands[za0001].Args { + o, err = msgp.AppendIntf(o, z.Commands[za0001].Args[za0002]) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args", za0002) + return + } + } + } + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *Request) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "db": + z.Db, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Db") + return + } + case "commands": + var zb0002 uint32 + zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Commands") + return + } + if cap(z.Commands) >= int(zb0002) { + z.Commands = (z.Commands)[:zb0002] + } else { + z.Commands = make([]BuildCmd, zb0002) + } + for za0001 := range z.Commands { + var zb0003 uint32 + zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + for zb0003 > 0 { + zb0003-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + switch msgp.UnsafeString(field) { + case "method": + z.Commands[za0001].Method, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Method") + return + } + case "args": + var zb0004 uint32 + zb0004, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args") + return + } + if cap(z.Commands[za0001].Args) >= int(zb0004) { + z.Commands[za0001].Args = (z.Commands[za0001].Args)[:zb0004] + } else { + z.Commands[za0001].Args = make([]interface{}, zb0004) + } + for za0002 := range z.Commands[za0001].Args { + z.Commands[za0001].Args[za0002], bts, err = msgp.ReadIntfBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001, "Args", za0002) + return + } + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err, "Commands", za0001) + return + } + } + } + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *Request) Msgsize() (s int) { + s = 1 + 3 + msgp.StringPrefixSize + len(z.Db) + 9 + msgp.ArrayHeaderSize + for za0001 := range z.Commands { + s += 1 + 7 + msgp.StringPrefixSize + len(z.Commands[za0001].Method) + 5 + msgp.ArrayHeaderSize + for za0002 := range z.Commands[za0001].Args { + s += msgp.GuessSize(z.Commands[za0001].Args[za0002]) + } + } + return +} diff --git a/pkg/proto/request_gen_test.go b/pkg/proto/request_gen_test.go new file mode 100644 index 0000000..f3074c0 --- /dev/null +++ b/pkg/proto/request_gen_test.go @@ -0,0 +1,236 @@ +package proto + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "bytes" + "testing" + + "github.com/tinylib/msgp/msgp" +) + +func TestMarshalUnmarshalBuildCmd(t *testing.T) { + v := BuildCmd{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgBuildCmd(b *testing.B) { + v := BuildCmd{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgBuildCmd(b *testing.B) { + v := BuildCmd{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalBuildCmd(b *testing.B) { + v := BuildCmd{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodeBuildCmd(t *testing.T) { + v := BuildCmd{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Log("WARNING: TestEncodeDecodeBuildCmd Msgsize() is inaccurate") + } + + vn := BuildCmd{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodeBuildCmd(b *testing.B) { + v := BuildCmd{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodeBuildCmd(b *testing.B) { + v := BuildCmd{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +} + +func TestMarshalUnmarshalRequest(t *testing.T) { + v := Request{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgRequest(b *testing.B) { + v := Request{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgRequest(b *testing.B) { + v := Request{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalRequest(b *testing.B) { + v := Request{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodeRequest(t *testing.T) { + v := Request{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Log("WARNING: TestEncodeDecodeRequest Msgsize() is inaccurate") + } + + vn := Request{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodeRequest(b *testing.B) { + v := Request{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodeRequest(b *testing.B) { + v := Request{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +}