[822] | 1 | # go-bare [](https://godocs.io/git.sr.ht/~sircmpwn/go-bare) [](https://builds.sr.ht/~sircmpwn/go-bare?)
|
---|
| 2 |
|
---|
| 3 | An implementation of the [BARE](https://baremessages.org) message format
|
---|
| 4 | for Go.
|
---|
| 5 |
|
---|
| 6 | **Status**
|
---|
| 7 |
|
---|
| 8 | This mostly works, but you may run into some edge cases with union types.
|
---|
| 9 |
|
---|
| 10 | ## Code generation
|
---|
| 11 |
|
---|
| 12 | An example is provided in the `examples` directory. Here is a basic
|
---|
| 13 | introduction:
|
---|
| 14 |
|
---|
| 15 | ```
|
---|
| 16 | $ cat schema.bare
|
---|
| 17 | type Address {
|
---|
| 18 | address: [4]string
|
---|
| 19 | city: string
|
---|
| 20 | state: string
|
---|
| 21 | country: string
|
---|
| 22 | }
|
---|
| 23 | $ go run git.sr.ht/~sircmpwn/go-bare/cmd/gen -p models schema.bare models/gen.go
|
---|
| 24 | ```
|
---|
| 25 |
|
---|
| 26 | Then you can write something like the following:
|
---|
| 27 |
|
---|
| 28 | ```go
|
---|
| 29 | import "models"
|
---|
| 30 |
|
---|
| 31 | /* ... */
|
---|
| 32 |
|
---|
| 33 | bytes := []byte{ /* ... */ }
|
---|
| 34 | var addr Address
|
---|
| 35 | err := addr.Decode(bytes)
|
---|
| 36 | ```
|
---|
| 37 |
|
---|
| 38 | You can also add custom types and skip generating them by passing the `-s
|
---|
| 39 | TypeName` flag to gen, then providing your own implementation. For example, to
|
---|
| 40 | rig up time.Time with a custom "Time" BARE type, add this to your BARE schema:
|
---|
| 41 |
|
---|
| 42 | ```
|
---|
| 43 | type Time string
|
---|
| 44 | ```
|
---|
| 45 |
|
---|
| 46 | Then pass `-s Time` to gen, and provide your own implementation of Time in the
|
---|
| 47 | same package. See `examples/time.go` for an example of such an implementation.
|
---|
| 48 |
|
---|
| 49 | ## Marshal usage
|
---|
| 50 |
|
---|
| 51 | For many use-cases, it may be more convenient to write your types manually and
|
---|
| 52 | use Marshal and Unmarshal directly. If you choose this approach, you may also
|
---|
| 53 | use `git.sr.ht/~sircmpwn/go-bare/schema.SchemaFor` to generate a BARE schema
|
---|
| 54 | language document describing your structs.
|
---|
| 55 |
|
---|
| 56 | ```go
|
---|
| 57 | package main
|
---|
| 58 |
|
---|
| 59 | import (
|
---|
| 60 | "fmt"
|
---|
| 61 | "git.sr.ht/~sircmpwn/go-bare"
|
---|
| 62 | )
|
---|
| 63 |
|
---|
| 64 | // type Coordinates {
|
---|
| 65 | // x: int
|
---|
| 66 | // y: int
|
---|
| 67 | // z: int
|
---|
| 68 | // q: optional<int>
|
---|
| 69 | // }
|
---|
| 70 | type Coordinates struct {
|
---|
| 71 | X uint
|
---|
| 72 | Y uint
|
---|
| 73 | Z uint
|
---|
| 74 | Q *uint
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | func main() {
|
---|
| 78 | var coords Coordinates
|
---|
| 79 | payload := []byte{0x01, 0x02, 0x03, 0x01, 0x04}
|
---|
| 80 | err := bare.Unmarshal(payload, &coords)
|
---|
| 81 | if err != nil {
|
---|
| 82 | panic(err)
|
---|
| 83 | }
|
---|
| 84 | fmt.Printf("coords: %d, %d, %d (%d)\n",
|
---|
| 85 | coords.X, coords.Y, coords.Z, *coords.Q) /* coords: 1, 2, 3 (4) */
|
---|
| 86 | }
|
---|
| 87 | ```
|
---|
| 88 |
|
---|
| 89 | ### Unions
|
---|
| 90 |
|
---|
| 91 | To use union types, you need to define an interface to represent the union of
|
---|
| 92 | possible values, and this interface needs to implement `bare.Union`:
|
---|
| 93 |
|
---|
| 94 | ```go
|
---|
| 95 | type Person interface {
|
---|
| 96 | Union
|
---|
| 97 | }
|
---|
| 98 | ```
|
---|
| 99 |
|
---|
| 100 | Then, for each possible union type, implement the interface:
|
---|
| 101 |
|
---|
| 102 | ```go
|
---|
| 103 | type Employee struct { /* ... */ }
|
---|
| 104 | func (e Employee) IsUnion() {}
|
---|
| 105 |
|
---|
| 106 | type Customer struct { /* ... */ }
|
---|
| 107 | func (c Customer) IsUnion() {}
|
---|
| 108 | ```
|
---|
| 109 |
|
---|
| 110 | The IsUnion function is necessary to make the type compatible with the Union
|
---|
| 111 | interface. Then, to marshal and unmarshal using this union type, you need to
|
---|
| 112 | tell go-bare about your union:
|
---|
| 113 |
|
---|
| 114 | ```go
|
---|
| 115 | func init() {
|
---|
| 116 | // The first argument is a pointer of the union interface, and the
|
---|
| 117 | // subsequent arguments are values of each possible subtype, in ascending
|
---|
| 118 | // order of union tag:
|
---|
| 119 | bare.RegisterUnion((*Person)(nil)).
|
---|
| 120 | Member(*new(Employee), 0).
|
---|
| 121 | Member(*new(Customer), 1)
|
---|
| 122 | }
|
---|
| 123 | ```
|
---|
| 124 |
|
---|
| 125 | This is all done for you if you use code generation.
|
---|
| 126 |
|
---|
| 127 | ## Contributing, getting help
|
---|
| 128 |
|
---|
| 129 | Send patches and questions to
|
---|
| 130 | [~sircmpwn/public-inbox@lists.sr.ht](mailto:~sircmpwn/public-inbox@lists.sr.ht)
|
---|