Code-generation based encoder for Skycoin
skyencoder
generates a file with encode and decode methods for an encodable struct, using the Skycoin binary encoding format.
For encodable non-struct types, you can wrap the non-struct type in a struct for the same result. A struct definition adds no overhead and does not change the encoding.
Skycoin's package encoder
has a reflect-based encoder that can be used at runtime,
and supports any encodable type.
go get github.com/skycoin/skyencoder/cmd/skyencoder
This installs skyencoder
to $GOPATH/bin
. Make sure $GOPATH/bin
is in
your shell environment's $PATH
variable in order to invoke it in the shell.
To use go generate
to generate the code, add a directive like this in the file where the struct is defined:
// go:generate skyencoder -struct Foo
Then, use go:generate
to generate it:
go generate github.com/foo/foo
» go run cmd/skyencoder/skyencoder.go --help
Usage of skyencoder:
skyencoder [flags] -struct T [go import path e.g. github.com/skycoin/skycoin/src/coin]
skyencoder [flags] -struct T files... # Must be a single package
Flags:
-no-test
disable generating the _test.go file (test files require github.com/google/go-cmp/cmp and github.com/skycoin/encodertest)
-output-file string
output file name; default <struct_name>_skyencoder.go
-output-path string
output path; defaults to the package's path, or the file's containing folder
-package string
package name for the output; if not provided, defaults to the struct's package
-silent
disable all non-error log output
-struct string
struct name, must be set
-tags string
comma-separated list of build tags to apply
-unexported
don't export generated methods (always true if the struct is not an exported type)
skyencoder
generates a file with encode and decode methods for a struct, using the Skycoin encoding format.
By default, the generated file is written to the same package as the source struct type.
If you wish to have the file written to a different location, use -package
to control the name of the destination package,
-output-path
to control the destination path, and -output-file
to control the destination filename.
Build tags can be applied to the loaded package with -tags
.
Generate code for struct coin.SignedBlock
in github.com/skycoin/skycoin/src/coin
:
go run cmd/skyencoder/skyencoder.go -struct SignedBlock github.com/skycoin/skycoin/src/coin
Generate code for struct Foo
in /tmp/foo/foo.go
:
go run cmd/skyencoder/skyencoder.go -struct Foo /tmp/foo/foo.go
Note: absolute paths can only point to a Go file. If there are multiple Go files in that same path, all of them must be included.
Generate code for struct coin.SignedBlock
in github.com/skycoin/skycoin/src/coin
, but sent to an external package:
go run cmd/skyencoder/skyencoder.go -struct SignedBlock -package foo -output-path /tmp/foo github.com/skycoin/skycoin/src/coin
Note: do not use -package
if the generated file is going to be in the same package as the struct
skyencoder
only generates code for struct types, but the reflect-based skycoin encoder
package can handle any encodable type as an argument.
Since structs add no overhead, you can wrap your non-struct type in a struct to generate an encoder for it with skyencoder
.
For example, to generate an encoder for []int64
, wrap it:
import (
"bytes"
"github.com/skycoin/skycoin/src/cipher/encoder"
)
//go:generate skyencoder -struct int64SliceWrapper
type int64SliceWrapper struct {
Int64Slice []int64
}
func assertEncoderEqualsSkyencoder(x []int64) {
buf, err := encoder.Serialize(x)
if err != nil {
return panic(err)
}
buf2, err := encodeInt64SliceWrapper(int64SliceWrapper{
Int64Slice: x,
})
if err != nil {
panic(err)
}
if !bytes.Equal(buf, buf2) {
panic("encoder.Serialize does not match encodeInt64SliceWrapper")
}
}
A file with tests is generated by default and can be disabled with -no-test
.
This test file requires github.com/google/go-cmp/cmp
and github.com/google/go-cmp/cmp/cmpopts
.
Autogenerated tests will check that encoding and decoding succeeds and that the output matches the reflect-based github.com/skycoin/skycoin/src/cipher/encoder
.
Notes:
- Autogenerated tests do not cover maxlen exceeded errors
Benchmarks compare the reflect-based github.com/skycoin/skycoin/src/cipher/encoder
to the generated encoder.
Benchmarks performed on a Mid-2015 base model 15" Macbook Pro.
Comparison of skyencoder
to other encoders is available at:
- https://github.com/gz-c/skycoin-serialization-benchmarks
- https://github.com/gz-c/gosercomp
» make bench
go test -benchmem -bench '.*' ./benchmark
goos: darwin
goarch: amd64
pkg: github.com/skycoin/skyencoder/benchmark
BenchmarkEncodeSize-8 200000000 6.33 ns/op 0 B/op 0 allocs/op
BenchmarkCipherEncodeSize-8 1000000 1488 ns/op 128 B/op 16 allocs/op
BenchmarkEncodeToBuffer-8 10000000 133 ns/op 0 B/op 0 allocs/op
BenchmarkEncode-8 10000000 189 ns/op 112 B/op 1 allocs/op
BenchmarkCipherEncode-8 500000 3103 ns/op 400 B/op 34 allocs/op
BenchmarkDecode-8 5000000 375 ns/op 120 B/op 10 allocs/op
BenchmarkCipherDecode-8 500000 2425 ns/op 472 B/op 29 allocs/op
BenchmarkEncodeSizeSignedBlock-8 50000000 25.0 ns/op 0 B/op 0 allocs/op
BenchmarkCipherEncodeSizeSignedBlock-8 200000 8125 ns/op 600 B/op 75 allocs/op
BenchmarkEncodeSignedBlockToBuffer-8 3000000 418 ns/op 0 B/op 0 allocs/op
BenchmarkEncodeSignedBlock-8 2000000 721 ns/op 1792 B/op 1 allocs/op
BenchmarkCipherEncodeSignedBlock-8 100000 19673 ns/op 4080 B/op 185 allocs/op
BenchmarkDecodeSignedBlock-8 1000000 1002 ns/op 1648 B/op 10 allocs/op
BenchmarkCipherDecodeSignedBlock-8 100000 13919 ns/op 5448 B/op 130 allocs/op
PASS
ok github.com/skycoin/skyencoder/benchmark 24.198s