#binary-format #postcard #serialization #binary-encoding #javascript #generate #serde

no-std postcard-bindgen

A crate to generate bindings for the postcard binary format for other languages than Rust

16 unstable releases (4 breaking)

new 0.5.0 Dec 12, 2024
0.4.0 Oct 14, 2024
0.3.6 Oct 6, 2024
0.3.3 Feb 4, 2024
0.1.2 Nov 26, 2022

#631 in Encoding

Download history 155/week @ 2024-09-12 43/week @ 2024-09-19 107/week @ 2024-09-26 218/week @ 2024-10-03 182/week @ 2024-10-10 26/week @ 2024-10-17

1,207 downloads per month

MIT/Apache

215KB
5K SLoC

Postcard Bindgen

Build status License Crates.io Documentation

Postcard Bindgen allows generating code for other languages to serialize to and deserialize from 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

⚠️ Run the crate that generates the bindings with rust nightly. This is necessary because this crate depends on 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 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.

#[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.

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
struct UnitStruct;
{}
class UnitStruct:
    pass

t = UnitStruct()
Tuple Struct
struct TupleStruct(u8, u16, u32);
[123, 1234, 12345]
class TupleStruct(tuple[u8]):
    ...

t = TupleStruct(123, 1234, 12345)
Struct
struct Struct {
    a: u8,
    b: u16
};
{
    a: 123,
    b: 1234
}
@dataclass
class Struct
    a: u8
    b: u16

t = Struct(a = 123, b = 1234)
Enum
enum Enum {
    A,
    B(u8),
    C {
        a: u8
    }
};
{
    tag: "A",
},
{
    tag: "B",
    value: 123
},
{
    tag: "C",
    value: {
        a: 123
    }
}
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
struct OptionTuple(Option<u8>);

struct OptionStruct {
    a: Option<u8>
}
// OptionTuple(Some(123))
[123]
// OptionTuple(None)
[undefined]

// OptionStruct { a: Some(123) }
{
    a: 123
}
// OptionStruct { a: None }
{}
// or
{
    a: undefined
}
# OptionTuple(Some(123))
OptionTuple(123)
# OptionTuple(None)
OptionTuple(None)

# OptionStruct { a: Some(123) }
OptionStruct(a = 123)
# OptionStruct { a: None }
OptionStruct(a = None)
Map
let map_string_key = HashMap::<String, u8>::new();

let map_any_key = HashMap::<u16, u8>::new();
// map_string_key
{
    key: value
}

// map_any_key
new Map()
# map_string_key
: Dict[str, u8] = {
    key: value
}

# map_any_key
: Dict[u16, u8] = {
    key: value
}

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Postcard Bindgen by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions

Dependencies

~3.5–5MB
~92K SLoC