1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#![cfg_attr(not(any(test, feature = "use-std")), no_std)]
#![warn(missing_docs)]
#![cfg_attr(not(doctest), doc = include_str!("../README.md"))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]

pub mod accumulator;
mod de;
mod error;
pub mod fixint;
mod ser;
mod varint;

// Still experimental! Don't make pub pub.
pub(crate) mod max_size;
pub(crate) mod schema;

/// # Experimental Postcard Features
///
/// Items inside this module require various feature flags, and are not
/// subject to SemVer stability. Items may be removed or deprecated at
/// any point.
///
/// ## Derive
///
/// The `experimental-derive` feature enables two experimental features:
///
/// * Max size calculation
/// * Message schema generation
///
/// ### Max Size Calculation
///
/// This features enables calculation of the Max serialized size of a message as
/// an associated `usize` constant called `POSTCARD_MAX_SIZE`. It also provides a
/// `#[derive(MaxSize)]` macro that can be used for calculating user types.
///
/// This is useful for determining the maximum buffer size needed when recieving
/// or sending a message that has been serialized.
///
/// NOTE: This only covers the size of "plain" flavored messages, e.g. not with COBS
/// or any other Flavors applied. The overhead for these flavors must be calculated
/// separately.
///
/// Please report any missing types, or any incorrectly calculated values.
///
/// ### Message Schema Generation
///
/// This feature enables the generation of a schema of a given message at compile
/// time. At the moment, this is only exposed as a [`NamedType`](crate::experimental::schema::NamedType)
/// which is a recursive data structure describing the schema. In the future, it is planned
/// to provide formatting functions that emit this as a human or machine readable schema.
///
/// NOTE: This only covers the schema of "plain" flavored messages, e.g. not with COBS
/// or any other Flavors applied. The format of these flavors must be calculated
/// separately.
///
/// Please report any missing types, or any incorrectly calculated schemas.
pub mod experimental {
    /// Compile time max-serialization size calculation
    #[cfg(feature = "experimental-derive")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "experimental-derive")))]
    pub mod max_size {
        // NOTE: This is the trait...
        pub use crate::max_size::MaxSize;
        // NOTE: ...and this is the derive macro
        pub use postcard_derive::MaxSize;
    }

    pub use crate::ser::serialized_size;

    /// Compile time Schema generation
    #[cfg(feature = "experimental-derive")]
    #[cfg_attr(doc_cfg, doc(cfg(feature = "experimental-derive")))]
    pub mod schema {
        // NOTE: This is the trait...
        pub use crate::schema::{NamedType, NamedValue, NamedVariant, Schema, SdmTy, Varint};
        // NOTE: ...and this is the derive macro
        pub use postcard_derive::Schema;
    }
}

pub use de::deserializer::Deserializer;
pub use de::flavors as de_flavors;
pub use de::{from_bytes, from_bytes_cobs, take_from_bytes, take_from_bytes_cobs};
pub use error::{Error, Result};
pub use ser::flavors as ser_flavors;
pub use ser::{serialize_with_flavor, serializer::Serializer, to_extend, to_slice, to_slice_cobs};

#[cfg(feature = "heapless")]
pub use ser::{to_vec, to_vec_cobs};

#[cfg(feature = "embedded-io")]
pub use ser::to_eio;

#[cfg(feature = "embedded-io")]
pub use de::from_eio;

#[cfg(feature = "use-std")]
pub use ser::{to_io, to_stdvec, to_stdvec_cobs};

#[cfg(feature = "use-std")]
pub use de::from_io;

#[cfg(feature = "alloc")]
pub use ser::{to_allocvec, to_allocvec_cobs};

#[cfg(feature = "use-crc")]
pub use {
    de::{from_bytes_crc32, take_from_bytes_crc32},
    ser::to_slice_crc32,
};

#[cfg(all(feature = "use-crc", feature = "heapless"))]
pub use ser::to_vec_crc32;

#[cfg(all(feature = "use-crc", feature = "use-std"))]
pub use ser::to_stdvec_crc32;

#[cfg(all(feature = "use-crc", feature = "alloc"))]
pub use ser::to_allocvec_crc32;

#[cfg(test)]
mod test {
    #[test]
    fn varint_boundary_canon() {
        let x = u32::MAX;
        let mut buf = [0u8; 5];
        let used = crate::to_slice(&x, &mut buf).unwrap();
        let deser: u32 = crate::from_bytes(used).unwrap();
        assert_eq!(deser, u32::MAX);
        assert_eq!(used, &mut [0xFF, 0xFF, 0xFF, 0xFF, 0x0F]);
        let deser: Result<u32, crate::Error> = crate::from_bytes(&[0xFF, 0xFF, 0xFF, 0xFF, 0x1F]);
        assert_eq!(deser, Err(crate::Error::DeserializeBadVarint));
    }

    #[test]
    fn signed_int128() {
        let x = -19490127978232325886905073712831_i128;
        let mut buf = [0u8; 32];
        let used = crate::to_slice(&x, &mut buf).unwrap();
        let deser: i128 = crate::from_bytes(used).unwrap();
        assert_eq!(deser, x);
    }
}