Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = '2'
members = [
"source/postcard",
"source/postcard2",
"source/postcard-derive",
"source/postcard-derive-ng",
"source/postcard-dyn",
Expand Down
2 changes: 1 addition & 1 deletion source/postcard-derive-ng/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "postcard-derive-ng"
version = "0.3.0"
version = "0.3.1"
authors = [
"Lachlan Sneff <lachlan.sneff@gmail.com>",
"James Munns <james@onevariable.com>",
Expand Down
10 changes: 5 additions & 5 deletions source/postcard-derive-ng/src/max_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn do_derive_max_size(item: proc_macro::TokenStream) -> proc_macro::TokenStr
let sum = max_size_sum(&input.data, span).unwrap_or_else(syn::Error::into_compile_error);

let expanded = quote! {
impl #impl_generics ::postcard::experimental::max_size::MaxSize for #name #ty_generics #where_clause {
impl #impl_generics ::postcard2::experimental::max_size::MaxSize for #name #ty_generics #where_clause {
const POSTCARD_MAX_SIZE: usize = #sum;
}
};
Expand All @@ -32,7 +32,7 @@ fn add_trait_bounds(mut generics: Generics) -> Generics {
if let GenericParam::Type(ref mut type_param) = *param {
type_param
.bounds
.push(parse_quote!(::postcard::experimental::max_size::MaxSize));
.push(parse_quote!(::postcard2::experimental::max_size::MaxSize));
}
}
generics
Expand Down Expand Up @@ -70,7 +70,7 @@ fn max_size_sum(data: &Data, span: Span) -> Result<TokenStream, syn::Error> {
}
Data::Union(_) => Err(syn::Error::new(
span,
"unions are not supported by `postcard::MaxSize`",
"unions are not supported by `postcard2::MaxSize`",
)),
}
}
Expand All @@ -86,7 +86,7 @@ fn sum_fields(fields: &Fields) -> TokenStream {

let recurse = fields.named.iter().map(|f| {
let ty = &f.ty;
quote_spanned! { f.span() => <#ty as ::postcard::experimental::max_size::MaxSize>::POSTCARD_MAX_SIZE }
quote_spanned! { f.span() => <#ty as ::postcard2::experimental::max_size::MaxSize>::POSTCARD_MAX_SIZE }
});

quote! {
Expand All @@ -96,7 +96,7 @@ fn sum_fields(fields: &Fields) -> TokenStream {
syn::Fields::Unnamed(fields) => {
let recurse = fields.unnamed.iter().map(|f| {
let ty = &f.ty;
quote_spanned! { f.span() => <#ty as ::postcard::experimental::max_size::MaxSize>::POSTCARD_MAX_SIZE }
quote_spanned! { f.span() => <#ty as ::postcard2::experimental::max_size::MaxSize>::POSTCARD_MAX_SIZE }
});

quote! {
Expand Down
100 changes: 100 additions & 0 deletions source/postcard2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
[package]
name = "postcard2"
version = "0.1.0"
authors = ["James Munns <james@onevariable.com>"]
edition = "2021"
readme = "README.md"
repository = "https://github.com/jamesmunns/postcard"
description = "A no_std + serde compatible message library for Rust"
license = "MIT OR Apache-2.0"
categories = [
"embedded",
"no-std",
]
keywords = [
"serde",
"cobs",
"framing",
]
documentation = "https://docs.rs/postcard/"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]

[dependencies.heapless]
version = "0.7.0"
default-features = false
features = ["serde"]
optional = true

[dependencies.serde]
version = "1.0.100"
default-features = false
features = ["derive"]

[dependencies.cobs]
version = "0.3.0"
default-features = false

[dependencies.defmt]
version = "1"
optional = true

[dependencies.embedded-io-04]
package = "embedded-io"
version = "0.4"
optional = true

[dependencies.embedded-io-06]
package = "embedded-io"
version = "0.6"
optional = true

[dependencies.postcard-derive-ng]
version = "0.3.0"
optional = true
path = "../postcard-derive-ng"

[dependencies.crc]
version = "3.0.1"
optional = true

[dependencies.nalgebra_v0_33]
package = "nalgebra"
version = "0.33.0"
optional = true
default-features = false

[features]
default = ["heapless-cas"]

# Enables support for `embedded-io` traits
# This feature will track the latest `embedded-io` when major releases are made
embedded-io = ["dep:embedded-io-04"]

# Specific versions of `embedded-io` can be selected through the features below
embedded-io-04 = ["dep:embedded-io-04"]
embedded-io-06 = ["dep:embedded-io-06"]

use-std = ["serde/std", "alloc"]
heapless-cas = ["heapless", "dep:heapless", "heapless/cas"]
alloc = ["serde/alloc", "embedded-io-04?/alloc", "embedded-io-06?/alloc"]
use-defmt = ["defmt"]
use-crc = ["crc"]

# Does nothing, for compat only
paste = []

# Experimental features!
#
# NOT subject to SemVer guarantees!
experimental-derive = ["postcard-derive-ng"]
core-num-saturating = []
nalgebra-v0_33 = ["nalgebra_v0_33"]
crc = ["dep:crc"]
defmt = ["dep:defmt"]
heapless = ["dep:heapless"]
postcard-derive-ng = ["dep:postcard-derive-ng"]
146 changes: 146 additions & 0 deletions source/postcard2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Postcard

[![Documentation](https://docs.rs/postcard/badge.svg)](https://docs.rs/postcard)

Postcard is a `#![no_std]` focused serializer and deserializer for Serde.

Postcard aims to be convenient for developers in constrained environments, while
allowing for flexibility to customize behavior as needed.

## Design Goals

1. Design primarily for `#![no_std]` usage, in embedded or other constrained contexts
2. Support a maximal set of `serde` features, so `postcard` can be used as a drop in replacement
3. Avoid special differences in code between communication code written for a microcontroller or a desktop/server PC
4. Be resource efficient - memory usage, code size, developer time, and CPU time; in that order
5. Allow library users to customize the serialization and deserialization behavior to fit their bespoke needs

## Format Stability

As of v1.0.0, `postcard` has a documented and stable wire format. More information about this
wire format can be found in the `spec/` folder of the Postcard repository, or viewed online
at <https://postcard.jamesmunns.com>.

Work towards the Postcard Specification and portions of the Postcard 1.0 Release
were sponsored by Mozilla Corporation.

## Variable Length Data

All signed and unsigned integers larger than eight bits are encoded using a [Varint].
This includes the length of array slices, as well as the discriminant of `enums`.

For more information, see the [Varint] chapter of the wire specification.

[Varint]: https://postcard.jamesmunns.com/wire-format.html#varint-encoded-integers

## Example - Serialization/Deserialization

Postcard can serialize and deserialize messages similar to other `serde` formats.

Using the default `heapless` feature to serialize to a `heapless::Vec<u8>`:

```rust
use core::ops::Deref;
use serde::{Serialize, Deserialize};
use postcard2::{from_bytes, to_vec};
use heapless::Vec;

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct RefStruct<'a> {
bytes: &'a [u8],
str_s: &'a str,
}
let message = "hElLo";
let bytes = [0x01, 0x10, 0x02, 0x20];
let output: Vec<u8, 11> = to_vec(&RefStruct {
bytes: &bytes,
str_s: message,
}).unwrap();

assert_eq!(
&[0x04, 0x01, 0x10, 0x02, 0x20, 0x05, b'h', b'E', b'l', b'L', b'o',],
output.deref()
);

let out: RefStruct = from_bytes(output.deref()).unwrap();
assert_eq!(
out,
RefStruct {
bytes: &bytes,
str_s: message,
}
);
```

Or the optional `alloc` feature to serialize to an `alloc::vec::Vec<u8>`:

```rust
use core::ops::Deref;
use serde::{Serialize, Deserialize};
use postcard2::{from_bytes, to_allocvec};
extern crate alloc;
use alloc::vec::Vec;

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct RefStruct<'a> {
bytes: &'a [u8],
str_s: &'a str,
}
let message = "hElLo";
let bytes = [0x01, 0x10, 0x02, 0x20];
let output: Vec<u8> = to_allocvec(&RefStruct {
bytes: &bytes,
str_s: message,
}).unwrap();

assert_eq!(
&[0x04, 0x01, 0x10, 0x02, 0x20, 0x05, b'h', b'E', b'l', b'L', b'o',],
output.deref()
);

let out: RefStruct = from_bytes(output.deref()).unwrap();
assert_eq!(
out,
RefStruct {
bytes: &bytes,
str_s: message,
}
);
```

## Flavors

`postcard` supports a system called `Flavors`, which are used to modify the way
postcard serializes or processes serialized data. These flavors act as "plugins" or "middlewares"
during the serialization or deserialization process, and can be combined to obtain complex protocol formats.

See the documentation of the `ser_flavors` or `de_flavors` modules for more information on usage.

## Setup - `Cargo.toml`

Don't forget to add [the `no-std` subset](https://serde.rs/no-std.html) of `serde` along with `postcard` to the `[dependencies]` section of your `Cargo.toml`!

```toml
[dependencies]
postcard = "1.0.0"

# By default, `serde` has the `std` feature enabled, which makes it unsuitable for embedded targets
# disabling default-features fixes this
serde = { version = "1.0.*", default-features = false }
```

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)

at your option.

### Contribution

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