ktakashi / r6rs-protobuf

Forked from code.google.com/p/r6rs-protobuf
GNU General Public License v3.0
2 stars 0 forks source link

Sat Dec 8 19:15:56 EDT 2012

r6rs-protobuf

This project is an R6RS Scheme implementation of Google's Protocol Buffers framework. It supports all of the features of the Protocol Buffer data language, except for the deprecated "group" feature. The following documentation explains how to use the components provided by this implementation; for more general information about protocol buffers, see the main protobuf project page at http://code.google.com/p/protobuf/.

Requirements

This library requires a Scheme platform capable of importing R6RS library forms. Additionally, SRFI-13 ("String Library") and SRFI-14 ("Character Set Library") are required.

SRFI-64 ("A Scheme API for test suites") is required to run the included unit tests.

Provided libraries

r6rs-protobuf provides two sets of functional components: Parsing and code generation, which produce R6RS Scheme libraries based on protobuf definitions; and runtime support for the generated code, to enable features like serialization and extension registration.

The code generation API is provided by the (protobuf compile)' library. The functions that make up the compiler API have the prefixprotoc:'.

The runtime support is provided by the (protobuf private)' library. The functions that make up the runtime support API have the prefixprotobuf:'. Note that it shouldn't ever be necessary to import this library directly; all the functionality necessary for interacting with your data structures should be exported by the generated libraries.

Code generation

In order to generate Scheme code from protobuf definitions, a .proto file (or other source of definitions) must first be parsed. The `protoc:read-proto' function takes one argument, an input port from which definitions can be read:

(protoc:read-proto (open-input-file "MyDataStructure.proto"))

The data source may specify multiple type definitions and packages. If import' directives are found, the paths they specify will be opened using open-input-file'.

After parsing is complete, type resolution for extensions and enum- and message-type fields is performed.

The resulting proto' record may be passed toprotoc:generate-libraries' to generate R6RS library forms for the packages defined in the proto. This function returns multiple values, one for each top-level message or enum definition for each distinct package definition.

Each resulting library will be given a name corresponding to the package and type definition it represents - dots are replaced with spaces, so the package name "com.google.protobuf" with top-level message definition "MyMessage" will be translated to the library name (com google protobuf MyMessage)'. Definitions that occur outside of a specified package will produce a library whose name has the prefix(protobuf default)'.

Messages

Each protobuf message definition will generate two R6RS record definitions: An opaque, sealed record type whose parent type is protobuf:message' and which defines a set of immutable fields that corresponds to the set of fields in the message definition; and a "builder" record type whose parent type is protobuf:message-builder' and which defines mutable versions of the message's fields. The builder type exports the following bindings:

When the builder factory function is called, a new instance of the message type is constructed that includes a shallow clone of the fields set on the builder at the time the factory function was called. The contents of repeated types are also converted from lists to vectors.

The -write function takes an output port as its second argument; the -read function takes an input port. Serialization and deserialization is performed according to the protocol buffer wire protocol format description.

For example, the extension definition

message MyDataStructure { repeated string foo = 1; }

produces the following bindings:

make-MyDataStructure-builder MyDataStructure-builder? MyDataStructure-builder-build

MyDataStructure-builder-foo set-MyDataStructure-builder-foo! has-MyDataStructure-builder-foo? clear-MyDataStructure-builder-foo!

MyDataStructure? MyDataStructure-foo

Use of the builder API follows the following pattern:

  1. Construct builder
  2. Set desired fields on builder
  3. Use factory function to construct immutable message instances

For example:

(define mdsb (make-MyDataStructure-builder)) (set-MyDataStructure-builder-foo! '("a" "b" "c")) (define mds (MyDataStructure-builder-build)) (MyDataStructure-foo mds) => #("a" "b" "c")

Enumerations

Each protobuf enum definition will generate an R6RS enumeration definition and export two bindings: The enumeration's "constructor syntax," which can be used to produce subsets of its universe; and its type predicate macro:

For example, the enum definition

enum MyEnumeration { FOO = 1, BAR = 2 }

creates the following bindings:

make-MyEnumeration MyEnumeration?

Extensions

Each protobuf extension definition will generate a set of extension field descriptor bindings that corresponds to the set of fields defined by the extensions.

These field descriptors can be passed as the second argument to the extension functions exported by the message types. For example, the extension definition

extend MyDataStructure { optional int32 bar = 100; }

will produce the extension field descriptor MyDataStructure-foo', which can be used with the extension API ofMyDataStructure' in the following ways:

(define mdsb (make-MyDataStructure-builder)) (set-MyDataStructure-builder-extension mdsb MyDataStructure-bar 256) (has-MyDataStructure-builder-extension? mdsb MyDataStructure-bar) => #t (define mds (MyDataStructure-builder-build)) (has-MyDataStructure-extension? mds MyDataStructure-bar) => #t