Commit 3e126545 authored by Robert Edmonds's avatar Robert Edmonds

protobuf-c: add doxygen documentation derived from doc/c-code-generator.xml

parent fc266579
......@@ -36,6 +36,11 @@
* This API includes interfaces that can be used directly by client code as well
* as the interfaces used by the code generated by the `protoc-c` compiler.
*
* The `libprotobuf-c` support library performs the actual serialization and
* deserialization of Protocol Buffers messages. It interacts with structures,
* definitions, and metadata generated by the `protoc-c` compiler from .proto
* files.
*
* \authors Dave Benson and the `protobuf-c` authors.
*
* \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license.
......@@ -43,6 +48,133 @@
* [protobuf-c]: https://github.com/protobuf-c/protobuf-c
* [Protocol Buffers]: https://developers.google.com/protocol-buffers/
* [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause
*
* \page gencode Generated Code
*
* For each enum, we generate a C enum. For each message, we generate a C
* structure which can be cast to a `ProtobufCMessage`.
*
* For each enum and message, we generate a descriptor object that allows us to
* implement a kind of reflection on the structures.
*
* First, some naming conventions:
*
* - The name of the type for enums and messages and services is camel case
* (meaning WordsAreCrammedTogether) except that double underscores are used
* to delimit scopes. For example, the following `.proto` file:
*
~~~{.proto}
package foo.bar;
message BazBah {
optional int32 val = 1;
}
~~~
*
* would generate a C type `Foo__Bar__BazBah`.
*
* - Identifiers for functions and globals are all lowercase, with camel case
* words separated by single underscores. For example, one of the function
* prototypes generated by `protoc-c` for the above example:
*
~~~{.c}
Foo__Bar__BazBah *
foo__bar__baz_bah__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
~~~
*
* - Identifiers for enum values contain an uppercase prefix which embeds the
* package name and the enum type name.
*
* - A double underscore is used to separate further components of identifier
* names.
*
* For example, in the name of the unpack function above, the package name
* `foo.bar` has become `foo__bar`, the message name BazBah has become
* `baz_bah`, and the method name is `unpack`. These are all joined with double
* underscores to form the C identifier `foo__bar__baz_bah__unpack`.
*
* We also generate descriptor objects for messages and enums. These are
* declared in the `.pb-c.h` files:
*
~~~{.c}
extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor;
~~~
*
* The message structures all begin with `ProtobufCMessageDescriptor *` which is
* sufficient to allow them to be cast to `ProtobufCMessage`.
*
* For each message defined in a `.proto` file, we generate a number of
* functions. Each function name contains a prefix based on the package name and
* message name in order to make it a unique C identifier.
*
* - `unpack()`. Unpacks data for a particular message format. Note that the
* `allocator` parameter is usually `NULL` to indicate that the system's
* `malloc()` and `free()` functions should be used for dynamically allocating
* memory.
*
~~~{.c}
Foo__Bar__BazBah *
foo__bar__baz_bah__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
~~~
*
* - `free_unpacked()`. Frees a message object obtained with the `unpack()`
* method.
*
~~~{.c}
void foo__bar__baz_bah__free_unpacked
(Foo__Bar__BazBah *message,
ProtobufCAllocator *allocator);
~~~
*
* - `get_packed_size()`. Calculates the length in bytes of the serialized
* representation of the message object.
*
~~~{.c}
size_t foo__bar__baz_bah__get_packed_size
(const Foo__Bar__BazBah *message);
~~~
*
* - `pack()`. Pack a message object into a preallocated buffer. Assumes that
* the buffer is large enough. (Use `get_packed_size()` first.)
*
~~~{.c}
size_t foo__bar__baz_bah__pack
(const Foo__Bar__BazBah *message,
uint8_t *out);
~~~
*
* - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an
* object which defines an "append bytes" callback to consume data as it is
* serialized.
*
~~~{.c}
size_t foo__bar__baz_bah__pack_to_buffer
(const Foo__Bar__BazBah *message,
ProtobufCBuffer *buffer);
~~~
*
* \page pack Packing and unpacking messages
*
* To pack a message, first compute the packed size of the message with
* protobuf_c_message_get_packed_size(), then allocate a buffer of at least
* that size, then call protobuf_c_message_pack().
*
* Alternatively, a message can be serialized without calculating the final size
* first. Use the protobuf_c_message_pack_to_buffer() function and provide a
* ProtobufCBuffer object which implements an "append" method that consumes
* data.
*
* To unpack a message, call the protobuf_c_message_unpack() function. The
* result can be cast to an object of the type that matches the descriptor for
* the message.
*
* The result of unpacking a message should be freed with
* protobuf_c_message_free_unpacked().
*/
#ifndef PROTOBUF_C_H
......@@ -247,7 +379,38 @@ struct ProtobufCBinaryData {
/**
* Structure for defining a virtual append-only buffer. Used by
* protobuf_c_message_pack_to_buffer().
* protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized
* bytes.
*
* `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to
* write to a `FILE` object:
*
~~~{.c}
typedef struct {
ProtobufCBuffer base;
FILE *fp;
} BufferAppendToFile;
static void
my_buffer_file_append(ProtobufCBuffer *buffer,
size_t len,
const uint8_t *data)
{
BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer;
fwrite(data, len, 1, file_buf->fp); // XXX: No error handling!
}
~~~
*
* To use this new type of ProtobufCBuffer, it could be called as follows:
*
~~~{.c}
...
BufferAppendToFile tmp = {0};
tmp.base.append = my_buffer_file_append;
tmp.fp = fp;
protobuf_c_message_pack_to_buffer(&message, &tmp);
...
~~~
*/
struct ProtobufCBuffer {
/** Append function. Consumes the `len` bytes stored at `data`. */
......@@ -258,6 +421,28 @@ struct ProtobufCBuffer {
/**
* Simple buffer "subclass" of `ProtobufCBuffer`.
*
* A `ProtobufCBufferSimple` object is declared on the stack and uses a
* scratch buffer provided by the user for the initial allocation. It performs
* exponential resizing, using dynamically allocated memory. A
* `ProtobufCBufferSimple` object can be created and used as follows:
*
~~~{.c}
uint8_t pad[128];
ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad);
ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple;
~~~
*
* `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a
* message has been serialized to a `ProtobufCBufferSimple` object, the
* serialized data bytes can be accessed from the `.data` field.
*
* To free the memory allocated by a `ProtobufCBufferSimple` object, if any,
* call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example:
*
~~~{.c}
PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple);
~~~
*
* \see PROTOBUF_C_BUFFER_SIMPLE_INIT
* \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment