You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.6 KiB

  1. # `tendermint/binary`
  2. The `binary` submodule encodes primary types and structs into bytes.
  3. ## Primary types
  4. uint\*, int\*, string, time, byteslice and byteslice-slice types can be
  5. encoded and decoded with the following methods:
  6. The following writes `o uint64` to `w io.Writer`, and increments `n` and/or sets `err`
  7. ```go
  8. WriteUint64(o uint64, w io.Writer, n *int64, err *error)
  9. // Typical usage:
  10. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  11. WriteUint64(uint64(x), buf, n, err)
  12. if *err != nil {
  13. panic(err)
  14. }
  15. ```
  16. The following reads a `uint64` from `r io.Reader`, and increments `n` and/or sets `err`
  17. ```go
  18. var o = ReadUint64(r io.Reader, n *int64, err *error)
  19. ```
  20. Similar methods for `uint32`, `uint16`, `uint8`, `int64`, `int32`, `int16`, `int8` exist.
  21. Protobuf variable length encoding is done with `uint` and `int` types:
  22. ```go
  23. WriteUvarint(o uint, w io.Writer, n *int64, err *error)
  24. var o = ReadUvarint(r io.Reader, n *int64, err *error)
  25. ```
  26. Byteslices can be written with:
  27. ```go
  28. WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error)
  29. ```
  30. Byteslices (and all slices such as byteslice-slices) are prepended with
  31. `uvarint` encoded length, so `ReadByteSlice()` knows how many bytes to read.
  32. Note that there is no type information encoded -- the caller is assumed to know what types
  33. to decode.
  34. ## Struct Types
  35. Struct types can be automatically encoded with reflection. Unlike json-encoding, no field
  36. name or type information is encoded. Field values are simply encoded in order.
  37. ```go
  38. type Foo struct {
  39. MyString string
  40. MyUint32 uint32
  41. myPrivateBytes []byte
  42. }
  43. foo := Foo{"my string", math.MaxUint32, []byte("my private bytes")}
  44. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  45. WriteBinary(foo, buf, n, err)
  46. // fmt.Printf("%X", buf.Bytes()) gives:
  47. // 096D7920737472696E67FFFFFFFF
  48. // 09: uvarint encoded length of string "my string"
  49. // 6D7920737472696E67: bytes of string "my string"
  50. // FFFFFFFF: bytes for MaxUint32
  51. // Note that the unexported "myPrivateBytes" isn't encoded.
  52. foo2 := ReadBinary(Foo{}, buf, n, err).(Foo)
  53. // Or, to decode onto a pointer:
  54. foo2 := ReadBinary(&Foo{}, buf, n, err).(*Foo)
  55. ```
  56. WriteBinary and ReadBinary can encode/decode structs recursively. However, interface field
  57. values are a bit more complicated.
  58. ```go
  59. type Greeter interface {
  60. Greet() string
  61. }
  62. type Dog struct{}
  63. func (d Dog) Greet() string { return "Woof!" }
  64. type Cat struct{}
  65. func (c Cat) Greet() string { return "Meow!" }
  66. type Foo struct {
  67. Greeter
  68. }
  69. foo := Foo{Dog{}}
  70. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  71. WriteBinary(foo, buf, n, err)
  72. // This errors because we don't know whether to read a Dog or Cat.
  73. foo2 := ReadBinary(Foo{}, buf, n, err)
  74. ```
  75. In the above example, `ReadBinary()` fails because the `Greeter` field for `Foo{}`
  76. is ambiguous -- it could be either a `Dog{}` or a `Cat{}`, like a union structure.
  77. The solution is to declare the concrete implementation types for interfaces:
  78. ```go
  79. type Dog struct{}
  80. func (d Dog) TypeByte() byte { return GreeterTypeDog }
  81. func (d Dog) Greet() string { return "Woof!" }
  82. type Cat struct{}
  83. func (c Cat) TypeByte() byte { return GreeterTypeCat }
  84. func (c Cat) Greet() string { return "Meow!" }
  85. var _ = RegisterInterface(
  86. struct{Greeter}{},
  87. ConcreteType{Dog{}},
  88. ConcreteType{Cat{}},
  89. })
  90. ```
  91. NOTE: The TypeByte() is written and expected to be read even when the struct
  92. is encoded or decoded directly:
  93. ```go
  94. WriteBinary(Dog{}, buf, n, err) // Writes GreeterTypeDog byte
  95. dog_ := ReadBinary(Dog{}, buf, n, err) // Expects to read GreeterTypeDog byte
  96. dog := dog_.(Dog) // ok if *err != nil, otherwise dog_ == nil.
  97. ```