postcard_core/
ser.rs

1//! Serializing tools
2
3use crate::varint::{
4    varint_max, varint_u16, varint_u32, varint_u64, varint_u128, varint_usize, zig_zag_i16,
5    zig_zag_i32, zig_zag_i64, zig_zag_i128,
6};
7
8/// The serialization buffer is full
9#[derive(Debug)]
10pub struct BufferFull;
11
12impl core::fmt::Display for BufferFull {
13    #[inline]
14    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15        f.write_str("BufferFull")
16    }
17}
18
19/// The serialization Flavor trait
20///
21/// This is used as the primary way to encode serialized data into some kind of buffer,
22/// or modify that data in a middleware style pattern.
23///
24/// See the module level docs for an example of how flavors are used.
25pub trait Flavor {
26    /// The `Output` type is what this storage "resolves" to when the serialization is complete,
27    /// such as a slice or a Vec of some sort.
28    type Output;
29
30    /// The error type specific to pushing methods.
31    ///
32    /// This includes [`Self::try_extend`] and [`Self::try_push`].
33    ///
34    /// If this type cannot error when pushing, e.g. with a `Vec`, consider using
35    /// [`Infallible`](core::convert::Infallible). If this type can only fail due
36    /// to exhausting available space, consider using [`BufferFull`].
37    type PushError: core::fmt::Debug + core::fmt::Display;
38
39    /// The error type specific to [`Self::finalize`].
40    ///
41    /// If this type cannot error when pushing, e.g. for storage flavors that don't
42    /// perform any meaningful finalization actions, consider using
43    /// [`Infallible`](core::convert::Infallible).
44    type FinalizeError: core::fmt::Debug + core::fmt::Display;
45
46    /// Override this method when you want to customize processing
47    /// multiple bytes at once, such as copying a slice to the output,
48    /// rather than iterating over one byte at a time.
49    #[inline]
50    fn try_extend(&mut self, data: &[u8]) -> Result<(), Self::PushError> {
51        data.iter().try_for_each(|d| self.try_push(*d))
52    }
53
54    /// Push a single byte to be modified and/or stored.
55    fn try_push(&mut self, data: u8) -> Result<(), Self::PushError>;
56
57    /// Finalize the serialization process.
58    fn finalize(self) -> Result<Self::Output, Self::FinalizeError>;
59}
60
61/// Attempt to push a [bool]
62///
63/// [bool]: https://postcard.jamesmunns.com/wire-format#1---bool
64#[inline]
65pub fn try_push_bool<F: Flavor>(f: &mut F, b: bool) -> Result<(), F::PushError> {
66    let u = if b { 1 } else { 0 };
67    try_push_u8(f, u)
68}
69
70/// Attempt to push a [u8]
71///
72/// [u8]: https://postcard.jamesmunns.com/wire-format#7---u8
73#[inline]
74pub fn try_push_u8<F: Flavor>(f: &mut F, u: u8) -> Result<(), F::PushError> {
75    f.try_push(u)
76}
77
78/// Attempt to push a [u16]
79///
80/// [u16]: https://postcard.jamesmunns.com/wire-format#8---u16
81#[inline]
82pub fn try_push_u16<F: Flavor>(f: &mut F, u: u16) -> Result<(), F::PushError> {
83    let mut buf = [0u8; varint_max::<u16>()];
84    let used_buf = varint_u16(u, &mut buf);
85    f.try_extend(used_buf)
86}
87
88/// Attempt to push a [u32]
89///
90/// [u32]: https://postcard.jamesmunns.com/wire-format#9---u32
91#[inline]
92pub fn try_push_u32<F: Flavor>(f: &mut F, u: u32) -> Result<(), F::PushError> {
93    let mut buf = [0u8; varint_max::<u32>()];
94    let used_buf = varint_u32(u, &mut buf);
95    f.try_extend(used_buf)
96}
97
98/// Attempt to push a [u64]
99///
100/// [u64]: https://postcard.jamesmunns.com/wire-format#10---u64
101#[inline]
102pub fn try_push_u64<F: Flavor>(f: &mut F, u: u64) -> Result<(), F::PushError> {
103    let mut buf = [0u8; varint_max::<u64>()];
104    let used_buf = varint_u64(u, &mut buf);
105    f.try_extend(used_buf)
106}
107
108/// Attempt to push a [u128]
109///
110/// [u128]: https://postcard.jamesmunns.com/wire-format#11---u128
111#[inline]
112pub fn try_push_u128<F: Flavor>(f: &mut F, u: u128) -> Result<(), F::PushError> {
113    let mut buf = [0u8; varint_max::<u128>()];
114    let used_buf = varint_u128(u, &mut buf);
115    f.try_extend(used_buf)
116}
117
118#[inline]
119pub fn try_push_usize<F: Flavor>(f: &mut F, u: usize) -> Result<(), F::PushError> {
120    let mut buf = [0u8; varint_max::<usize>()];
121    let used_buf = varint_usize(u, &mut buf);
122    f.try_extend(used_buf)
123}
124
125/// Attempt to push a [i8]
126///
127/// [i8]: https://postcard.jamesmunns.com/wire-format#2---i8
128#[inline]
129pub fn try_push_i8<F: Flavor>(f: &mut F, i: i8) -> Result<(), F::PushError> {
130    let u = i as u8;
131    f.try_push(u)
132}
133
134/// Attempt to push a [i16]
135///
136/// [i16]: https://postcard.jamesmunns.com/wire-format#3---i16
137#[inline]
138pub fn try_push_i16<F: Flavor>(f: &mut F, i: i16) -> Result<(), F::PushError> {
139    let u = zig_zag_i16(i);
140    try_push_u16(f, u)
141}
142
143/// Attempt to push a [i32]
144///
145/// [i32]: https://postcard.jamesmunns.com/wire-format#4---i32
146#[inline]
147pub fn try_push_i32<F: Flavor>(f: &mut F, i: i32) -> Result<(), F::PushError> {
148    let u = zig_zag_i32(i);
149    try_push_u32(f, u)
150}
151
152/// Attempt to push a [i64]
153///
154/// [i64]: https://postcard.jamesmunns.com/wire-format#5---i64
155#[inline]
156pub fn try_push_i64<F: Flavor>(f: &mut F, i: i64) -> Result<(), F::PushError> {
157    let u = zig_zag_i64(i);
158    try_push_u64(f, u)
159}
160
161/// Attempt to push a [i128]
162///
163/// [i128]: https://postcard.jamesmunns.com/wire-format#6---i128
164#[inline]
165pub fn try_push_i128<F: Flavor>(f: &mut F, i: i128) -> Result<(), F::PushError> {
166    let u = zig_zag_i128(i);
167    try_push_u128(f, u)
168}
169
170#[inline]
171pub fn try_push_isize<F: Flavor>(f: &mut F, i: isize) -> Result<(), F::PushError> {
172    #[cfg(target_pointer_width = "16")]
173    let u = zig_zag_i16(i as i16) as usize;
174    #[cfg(target_pointer_width = "32")]
175    let u = zig_zag_i32(i as i32) as usize;
176    #[cfg(target_pointer_width = "64")]
177    let u = zig_zag_i64(i as i64) as usize;
178
179    try_push_usize(f, u)
180}
181
182/// Attempt to push an [f32]
183///
184/// [f32]: https://postcard.jamesmunns.com/wire-format#12---f32
185#[inline]
186pub fn try_push_f32<F: Flavor>(f: &mut F, fl: f32) -> Result<(), F::PushError> {
187    let u: [u8; 4] = fl.to_bits().to_le_bytes();
188    f.try_extend(&u)
189}
190
191/// Attempt to push an [f64]
192///
193/// [f64]: https://postcard.jamesmunns.com/wire-format#13---f64
194#[inline]
195pub fn try_push_f64<F: Flavor>(f: &mut F, fl: f64) -> Result<(), F::PushError> {
196    let u: [u8; 8] = fl.to_bits().to_le_bytes();
197    f.try_extend(&u)
198}
199
200/// Attempt to push a [byte array]
201///
202/// [byte array]: https://postcard.jamesmunns.com/wire-format#16---byte-array
203#[inline]
204pub fn try_push_bytes<F: Flavor>(f: &mut F, b: &[u8]) -> Result<(), F::PushError> {
205    try_push_length(f, b.len())?;
206    f.try_extend(b)
207}
208
209/// Attempt to push a [string]
210///
211/// [string]: https://postcard.jamesmunns.com/wire-format#15---string
212#[inline]
213pub fn try_push_str<F: Flavor>(f: &mut F, b: &str) -> Result<(), F::PushError> {
214    let bytes = b.as_bytes();
215    try_push_bytes(f, bytes)
216}
217
218/// Attempt to push an [option] discriminant
219///
220/// [option]: https://postcard.jamesmunns.com/wire-format#17---option
221#[inline]
222pub fn try_push_option_none<F: Flavor>(f: &mut F) -> Result<(), F::PushError> {
223    try_push_u8(f, 0)
224}
225
226/// Attempt to push an [option] discriminant
227///
228/// [option]: https://postcard.jamesmunns.com/wire-format#17---option
229#[inline]
230pub fn try_push_option_some<F: Flavor>(f: &mut F) -> Result<(), F::PushError> {
231    try_push_u8(f, 1)
232}
233
234/// Attempt to push a discriminant
235///
236/// Used for:
237///
238/// * [unit variant]
239/// * [newtype variant]
240/// * [tuple variant]
241/// * [struct variant]
242///
243/// [unit variant]: https://postcard.jamesmunns.com/wire-format#20---unit_variant
244/// [newtype variant]: https://postcard.jamesmunns.com/wire-format#22---newtype_variant
245/// [tuple variant]: https://postcard.jamesmunns.com/wire-format#26---tuple_variant
246/// [struct variant]: https://postcard.jamesmunns.com/wire-format#29---struct_variant
247#[inline]
248pub fn try_push_discriminant<F: Flavor>(f: &mut F, v: u32) -> Result<(), F::PushError> {
249    try_push_u32(f, v)
250}
251
252/// Attempt to push a length
253///
254/// Used for:
255///
256/// * [seq]
257/// * [map]
258/// * [byte array]
259/// * [string]
260///
261/// [seq]: https://postcard.jamesmunns.com/wire-format#23---seq
262/// [map]: https://postcard.jamesmunns.com/wire-format#27---map
263/// [byte array]: https://postcard.jamesmunns.com/wire-format#16---byte-array
264/// [string]: https://postcard.jamesmunns.com/wire-format#15---string
265#[inline]
266pub fn try_push_length<F: Flavor>(f: &mut F, v: usize) -> Result<(), F::PushError> {
267    try_push_usize(f, v)
268}
269
270/// Attempt to push a [char]
271///
272/// [char]: https://postcard.jamesmunns.com/wire-format#14---char
273#[inline]
274pub fn try_push_char<F: Flavor>(f: &mut F, v: char) -> Result<(), F::PushError> {
275    let mut buf = [0u8; 4];
276    let strsl = v.encode_utf8(&mut buf);
277    try_push_str(f, strsl)
278}