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.

168 lines
4.7 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 with "Unknown field type interface"
  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. In this case, the user must define a custom encoder/decoder as follows:
  78. ```go
  79. const (
  80. GreeterTypeDog = byte(0x01)
  81. GreeterTypeCat = byte(0x02)
  82. )
  83. func GreeterEncoder(o interface{}, w io.Writer, n *int64, err *error) {
  84. switch o.(type) {
  85. case Dog:
  86. WriteByte(GreeterTypeDog, w, n, err)
  87. WriteBinary(o, w, n, err)
  88. case Cat:
  89. WriteByte(GreeterTypeCat, w, n, err)
  90. WriteBinary(o, w, n, err)
  91. default:
  92. *err = errors.New(fmt.Sprintf("Unknown greeter type %v", o))
  93. }
  94. }
  95. func GreeterDecoder(r *bytes.Reader, n *int64, err *error) interface{} {
  96. // We must peek the type byte because ReadBinary() expects it.
  97. switch t := PeekByte(r, n, err); t {
  98. case GreeterTypeDog:
  99. return ReadBinary(Dog{}, r, n, err)
  100. case GreeterTypeCat:
  101. return ReadBinary(Cat{}, r, n, err)
  102. default:
  103. *err = errors.New(fmt.Sprintf("Unknown greeter type byte %X", t))
  104. return nil
  105. }
  106. }
  107. // This tells the reflection system to use the custom encoder/decoder functions
  108. // for encoding/decoding interface struct-field types.
  109. var _ = RegisterType(&TypeInfo{
  110. Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
  111. Encoder: GreeterEncoder,
  112. Decoder: GreeterDecoder,
  113. })
  114. ```
  115. Sometimes you want to always prefix a globally unique type byte while encoding,
  116. whether or not the declared type is an interface or concrete type.
  117. In this case, you can declare a "TypeByte() byte" function on the struct (as
  118. a value receiver, not a pointer receiver!), and you can skip the declaration of
  119. a custom decoder.
  120. ```go
  121. type Dog struct{}
  122. func (d Dog) TypeByte() byte { return GreeterTypeDog }
  123. func (d Dog) Greet() string { return "Woof!" }
  124. type Cat struct{}
  125. func (c Cat) TypeByte() byte { return GreeterTypeCat }
  126. func (c Cat) Greet() string { return "Meow!" }
  127. var _ = RegisterType(&TypeInfo{
  128. Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
  129. Decoder: GreeterDecoder,
  130. })
  131. ```