Coverage Report

Created: 2025-10-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rmp-0.8.14/src/encode/mod.rs
Line
Count
Source
1
//! Provides various functions and structs for MessagePack encoding.
2
3
mod bin;
4
mod dec;
5
mod ext;
6
mod map;
7
mod sint;
8
mod str;
9
mod uint;
10
mod vec;
11
12
pub use self::bin::{write_bin, write_bin_len};
13
pub use self::dec::{write_f32, write_f64};
14
pub use self::sint::{write_i16, write_i32, write_i64, write_i8, write_nfix, write_sint};
15
pub use self::str::{write_str, write_str_len};
16
pub use self::uint::{write_pfix, write_u16, write_u32, write_u64, write_u8, write_uint, write_uint8};
17
18
use core::fmt::{self, Debug, Display, Formatter};
19
#[cfg(feature = "std")]
20
use std::error;
21
22
use crate::Marker;
23
24
pub mod buffer;
25
pub use buffer::ByteBuf;
26
27
#[doc(inline)]
28
#[allow(deprecated)]
29
pub use crate::errors::Error;
30
31
/// The error type for operations on the [`RmpWrite`] trait.
32
///
33
/// For [`std::io::Write`], this is [`std::io::Error`]
34
/// For [`ByteBuf`], this is [`core::convert::Infallible`]
35
pub trait RmpWriteErr: Display + Debug + crate::errors::MaybeErrBound + 'static {}
36
#[cfg(feature = "std")]
37
impl RmpWriteErr for std::io::Error {}
38
impl RmpWriteErr for core::convert::Infallible {}
39
40
// An error returned from the `write_marker` and `write_fixval` functions.
41
struct MarkerWriteError<E: RmpWriteErr>(E);
42
43
impl<E: RmpWriteErr> From<E> for MarkerWriteError<E> {
44
    #[cold]
45
0
    fn from(err: E) -> Self {
46
0
        MarkerWriteError(err)
47
0
    }
48
}
49
50
/// Attempts to write the given marker into the writer.
51
0
fn write_marker<W: RmpWrite>(wr: &mut W, marker: Marker) -> Result<(), MarkerWriteError<W::Error>> {
52
0
    wr.write_u8(marker.to_u8()).map_err(MarkerWriteError)
53
0
}
54
55
/// An error returned from primitive values write functions.
56
#[doc(hidden)]
57
pub struct DataWriteError<E: RmpWriteErr>(E);
58
59
impl<E: RmpWriteErr> From<E> for DataWriteError<E> {
60
    #[cold]
61
    #[inline]
62
0
    fn from(err: E) -> DataWriteError<E> {
63
0
        DataWriteError(err)
64
0
    }
65
}
66
67
/// Encodes and attempts to write a nil value into the given write.
68
///
69
/// According to the MessagePack specification, a nil value is represented as a single `0xc0` byte.
70
///
71
/// # Errors
72
///
73
/// This function will return `Error` on any I/O error occurred while writing the nil marker.
74
///
75
/// # Examples
76
///
77
/// ```
78
/// let mut buf = Vec::new();
79
///
80
/// rmp::encode::write_nil(&mut buf).unwrap();
81
///
82
/// assert_eq!(vec![0xc0], buf);
83
/// ```
84
#[inline]
85
0
pub fn write_nil<W: RmpWrite>(wr: &mut W) -> Result<(), W::Error> {
86
0
    write_marker(wr, Marker::Null).map_err(|e| e.0)
87
0
}
88
89
/// Encodes and attempts to write a bool value into the given write.
90
///
91
/// According to the MessagePack specification, an encoded boolean value is represented as a single
92
/// byte.
93
///
94
/// # Errors
95
///
96
/// Each call to this function may generate an I/O error indicating that the operation could not be
97
/// completed.
98
#[inline]
99
0
pub fn write_bool<W: RmpWrite>(wr: &mut W, val: bool) -> Result<(), W::Error> {
100
0
    let marker = if val { Marker::True } else { Marker::False };
101
102
0
    write_marker(wr, marker).map_err(|e| e.0)
103
0
}
104
105
mod sealed {
106
    pub trait Sealed {}
107
    #[cfg(feature = "std")]
108
    impl<T: ?Sized + std::io::Write> Sealed for T {}
109
    #[cfg(not(feature = "std"))]
110
    impl Sealed for &mut [u8] {}
111
    #[cfg(not(feature = "std"))]
112
    impl Sealed for alloc::vec::Vec<u8> {}
113
    impl Sealed for super::ByteBuf {}
114
}
115
116
macro_rules! write_byteorder_utils {
117
    ($($name:ident => $tp:ident),* $(,)?) => {
118
        $(
119
            #[inline]
120
            #[doc(hidden)]
121
0
            fn $name(&mut self, val: $tp) -> Result<(), DataWriteError<Self::Error>> where Self: Sized {
122
                const SIZE: usize = core::mem::size_of::<$tp>();
123
0
                let mut buf: [u8; SIZE] = [0u8; SIZE];
124
                paste::paste! {
125
0
                    <byteorder::BigEndian as byteorder::ByteOrder>::[<write_ $tp>](&mut buf, val);
126
                }
127
0
                self.write_bytes(&buf).map_err(DataWriteError)
128
0
            }
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_f32
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_f64
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_i16
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_i32
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_i64
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_u16
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_u32
Unexecuted instantiation: <_ as rmp::encode::RmpWrite>::write_data_u64
129
        )*
130
    };
131
}
132
133
/// A type that `rmp` supports writing into.
134
///
135
/// The methods of this trait should be considered an implementation detail (for now).
136
/// It is currently sealed (can not be implemented by the user).
137
///
138
/// See also [`std::io::Write`] and [`byteorder::WriteBytesExt`]
139
///
140
/// Its primary implementations are [`std::io::Write`] and [`ByteBuf`].
141
pub trait RmpWrite: sealed::Sealed {
142
    type Error: RmpWriteErr;
143
144
    /// Write a single byte to this stream
145
    #[inline]
146
0
    fn write_u8(&mut self, val: u8) -> Result<(), Self::Error> {
147
0
        let buf = [val];
148
0
        self.write_bytes(&buf)
149
0
    }
150
151
    /// Write a slice of bytes to the underlying stream
152
    ///
153
    /// This will either write all the bytes or return an error.
154
    /// See also [`std::io::Write::write_all`]
155
    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
156
157
    // Internal helper functions to map I/O error into the `DataWriteError` error.
158
159
    /// Write a single (signed) byte to this stream.
160
    #[inline]
161
    #[doc(hidden)]
162
0
    fn write_data_u8(&mut self, val: u8) -> Result<(), DataWriteError<Self::Error>> {
163
0
        self.write_u8(val).map_err(DataWriteError)
164
0
    }
165
    /// Write a single (signed) byte to this stream.
166
    #[inline]
167
    #[doc(hidden)]
168
0
    fn write_data_i8(&mut self, val: i8) -> Result<(), DataWriteError<Self::Error>> {
169
0
        self.write_data_u8(val as u8)
170
0
    }
171
172
    write_byteorder_utils!(
173
        write_data_u16 => u16,
174
        write_data_u32 => u32,
175
        write_data_u64 => u64,
176
        write_data_i16 => i16,
177
        write_data_i32 => i32,
178
        write_data_i64 => i64,
179
        write_data_f32 => f32,
180
        write_data_f64 => f64
181
    );
182
}
183
184
#[cfg(feature = "std")]
185
impl<T: std::io::Write> RmpWrite for T {
186
    type Error = std::io::Error;
187
188
    #[inline]
189
0
    fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
190
0
        self.write_all(buf)
191
0
    }
