• Stars
    star
    72
  • Rank 438,337 (Top 9 %)
  • Language
    C
  • License
    MIT License
  • Created over 5 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Google Protocol Buffers tools (C code generator).

nala_

About

Google Protocol Buffers tools in Python 3.6+.

  • C source code generator.
  • proto3 language parser.

Known limitations:

  • Options, services (gRPC) and reserved fields are ignored.
  • Public imports are not implemented.

Project homepage: https://github.com/eerimoq/pbtools

Documentation: https://pbtools.readthedocs.io

Installation

pip install pbtools

C source code design

The C source code is designed with the following in mind:

  • Clean and easy to use API.
  • No malloc/free. Uses a workspace/arena for memory allocations.
  • Fast encoding and decoding.
  • Small memory footprint.
  • Thread safety.

Known limitations:

  • char must be 8 bits.

ToDo:

  • Make map easier to use. Only one allocation should be needed before encoding, not one per sub-message item.

Memory management

A workspace, or arena, is used to allocate memory when encoding and decoding messages. For simplicity, allocated memory can't be freed, which puts restrictions on how a message can be modified between encodings (if one want to do that). Scalar value type fields (ints, strings, bytes, etc.) can be modified, but the length of repeated fields can't.

Scalar Value Types

Protobuf scalar value types are mapped to C types as shown in the table below.

Protubuf Type C Type
double double
float float
int32 int32_t
int64 int64_t
uint32 uint32_t
uint64 uint64_t
sint32 int32_t
sint64 int64_t
fixed32 int32_t
fixed64 int64_t
sfixed32 int32_t
sfixed64 int64_t
bool bool
string char *
bytes struct { uint8_t *buf_p, size_t size }

Message

A message is a struct in C.

For example, let's create a protocol specification.

syntax = "proto3";

package foo;

message Bar {
    bool v1 = 1;
}

message Fie {
    int32 v2 = 1;
    Bar v3 = 2;
}

One struct is generated per message.

struct foo_bar_t {
    bool v1;
};

struct foo_fie_t {
    int32_t v2;
    struct foo_bar_t *v3_p;
};

The sub-message v3 has to be allocated before encoding and checked if NULL after decoding.

struct foo_fie_t *fie_p;

/* Encode. */
fie_p = foo_fie_new(...);
fie_p->v2 = 5;
foo_fie_v3_alloc(fie_p);
fie_p->v3_p->v1 = true;
foo_fie_encode(fie_p, ...);

/* Decode. */
fie_p = foo_fie_new(...);
foo_fie_decode(fie_p, ...);

printf("%d\n", fie_p->v2);

if (fie_p->v3_p != NULL) {
    printf("%d\n", fie_p->v3_p->v1);
}

Oneof

A oneof is an enum (the choice) and a union in C.

For example, let's create a protocol specification.

syntax = "proto3";

package foo;

message Bar {
    oneof fie {
        int32 v1 = 1;
        bool v2 = 2;
    };
}

One enum and one struct is generated per oneof.

enum foo_bar_fie_e {
    foo_bar_fie_none_e = 0,
    foo_bar_fie_v1_e = 1,
    foo_bar_fie_v2_e = 2
};

struct foo_bar_t {
    enum foo_bar_fie_choice_e fie;
    union {
        int32_t v1;
        bool v2;
    };
};

The generated code can encode and decode messages. Call _<field>_init() or _<field>_alloc() to select which oneof field to encode. Use the enum to check which oneof field was decoded (if any).

struct foo_bar_t *bar_p;

/* Encode with choice v1. */
bar_p = foo_bar_new(...);
foo_bar_v1_init(bar_p);
bar_p->v1 = -2;
foo_bar_encode(bar_p, ...);

/* Decode. */
bar_p = foo_bar_new(...);
foo_bar_decode(bar_p, ...);

switch (bar_p->fie) {

case foo_bar_fie_none_e:
    printf("Not present.\n");
    break;

case foo_bar_fie_v1_e:
    printf("%d\n", bar_p->v1);
    break;

case foo_bar_fie_v2_e:
    printf("%d\n", bar_p->v2);
    break;

default:
    printf("Can not happen.\n");
    break;
}

Benchmark

See benchmark for a benchmark of a few C/C++ protobuf libraries.

Example usage

C source code

In this example we use the simple proto-file hello_world.proto.

syntax = "proto3";

package hello_world;

message Foo {
    int32 bar = 1;
}

Generate C source code from the proto-file.

$ pbtools generate_c_source examples/hello_world/hello_world.proto

See hello_world.h and hello_world.c for the contents of the generated files.

We'll use the generated types and functions below.

struct hello_world_foo_t {
   struct pbtools_message_base_t base;
   int32_t bar;
};

struct hello_world_foo_t *hello_world_foo_new(
    void *workspace_p,
    size_t size);

int hello_world_foo_encode(
    struct hello_world_foo_t *self_p,
    void *encoded_p,
    size_t size);

int hello_world_foo_decode(
    struct hello_world_foo_t *self_p,
    const uint8_t *encoded_p,
    size_t size);

