3[](https://github.com/xc-jp/purescript-protobuf/actions)
4[](http://pursuit.purescript.org/packages/purescript-protobuf/)
6Purescript library and code generator for
7[Google Protocol Buffers version 3](https://developers.google.com/protocol-buffers/docs/proto3).
9This library operates on
10[`ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer), so it will run both
11[in *Node.js*](https://pursuit.purescript.org/packages/purescript-node-buffer/docs/Node.Buffer.Class)
12and in browser environments.
16The `shell.nix` environment provides
18* The Purescript toolchain
19* The [`protoc`](https://github.com/protocolbuffers/protobuf/blob/master/src/README.md) compiler
20* The `protoc-gen-purescript` executable plugin for `protoc` on the `PATH` so that
21 [`protoc` can find it](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.compiler.plugin).
26Purescript Protobuf development environment.
27To build purescript-protobuf, run:
32To test purescript-protobuf, run:
34 protoc --purescript_out=./test/generated test/*.proto
35 spago -x test.dhall build
36 spago -x test.dhall test
38To generate Purescript .purs files from .proto files, run:
40 protoc --purescript_out=path_to_output file.proto
45## Writing programs with the generated code
47*None of the modules in this package should be imported directly in our program.*
49Rather, we'll import the message modules from the generated `.purs` files,
50as well as modules for reading and writing `ArrayBuffer`s.
52For example, a message in a `.proto` file declared as
60will export these four names in the generated `.purs` modules.
621. A message record type
64 type MyMessageR = { my_field :: Maybe Int }
68 newtype MyMessage = MyMessage MyMessageR
703. A message encoder which works with
71 [__purescript-arraybuffer-builder__](http://pursuit.purescript.org/packages/purescript-arraybuffer-builder/)
73 putMyMessage :: forall m. MonadEffect m => MyMessage -> PutM m Unit
754. A message decoder which works with
76 [__purescript-parsing-dataview__](http://pursuit.purescript.org/packages/purescript-parsing-dataview/)
78 parseMyMessage :: forall m. MonadEffect m => Int -> ParserT DataView m MyMessage
80 The message decoder needs an argument which tells it the
81 length of the message which it’s about to decode, because
82 [“the Protocol Buffer wire format is not self-delimiting.”](https://developers.google.com/protocol-buffers/docs/techniques#streaming)
84Then, in our program, our imports will look something like this.
88import Generated.Module (MyMessage(..), putMyMessage, parseMyMessage)
89import Text.Parsing.Parser (runParserT)
90import Data.ArrayBuffer.Builder (execPutM)
93The generated code modules will import modules from this
96The generated code depends on packages
101 , "arraybuffer-types"
102 , "arraybuffer-builder"
111[__package-sets__](https://github.com/purescript/package-sets),
113[__purescript-longs__](https://pursuit.purescript.org/packages/purescript-longs)
114(see `spago.dhall` in this package for the particulars).
116It also depends on the Javascript package
117[__long__](https://www.npmjs.com/package/long).
119### Generated message instances
121We cannot easily derive common instances like `Eq` for the
122generated message types because
1231. The types [might be recursive](https://github.com/purescript/documentation/blob/master/errors/CycleInDeclaration.md).
1242. The types might contain fields of type
125 [`ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer),
126 which doesn't have those instances.
128All of the generated message types have an instance of
129[`Generic`](https://pursuit.purescript.org/packages/purescript-generics-rep/docs/Data.Generic.Rep#t:Generic).
130This allows us to sometimes use
131[`genericEq`](https://pursuit.purescript.org/packages/purescript-generics-rep/docs/Data.Generic.Rep.Eq#v:genericEq)
133[`genericShow`](https://pursuit.purescript.org/packages/purescript-generics-rep/docs/Data.Generic.Rep.Show#v:genericShow)
134on a generated message, if the generated message has those instances for
137All of the generated message types have an instance of
138[`NewType`](https://pursuit.purescript.org/packages/purescript-newtype/docs/Data.Newtype#t:Newtype).
142The __purescript-protobuf__ repository contains three executable *Node.js*
143programs which use code generated by __purescript-protobuf__. Refer to these
144for further examples of how to use the generated code.
147 [compiler plugin](https://github.com/xc-jp/purescript-protobuf/blob/master/src/ProtocPlugin/Main.purs).
148 The code generator imports generated code. Trippy, right? This program
149 literally writes itself.
151 [unit test suite](https://github.com/xc-jp/purescript-protobuf/blob/master/test/Main.purs)
153 [conformance test program](https://github.com/xc-jp/purescript-protobuf/blob/master/conformance/Main.purs)
155### Interpreting invalid encoding parse failures
157When the decode parser encounters an invalid encoding in the protobuf input
158stream then it will fail to parse.
161[`Text.Parsing.Parser.ParserT`](https://pursuit.purescript.org/packages/purescript-parsing/docs/Text.Parsing.Parser#t:ParserT)
162fails it will return a `ParseError String (Position {line::Int,column::Int})`.
164The byte offset at which the parse failure occured is given by the
167The path to the protobuf definition which failed to parse will be included
168in the `ParseError String` and delimited by `'/'`, something
169like `"Message1 / string_field_1 / Invalid UTF8 encoding."`.
173We aim to support binary-encoded (not JSON-encoded)
174[__proto3__](https://developers.google.com/protocol-buffers/docs/proto3).
175Many __proto2__-syntax descriptor files will
176also work, as long as they don't use __proto2__ features.
179[extensions](https://developers.google.com/protocol-buffers/docs/proto?hl=en#extensions).
181The generated optional record fields will use `Nothing` instead of the
182[default values](https://developers.google.com/protocol-buffers/docs/proto3?hl=en#default).
185[unknown fields](https://developers.google.com/protocol-buffers/docs/proto3?hl=en#unknowns).
188[services](https://developers.google.com/protocol-buffers/docs/proto3?hl=en#services).
192At the time of this writing, we pass 193 out of 194 of the
193[Google conformance tests](https://github.com/protocolbuffers/protobuf/tree/master/conformance)
194for binary-encoded proto3.
195The one test we fail is
196the *Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput* test, which
197is the test for preserving unknown fields, which we do not support, see above.
199See the `conformance/README.md` in this repository for details.
203The code generator will use the `package` statement in the `.proto` file
204and the base file name as the Purescript module name for that file.
207[`import`](https://developers.google.com/protocol-buffers/docs/proto3#importing_definitions)
208statement allows Protobuf messages to have fields
209consisting of Protobuf messages imported from another file, and qualified
210by the package name in that file. In order to generate
211the correct Purescript module name qualifier on the types of imported message
212fields, the code generator must be able to lookup the package name
213statement in the imported file.
215For that reason, we can only use top-level
216(not [nested](https://developers.google.com/protocol-buffers/docs/proto3#nested))
217`message` and `enum` types from an `import`.
219The generated Purescript code will usually have module imports which cause
220the `purs` compiler to emit warnings. Sorry.
224The implementation is simple and straightforward. We haven't done
225any special optimizations. For example, when encoding a protobuf varint, we
226allocate a list of new one-byte `ArrayBuffers`s and then copy them all into
227position in the final `ArrayBuffer`. For another example, when decoding a
228packed field of numbers, we build a list of the numbers, and then copy them
229all into the final `Array`. Also, this whole library is very stack-unsafe.
230This may all be improved in later versions.
234Pull requests welcome.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list