192
}
193
194
/// An error that can occur when attempting to write multi-byte MessagePack value.
195
#[derive(Debug)]
196
#[allow(deprecated)] // TODO: Needed for compatibility
197
pub enum ValueWriteError<E: RmpWriteErr = Error> {
198
    /// I/O error while writing marker.
199
    InvalidMarkerWrite(E),
200
    /// I/O error while writing data.
201
    InvalidDataWrite(E),
202
}
203
204
impl<E: RmpWriteErr> From<MarkerWriteError<E>> for ValueWriteError<E> {
205
    #[cold]
206
0
    fn from(err: MarkerWriteError<E>) -> Self {
207
0
        match err {
208
0
            MarkerWriteError(err) => ValueWriteError::InvalidMarkerWrite(err),
209
        }
210
0
    }
211
}
212
213
impl<E: RmpWriteErr> From<DataWriteError<E>> for ValueWriteError<E> {
214
    #[cold]
215
0
    fn from(err: DataWriteError<E>) -> Self {
216
0
        match err {
217
0
            DataWriteError(err) => ValueWriteError::InvalidDataWrite(err),
218
        }
219
0
    }
220
}
221
222
#[cfg(feature = "std")] // Backwards compatbility ;)
223
impl From<ValueWriteError<std::io::Error>> for std::io::Error {
224
    #[cold]
225
0
    fn from(err: ValueWriteError<std::io::Error>) -> std::io::Error {
226
0
        match err {
227
0
            ValueWriteError::InvalidMarkerWrite(err) |
228
0
            ValueWriteError::InvalidDataWrite(err) => err,
229
        }
230
0
    }
231
}
232
233
#[cfg(feature = "std")]
234
impl<E: RmpWriteErr> error::Error for ValueWriteError<E> {
235
    #[cold]
236
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
237
0
        match *self {
238
0
            ValueWriteError::InvalidMarkerWrite(ref err) |
239
0
            ValueWriteError::InvalidDataWrite(ref err) => Some(err),
240
        }
241
0
    }
