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.

138 lines
3.9 KiB

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