gobwire
Go's encoding/gob wire format for Rust: the byte streams
gob.Encoder and gob.Decoder exchange, and so the payloads of Go's net/rpc and HashiCorp
go-plugin's net/rpc protocol.
use ;
let bytes = new.encode.unwrap;
let mut decoder = new;
assert_eq!;
The bytes above are exactly the worked example in Go's encoding/gob documentation.
Matching Go
It is tested against Go's own encoding/gob in both directions: every stream in a corpus written
by Go must decode in Rust to what Go's decoder produced, and every value Rust re-encodes must
decode in Go to the same thing.
- Fields match by Go field name. Name them with
#[gob(name = "...")]. - Zero values are omitted exactly where Go omits them — and structs and arrays are not.
- Decoding merges into the destination, as Go does: absent fields keep their values, pointers and slices are reused, map entries are replaced.
- A value can span several messages (whenever an interface introduces a new type); the decoder handles it without leaving a destination half-written.
- Interfaces (
any,error) decode to a dynamic, re-encodableInterface, with no global type registry. time.TimeisGoTime, byte-compatible with Go's binary form.
Where it differs, and why
- A Rust map cannot be nil, so an empty map is sent as nil.
- A slice decoded into a
Vecmerges into existing elements only when theVecis at least as long as the incoming slice; Go looks at capacity. - Strings must be UTF-8.
- Nesting is limited (
MAX_DEPTH) rather than bounded only by the stack. - Go's decoder cannot skip an interface that defines a type inline, nor a nil interface inside
a skipped field.
gobwireskips both correctly, and its encoder always defines types before the value, so Go can skip anythinggobwiresends — except a nil interface, which no encoding can protect Go's skip from. - gob ignores
encoding.TextMarshalerwhatever its documentation says; so doesgobwire.
Licence
MIT or Apache-2.0, at your option.