{"id":18913569,"url":"https://github.com/eerimoq/pbtools","last_synced_at":"2025-04-09T19:19:14.875Z","repository":{"id":43878066,"uuid":"203055828","full_name":"eerimoq/pbtools","owner":"eerimoq","description":"Google Protocol Buffers tools (C code generator).","archived":false,"fork":false,"pushed_at":"2024-04-06T15:11:06.000Z","size":1072,"stargazers_count":75,"open_issues_count":2,"forks_count":11,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-09T19:19:11.038Z","etag":null,"topics":["c","embedded","proto3","protobuf","protocol-buffers"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eerimoq.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"eerimoq"}},"created_at":"2019-08-18T20:57:14.000Z","updated_at":"2025-02-19T09:38:48.000Z","dependencies_parsed_at":"2024-01-16T23:30:34.014Z","dependency_job_id":"fc9430ae-1504-4fa8-a6b3-9e66f7d8fd2b","html_url":"https://github.com/eerimoq/pbtools","commit_stats":{"total_commits":426,"total_committers":3,"mean_commits":142.0,"dds":"0.0046948356807511304","last_synced_commit":"5ee0501b1357f85fecd8f86429c4e8664f65c1db"},"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eerimoq%2Fpbtools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eerimoq%2Fpbtools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eerimoq%2Fpbtools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eerimoq%2Fpbtools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eerimoq","download_url":"https://codeload.github.com/eerimoq/pbtools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248094991,"owners_count":21046770,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","embedded","proto3","protobuf","protocol-buffers"],"created_at":"2024-11-08T10:08:16.773Z","updated_at":"2025-04-09T19:19:14.831Z","avatar_url":"https://github.com/eerimoq.png","language":"C","funding_links":["https://github.com/sponsors/eerimoq"],"categories":["Serialization","序列化"],"sub_categories":["Advanced books","高级书籍"],"readme":"|nala|_\n\nAbout\n=====\n\n`Google Protocol Buffers`_ tools in Python 3.6+.\n\n- `C` source code generator.\n\n- `proto3`_ language parser.\n\nKnown limitations:\n\n- Options, services (gRPC) and reserved fields are ignored.\n\n- Public imports are not implemented.\n\nProject homepage: https://github.com/eerimoq/pbtools\n\nDocumentation: https://pbtools.readthedocs.io\n\nInstallation\n============\n\n.. code-block:: python\n\n   pip install pbtools\n\nC source code design\n====================\n\nThe C source code is designed with the following in mind:\n\n- Clean and easy to use API.\n\n- No malloc/free. Uses a workspace/arena for memory allocations.\n\n- Fast encoding and decoding.\n\n- Small memory footprint.\n\n- Thread safety.\n\nKnown limitations:\n\n- ``char`` must be 8 bits.\n\nToDo:\n\n- Make ``map`` easier to use. Only one allocation should be needed\n  before encoding, not one per sub-message item.\n\nMemory management\n-----------------\n\nA workspace, or arena, is used to allocate memory when encoding and\ndecoding messages. For simplicity, allocated memory can't be freed,\nwhich puts restrictions on how a message can be modified between\nencodings (if one want to do that). Scalar value type fields (ints,\nstrings, bytes, etc.) can be modified, but the length of repeated\nfields can't.\n\nScalar Value Types\n------------------\n\nProtobuf scalar value types are mapped to C types as shown in the\ntable below.\n\n+---------------+--------------------------------------------+\n| Protubuf Type | C Type                                     |\n+===============+============================================+\n| ``double``    | ``double``                                 |\n+---------------+--------------------------------------------+\n| ``float``     | ``float``                                  |\n+---------------+--------------------------------------------+\n| ``int32``     | ``int32_t``                                |\n+---------------+--------------------------------------------+\n| ``int64``     | ``int64_t``                                |\n+---------------+--------------------------------------------+\n| ``uint32``    | ``uint32_t``                               |\n+---------------+--------------------------------------------+\n| ``uint64``    | ``uint64_t``                               |\n+---------------+--------------------------------------------+\n| ``sint32``    | ``int32_t``                                |\n+---------------+--------------------------------------------+\n| ``sint64``    | ``int64_t``                                |\n+---------------+--------------------------------------------+\n| ``fixed32``   | ``int32_t``                                |\n+---------------+--------------------------------------------+\n| ``fixed64``   | ``int64_t``                                |\n+---------------+--------------------------------------------+\n| ``sfixed32``  | ``int32_t``                                |\n+---------------+--------------------------------------------+\n| ``sfixed64``  | ``int64_t``                                |\n+---------------+--------------------------------------------+\n| ``bool``      | ``bool``                                   |\n+---------------+--------------------------------------------+\n| ``string``    | ``char *``                                 |\n+---------------+--------------------------------------------+\n| ``bytes``     | ``struct { uint8_t *buf_p, size_t size }`` |\n+---------------+--------------------------------------------+\n\nMessage\n-------\n\nA message is a struct in C.\n\nFor example, let's create a protocol specification.\n\n.. code-block:: proto\n\n   syntax = \"proto3\";\n\n   package foo;\n\n   message Bar {\n       bool v1 = 1;\n   }\n\n   message Fie {\n       int32 v2 = 1;\n       Bar v3 = 2;\n   }\n\nOne struct is generated per message.\n\n.. code-block:: c\n\n   struct foo_bar_t {\n       bool v1;\n   };\n\n   struct foo_fie_t {\n       int32_t v2;\n       struct foo_bar_t *v3_p;\n   };\n\nThe sub-message ``v3`` has to be allocated before encoding and checked\nif ``NULL`` after decoding.\n\n.. code-block:: c\n\n   struct foo_fie_t *fie_p;\n\n   /* Encode. */\n   fie_p = foo_fie_new(...);\n   fie_p-\u003ev2 = 5;\n   foo_fie_v3_alloc(fie_p);\n   fie_p-\u003ev3_p-\u003ev1 = true;\n   foo_fie_encode(fie_p, ...);\n\n   /* Decode. */\n   fie_p = foo_fie_new(...);\n   foo_fie_decode(fie_p, ...);\n\n   printf(\"%d\\n\", fie_p-\u003ev2);\n\n   if (fie_p-\u003ev3_p != NULL) {\n       printf(\"%d\\n\", fie_p-\u003ev3_p-\u003ev1);\n   }\n\nOneof\n-----\n\nA oneof is an enum (the choice) and a union in C.\n\nFor example, let's create a protocol specification.\n\n.. code-block:: proto\n\n   syntax = \"proto3\";\n\n   package foo;\n\n   message Bar {\n       oneof fie {\n           int32 v1 = 1;\n           bool v2 = 2;\n       };\n   }\n\nOne enum and one struct is generated per oneof.\n\n.. code-block:: c\n\n   enum foo_bar_fie_e {\n       foo_bar_fie_none_e = 0,\n       foo_bar_fie_v1_e = 1,\n       foo_bar_fie_v2_e = 2\n   };\n\n   struct foo_bar_t {\n       enum foo_bar_fie_choice_e fie;\n       union {\n           int32_t v1;\n           bool v2;\n       };\n   };\n\nThe generated code can encode and decode messages. Call\n``_\u003cfield\u003e_init()`` or ``_\u003cfield\u003e_alloc()`` to select which oneof\nfield to encode. Use the ``enum`` to check which oneof field was\ndecoded (if any).\n\n.. code-block:: c\n\n   struct foo_bar_t *bar_p;\n\n   /* Encode with choice v1. */\n   bar_p = foo_bar_new(...);\n   foo_bar_v1_init(bar_p);\n   bar_p-\u003ev1 = -2;\n   foo_bar_encode(bar_p, ...);\n\n   /* Decode. */\n   bar_p = foo_bar_new(...);\n   foo_bar_decode(bar_p, ...);\n\n   switch (bar_p-\u003efie) {\n\n   case foo_bar_fie_none_e:\n       printf(\"Not present.\\n\");\n       break;\n\n   case foo_bar_fie_v1_e:\n       printf(\"%d\\n\", bar_p-\u003ev1);\n       break;\n\n   case foo_bar_fie_v2_e:\n       printf(\"%d\\n\", bar_p-\u003ev2);\n       break;\n\n   default:\n       printf(\"Can not happen.\\n\");\n       break;\n   }\n\nBenchmark\n---------\n\nSee `benchmark`_ for a benchmark of a few C/C++ protobuf libraries.\n\nExample usage\n=============\n\nC source code\n-------------\n\nIn this example we use the simple proto-file `hello_world.proto`_.\n\n.. code-block:: proto\n\n   syntax = \"proto3\";\n\n   package hello_world;\n\n   message Foo {\n       int32 bar = 1;\n   }\n\nGenerate C source code from the proto-file.\n\n.. code-block:: text\n\n   $ pbtools generate_c_source examples/hello_world/hello_world.proto\n\nSee `hello_world.h`_ and `hello_world.c`_ for the contents of the\ngenerated files.\n\nWe'll use the generated types and functions below.\n\n.. code-block:: c\n\n   struct hello_world_foo_t {\n      struct pbtools_message_base_t base;\n      int32_t bar;\n   };\n\n   struct hello_world_foo_t *hello_world_foo_new(\n       void *workspace_p,\n       size_t size);\n\n   int hello_world_foo_encode(\n       struct hello_world_foo_t *self_p,\n       void *encoded_p,\n       size_t size);\n\n   int hello_world_foo_decode(\n       struct hello_world_foo_t *self_p,\n       const uint8_t *encoded_p,\n       size_t size);\n\nEncode and decode the Foo-message in `main.c`_.\n\n.. code-block:: c\n\n   #include \u003cstdio.h\u003e\n   #include \"hello_world.h\"\n\n   int main(int argc, const char *argv[])\n   {\n       int size;\n       uint8_t workspace[64];\n       uint8_t encoded[16];\n       struct hello_world_foo_t *foo_p;\n\n       /* Encode. */\n       foo_p = hello_world_foo_new(\u0026workspace[0], sizeof(workspace));\n\n       if (foo_p == NULL) {\n           return (1);\n       }\n\n       foo_p-\u003ebar = 78;\n       size = hello_world_foo_encode(foo_p, \u0026encoded[0], sizeof(encoded));\n\n       if (size \u003c 0) {\n           return (2);\n       }\n\n       printf(\"Successfully encoded Foo into %d bytes.\\n\", size);\n\n       /* Decode. */\n       foo_p = hello_world_foo_new(\u0026workspace[0], sizeof(workspace));\n\n       if (foo_p == NULL) {\n           return (3);\n       }\n\n       size = hello_world_foo_decode(foo_p, \u0026encoded[0], size);\n\n       if (size \u003c 0) {\n           return (4);\n       }\n\n       printf(\"Successfully decoded %d bytes into Foo.\\n\", size);\n       printf(\"Foo.bar: %d\\n\", foo_p-\u003ebar);\n\n       return (0);\n   }\n\nBuild and run the program.\n\n.. code-block:: text\n\n   $ gcc -I lib/include main.c hello_world.c lib/src/pbtools.c -o main\n   $ ./main\n   Successfully encoded Foo into 2 bytes.\n   Successfully decoded 2 bytes into Foo.\n   Foo.bar: 78\n\nSee `examples/hello_world`_ for all files used in this example.\n\nCommand line tool\n-----------------\n\nThe generate C source subcommand\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nBelow is an example of how to generate C source code from a\nproto-file.\n\n.. code-block:: text\n\n   $ pbtools generate_c_source examples/address_book/address_book.proto\n\nSee `address_book.h`_ and `address_book.c`_ for the contents of the\ngenerated files.\n\n.. |nala| image:: https://img.shields.io/badge/nala-test-blue.svg\n.. _nala: https://github.com/eerimoq/nala\n\n.. _Google Protocol Buffers: https://developers.google.com/protocol-buffers\n\n.. _proto3: https://developers.google.com/protocol-buffers/docs/proto3\n\n.. _address_book.h: https://github.com/eerimoq/pbtools/blob/master/examples/address_book/generated/address_book.h\n\n.. _address_book.c: https://github.com/eerimoq/pbtools/blob/master/examples/address_book/generated/address_book.c\n\n.. _hello_world.proto: https://github.com/eerimoq/pbtools/blob/master/examples/hello_world/hello_world.proto\n\n.. _hello_world.h: https://github.com/eerimoq/pbtools/blob/master/examples/hello_world/generated/hello_world.h\n\n.. _hello_world.c: https://github.com/eerimoq/pbtools/blob/master/examples/hello_world/generated/hello_world.c\n\n.. _main.c: https://github.com/eerimoq/pbtools/blob/master/examples/hello_world/main.c\n\n.. _examples/hello_world: https://github.com/eerimoq/pbtools/blob/master/examples/hello_world\n\n.. _benchmark: https://github.com/eerimoq/pbtools/blob/master/benchmark\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feerimoq%2Fpbtools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feerimoq%2Fpbtools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feerimoq%2Fpbtools/lists"}