242
}
243
244
impl<E: RmpWriteErr> Display for ValueWriteError<E> {
245
    #[cold]
246
0
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
247
0
        f.write_str("error while writing multi-byte MessagePack value")
248
0
    }
249
}
250
251
/// Encodes and attempts to write the most efficient array length implementation to the given write,
252
/// returning the marker used.
253
///
254
/// # Errors
255
///
256
/// This function will return `ValueWriteError` on any I/O error occurred while writing either the
257
/// marker or the data.
258
0
pub fn write_array_len<W: RmpWrite>(wr: &mut W, len: u32) -> Result<Marker, ValueWriteError<W::Error>> {
259
0
    let marker = if len < 16 {
260
0
        Marker::FixArray(len as u8)
261
0
    } else if len <= u16::MAX as u32 {
262
0
        Marker::Array16
263
    } else {
264
0
        Marker::Array32
265
    };
266
267
0
    write_marker(wr, marker)?;
268
0
    if marker == Marker::Array16 {
269
0
        wr.write_data_u16(len as u16)?;
270
0
    } else if marker == Marker::Array32 {
271
0
        wr.write_data_u32(len)?;
272
0
    }
273
0
    Ok(marker)
274
0
}
275
276
/// Encodes and attempts to write the most efficient map length implementation to the given write,
277
/// returning the marker used.
278
///
279
/// # Errors
280
///
281
/// This function will return `ValueWriteError` on any I/O error occurred while writing either the
282
/// marker or the data.
283
0
pub fn write_map_len<W: RmpWrite>(wr: &mut W, len: u32) -> Result<Marker, ValueWriteError<W::Error>> {
284
0
    let marker = if len < 16 {
285
0
        Marker::FixMap(len as u8)
286
0
    } else if len <= u16::MAX as u32 {
287
0
        Marker::Map16
288
    } else {
289
0
        Marker::Map32
290
    };
291
292
0
    write_marker(wr, marker)?;
293
0
    if marker == Marker::Map16 {
294
0
        wr.write_data_u16(len as u16)?;
295
0
    } else if marker == Marker::Map32 {
296
0
        wr.write_data_u32(len)?;
297
0
    }
298
0
    Ok(marker)
299
0
}
300
301
/// Encodes and attempts to write the most efficient ext metadata implementation to the given
302
/// write, returning the marker used.
303
///
304
/// # Errors
305
///
306
/// This function will return `ValueWriteError` on any I/O error occurred while writing either the
307
/// marker or the data.
308
///
309
/// # Panics
310
///
311
/// Panics if `ty` is negative, because it is reserved for future MessagePack extension including
312
/// 2-byte type information.
313
0
pub fn write_ext_meta<W: RmpWrite>(wr: &mut W, len: u32, ty: i8) -> Result<Marker, ValueWriteError<W::Error>> {
314
0
    let marker = match len {
315
0
        1 => Marker::FixExt1,
316
0
        2 => Marker::FixExt2,
317
0
        4 => Marker::FixExt4,
318
0
        8 => Marker::FixExt8,
319
0
        16 => Marker::FixExt16,
320
0
        0..=255 => Marker::Ext8,
321
0
        256..=65535 => Marker::Ext16,
322
0
        _ => Marker::Ext32,
323
    };
324
0
    write_marker(wr, marker)?;
325
326
0
    if marker == Marker::Ext8 {
327
0
        wr.write_data_u8(len as u8)?;
328
0
    } else if marker == Marker::Ext16 {
329
0
        wr.write_data_u16(len as u16)?;
330
0
    } else if marker == Marker::Ext32 {
331
0
        wr.write_data_u32(len)?;
332
0
    }
333
334
0
    wr.write_data_i8(ty)?;
335
336
0
    Ok(marker)
337
0
}