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)
|
---|