# Postcard Bindgen [![Build status](https://github.com/teamplayer3/postcard-bindgen/workflows/Rust/badge.svg)](https://github.com/teamplayer3/postcard-bindgen/actions) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/teamplayer3/postcard-bindgen) [![Crates.io](https://img.shields.io/crates/v/postcard-bindgen.svg)](https://crates.io/crates/postcard-bindgen) [![Documentation](https://docs.rs/postcard-bindgen/badge.svg)](https://docs.rs/postcard-bindgen) `Postcard Bindgen` allows generating code for other languages to serialize to and deserialize from [postcard](https://github.com/jamesmunns/postcard) byte format. This helps to setup a communication between for example a microcontroller and a App using the `postcard crate` and its lightweight memory format. As main types structs and enums can be annotated with `PostcardBindings` to generate code for them. The generated code can be exported as a npm package to import it into a JavaScript project or as a pip package for python. ## Supported Languages * 🌐 JavaScript * 🐍 Python ## Usage > :warning: Run the crate that generates the bindings with rust nightly. This is necessary because this crate depends on [genco](https://github.com/udoprog/genco) and this crate uses a nightly feature to detect column changes. Structs and enums for which bindings should be generated must be annotated with `Serialize`/`Deserialize` from the [serde crate](https://github.com/serde-rs/serde) and the `PostcardBindings` macro from this crate. The process is divided into two steps. Firstly the annotation step. This is done mostly in a library crate. Secondly in a extra binary crate the annotated structs and enums must be imported (this means the library crate must be defined as a dependency) and as a main function the generation logic added. To generate the npm package this extra binary crate must be run. > If the `postcard-bindgen` crate is added as a dependency in the generation binary crate the future `generating` must be enabled. ## Example This example shows how to easily generate a npm package. For this the struct `Test` and the generation logic is in the same rust file. ```rust #[derive(Serialize, PostcardBindings)] struct Test { name: u8, other: u16, } fn main() { javascript::build_package( std::env::current_dir().unwrap().as_path(), PackageInfo { name: "generation-test".into(), version: "0.1.0".try_into().unwrap(), }, javascript::GenerationSettings::enable_all(), generate_bindings!(Test), ) .unwrap(); } ``` The following code can now be used to serialize an object in JavaScript. ```js import { serialize } from "generation-test"; const test = { name: "test", other: 23 } const bytes = serialize("Test", test) ``` ## Type mappings
Type Name | Rust | Js | Python |
Unit Type | ```rust struct UnitStruct; ``` | ```javascript {} ``` | ```python class UnitStruct: pass t = UnitStruct() ``` |
Tuple Struct | ```rust struct TupleStruct(u8, u16, u32); ``` | ```javascript [123, 1234, 12345] ``` | ```python class TupleStruct(tuple[u8]): ... t = TupleStruct(123, 1234, 12345) ``` |
Struct | ```rust struct Struct { a: u8, b: u16 }; ``` | ```javascript { a: 123, b: 1234 } ``` | ```python @dataclass class Struct a: u8 b: u16 t = Struct(a = 123, b = 1234) ``` |
Enum | ```rust enum Enum { A, B(u8), C { a: u8 } }; ``` | ```javascript { tag: "A", }, { tag: "B", value: 123 }, { tag: "C", value: { a: 123 } } ``` | ```python class Enum: pass class Enum_A(Enum): pass class Enum_B(Enum, tuple[u8]): ... @dataclass class Enum_C(Enum) a: u8 a = Enum_A() b = Enum_B(23) c = Enum_C(a = 23) ``` |
Option |
```rust
struct OptionTuple(Option | ```javascript // OptionTuple(Some(123)) [123] // OptionTuple(None) [undefined] // OptionStruct { a: Some(123) } { a: 123 } // OptionStruct { a: None } {} // or { a: undefined } ``` | ```python # OptionTuple(Some(123)) OptionTuple(123) # OptionTuple(None) OptionTuple(None) # OptionStruct { a: Some(123) } OptionStruct(a = 123) # OptionStruct { a: None } OptionStruct(a = None) ``` |
Map |
```rust
let map_string_key = HashMap:: | ```javascript // map_string_key { key: value } // map_any_key new Map() ``` | ```python # map_string_key : Dict[str, u8] = { key: value } # map_any_key : Dict[u16, u8] = { key: value } ``` |