Skip to content

Bazel rules to encode & decode protocol buffer messages in S-expression, json, text, and binary formats.

License

Notifications You must be signed in to change notification settings

rendezqueue/rules_sxproto

Repository files navigation

Sxproto Rules for Bazel

Do you want to write structured data in a Lisp-like syntax? Is your build system fast and correct? If so, you might like this project's Bazel rule named sxproto_data().

Sxproto (pronounced "ess ex proto") is an S-expression file format for protocol buffer messages. Our sxproto_data() Bazel rule compiles one of these .sxpb files into a binary protobuf (.binpb). See example/BUILD.bazel for how to use it with the next section's examples!

Format

As you might expect, the sxproto file format is pretty simple. You can basically be an expert after reading through a handful of examples.

Comments. In Lisp, comments are semicolons, so sxproto files do the same. In fact, we can put the following comment at the end of a sxproto file to tell Vim that it should have Lisp indentation.

; vim: ft=lisp lw=nil

Scalar fields. These are fields that contain a number or a string. Fields all have names, so the name should begin the S-expression and the value comes after it.

; An integer.
(i 5)
; A float.
(f 5.5)
; A string.
(s "hello")

Message fields. These are written the same as scalars. The field name comes first in the S-expression, and everything after it represents the fields of the message. Since each field of that message is an S-expression itself, there's no ambiguity.

; An message holding a single string.
(m (s "hello"))

; An empty message.
(m)

; A message holding the first 3 fields of the previous example.
(m (i 5) (f 5.5) (s "hello"))

Array fields. Rather than holding just one value of a certain type, a repeated field holds an array of such values. Conceptually, an array is a funny message with no field names, so we wrap the name of the "funny message" field with parentheses and use an empty S-expression () in place of each element's nonexistent field name. For simplicity, the "nonexistent field name" part is omitted for repeated scalars.

; An array of integers.
((my_integers) 1 2 3)

; An array of strings.
((my_strings) "yo" "howdy" "sup")

; An array of messages.
((my_messages)
 (() (i 5))
 (())
 (() (i 5) (f 5.5) (s "hello")))