File: README.md

package info (click to toggle)
golang-sourcehut-sircmpwn-go-bare 0.0~git20210406.ab86bc2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 268 kB
  • sloc: makefile: 5
file content (130 lines) | stat: -rw-r--r-- 3,225 bytes parent folder | download
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 [![godocs.io](https://godocs.io/git.sr.ht/~sircmpwn/go-bare?status.svg)](https://godocs.io/git.sr.ht/~sircmpwn/go-bare) [![builds.sr.ht status](https://builds.sr.ht/~sircmpwn/go-bare.svg)](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)