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