Encode and decode the Foo-message in main.c.

#include <stdio.h>
#include "hello_world.h"

int main(int argc, const char *argv[])
{
    int size;
    uint8_t workspace[64];
    uint8_t encoded[16];
    struct hello_world_foo_t *foo_p;

    /* Encode. */
    foo_p = hello_world_foo_new(&workspace[0], sizeof(workspace));

    if (foo_p == NULL) {
        return (1);
    }

    foo_p->bar = 78;
    size = hello_world_foo_encode(foo_p, &encoded[0], sizeof(encoded));

    if (size < 0) {
        return (2);
    }

    printf("Successfully encoded Foo into %d bytes.\n", size);

    /* Decode. */
    foo_p = hello_world_foo_new(&workspace[0], sizeof(workspace));

    if (foo_p == NULL) {
        return (3);
    }

    size = hello_world_foo_decode(foo_p, &encoded[0], size);

    if (size < 0) {
        return (4);
    }

    printf("Successfully decoded %d bytes into Foo.\n", size);
    printf("Foo.bar: %d\n", foo_p->bar);

    return (0);
}

Build and run the program.

$ gcc -I lib/include main.c hello_world.c lib/src/pbtools.c -o main
$ ./main
Successfully encoded Foo into 2 bytes.
Successfully decoded 2 bytes into Foo.
Foo.bar: 78

See examples/hello_world for all files used in this example.

Command line tool

The generate C source subcommand

Below is an example of how to generate C source code from a proto-file.

$ pbtools generate_c_source examples/address_book/address_book.proto

See address_book.h and address_book.c for the contents of the generated files.

More Repositories

1

gqt

Build and execute GraphQL queries in the terminal.
Python
461
star
2

simba

Simba Embedded Programming Platform.
C
339
star
3

monolinux

Create embedded Linux systems with a single statically linked executable.
Makefile
324
star
4

asn1tools

ASN.1 parsing, encoding and decoding.
Python
290
star
5

detools

Binary delta encoding tools.
Python
159
star
6

monolinux-jiffy

A Monolinux distro for the Jiffy board!
C
154
star
7

moblin

Moblin, a free iOS app for IRL streaming.
Swift
133
star
8

bitstruct

Python bit pack/unpack package.
C
120
star
9

bincopy

Mangling of various file formats that conveys binary information (Motorola S-Record, Intel HEX, TI-TXT, Verilog VMEM, ELF and binary files).
Python
102
star
10

dbg-macro

A set of dbg(…) macros for C
C
79
star
11

nala

🦁 Nala - A delightful test framework for C projects.
C
69
star
12

pumbaa

Python on Simba.
C
62
star
13

mqttools

MQTT version 5.0 client and broker using asyncio
Python
61
star
14

hardware-reference

Various documents.
55
star
15

textparser

A text parser.
Python
29
star
16

async

πŸ”€ Asynchronous framework in C.
C
26
star
17

pyfuzzer

Fuzz test Python modules with libFuzzer
Python
24
star
18

asyncudp

Asyncio high level UDP sockets.
Python
24
star
19

asyncbg

Asyncio background tasks
Python
16
star
20

monolinux-raspberry-pi-3

A Monolinux distro for Raspberry Pi 3!
C
15
star
21

bitstream

A bit stream library for C.
C
15
star
22

messi

⚽ Reliable message passing in distributed systems.
C
14
star
23

pictools

Microchip PIC tools for software developers.
C
13
star
24

ecdtools

Electronic circuit design tools.
Python
10
star
25

monolinux-c-library

The Monolinux C library.
C
9
star
26

traceback

Colorful stack traceback in C on Linux.
C
9
star
27

soundid

Sound identification.
Python
7
star
28

humanfriendly

Human friendly C library.
C
7
star
29

monolinux-example-project

A Monolinux example project.
C
6
star
30

irwin

Plotting data in the terminal
Python
5
star
31

expect

Programmed dialogue with interactive streams.
Python
5
star
32

bunga

Control and monitor your system.
C
5
star
33

advent-of-code

https://adventofcode.com/
Python
4
star
34

systest

System test framework.
Python
4
star
35

simba-esp32

ESP32 for Simba
C
4
star
36

moblin-remote-control-relay

Moblin Remote Control Relay
JavaScript
4
star
37

argparse_addons

Additional Python argparse types and actions.
Python
3
star
38

terminal_graphics

Who knows?!?
Python
3
star
39

uml

Unified Modeling Language (UML)
Python
2
star
40

obs-remote-control-relay

OBS Remote Control Relay
JavaScript
2
star
41

romeo

C
2
star
42

drmario

Dr. Mario OBS plugin.
CMake
2
star
43

httpasync

HTTP Async
Python
2
star
44

avr-toolchain-windows

AVR toolchain for Windows
C
2
star
45

rafiki

Rust on Simba.
Rust
2
star
46

moblin_assistant

Moblin remote control assistant.
Python
2
star
47

Rist

librist Swift wrapper
Swift
1
star
48

monolinux-rust-jiffy

Monolinux in Rust for the Jiffy board
Dockerfile
1
star