Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rmp-0.8.14/src/decode/str.rs
Line
Count
Source
1
#[cfg(feature = "std")]
2
use std::error;
3
use core::fmt::{self, Display, Formatter};
4
use core::str::{from_utf8, Utf8Error};
5
6
use super::{read_marker, RmpRead, RmpReadErr, ValueReadError};
7
use crate::Marker;
8
9
#[derive(Debug)]
10
#[allow(deprecated)] // Only for compatibility
11
pub enum DecodeStringError<'a, E: RmpReadErr = super::Error> {
12
    InvalidMarkerRead(E),
13
    InvalidDataRead(E),
14
    TypeMismatch(Marker),
15
    /// The given buffer is not large enough to accumulate the specified amount of bytes.
16
    BufferSizeTooSmall(u32),
17
    InvalidUtf8(&'a [u8], Utf8Error),
18
}
19
20
#[cfg(feature = "std")]
21
impl<'a, E: RmpReadErr> error::Error for DecodeStringError<'a, E> {
22
    #[cold]
23
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
24
0
        match *self {
25
0
            DecodeStringError::InvalidMarkerRead(ref err) |
26
0
            DecodeStringError::InvalidDataRead(ref err) => Some(err),
27
            DecodeStringError::TypeMismatch(..) |
28
0
            DecodeStringError::BufferSizeTooSmall(..) => None,
29
0
            DecodeStringError::InvalidUtf8(_, ref err) => Some(err),
30
        }
31
0
    }
32
}
33
34
impl<'a, E: RmpReadErr> Display for DecodeStringError<'a, E> {
35
    #[cold]
36
0
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
37
0
        f.write_str("error while decoding string")
38
0
    }
39
}
40
41
impl<'a, E: RmpReadErr> From<ValueReadError<E>> for DecodeStringError<'a, E> {
42
    #[cold]
43
0
    fn from(err: ValueReadError<E>) -> DecodeStringError<'a, E> {
44
0
        match err {
45
0
            ValueReadError::InvalidMarkerRead(err) => DecodeStringError::InvalidMarkerRead(err),
46
0
            ValueReadError::InvalidDataRead(err) => DecodeStringError::InvalidDataRead(err),
47
0
            ValueReadError::TypeMismatch(marker) => DecodeStringError::TypeMismatch(marker),
48
        }
49
0
    }
50
}
51
52
/// Attempts to read up to 9 bytes from the given reader and to decode them as a string `u32` size
53
/// value.
54
///
55
/// According to the MessagePack specification, the string format family stores an byte array in 1,
56
/// 2, 3, or 5 bytes of extra bytes in addition to the size of the byte array.
57
///
58
/// # Errors
59
///
60
/// This function will return `ValueReadError` on any I/O error while reading either the marker or
61
/// the data.
62
///
63
/// It also returns `ValueReadError::TypeMismatch` if the actual type is not equal with the
64
/// expected one, indicating you with the actual type.
65
#[inline]
66
0
pub fn read_str_len<R: RmpRead>(rd: &mut R) -> Result<u32, ValueReadError<R::Error>> {
67
0
    Ok(read_str_len_with_nread(rd)?.0)
68
0
}
69
70
0
fn read_str_len_with_nread<R>(rd: &mut R) -> Result<(u32, usize), ValueReadError<R::Error>>
71
0
    where R: RmpRead
72
{
73
0
    match read_marker(rd)? {
74
0
        Marker::FixStr(size) => Ok((u32::from(size), 1)),
75
0
        Marker::Str8 => Ok((u32::from(rd.read_data_u8()?), 2)),
76
0
        Marker::Str16 => Ok((u32::from(rd.read_data_u16()?), 3)),
77
0
        Marker::Str32 => Ok((rd.read_data_u32()?, 5)),
78
0
        marker => Err(ValueReadError::TypeMismatch(marker)),
79
    }
80
0
}
81
82
/// Attempts to read a string data from the given reader and copy it to the buffer provided.
83
///
84
/// On success returns a borrowed string type, allowing to view the copied bytes as properly utf-8
85
/// string.
86
/// According to the spec, the string's data must to be encoded using utf-8.
87
///
88
/// # Errors
89
///
90
/// Returns `Err` in the following cases:
91
///
92
///  - if any IO error (including unexpected EOF) occurs, while reading an `rd`, except the EINTR,
93
///    which is handled internally.
94
///  - if the `out` buffer size is not large enough to keep all the data copied.
95
///  - if the data is not utf-8, with a description as to why the provided data is not utf-8 and
96
///    with a size of bytes actually copied to be able to get them from `out`.
97
///
98
/// # Examples
99
/// ```
100
/// use rmp::decode::read_str;
101
///
102
/// let buf = [0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
103
/// let mut out = [0u8; 16];
104
///
105
/// assert_eq!("le message", read_str(&mut &buf[..], &mut &mut out[..]).unwrap());
106
/// ```
107
///
108
/// # Unstable
109
///
110
/// This function is **unstable**, because it needs review.
111
// TODO: Stabilize. Mark error values for each error case (in docs).
112
0
pub fn read_str<'r, R>(rd: &mut R, buf: &'r mut [u8]) -> Result<&'r str, DecodeStringError<'r, R::Error>>
113
0
where
114
0
    R: RmpRead,
115
{
116
0
    let len = read_str_len(rd)?;
117
0
    let ulen = len as usize;
118
119
0
    if buf.len() < ulen {
120
0
        return Err(DecodeStringError::BufferSizeTooSmall(len));
121
0
    }
122
123
0
    read_str_data(rd, len, &mut buf[0..ulen])
124
0
}
125
126
0
pub fn read_str_data<'r, R>(rd: &mut R,
127
0
                            len: u32,
128
0
                            buf: &'r mut [u8])
129
0
                            -> Result<&'r str, DecodeStringError<'r, R::Error>>
130
0
    where R: RmpRead
131
{
132
0
    debug_assert_eq!(len as usize, buf.len());
133
134
    // Trying to copy exact `len` bytes.
135
0
    match rd.read_exact_buf(buf) {
136
0
        Ok(()) => match from_utf8(buf) {
137
0
            Ok(decoded) => Ok(decoded),
138
0
            Err(err) => Err(DecodeStringError::InvalidUtf8(buf, err)),
139
        },
140
0
        Err(err) => Err(DecodeStringError::InvalidDataRead(err)),
141
    }
142
0
}
143
144
/// Attempts to read and decode a string value from the reader, returning a borrowed slice from it.
145
///
146
// TODO: Also it's possible to implement all borrowing functions for all `BufRead` implementors.
147
#[deprecated(since = "0.8.6", note = "useless, use `read_str_from_slice` instead")]
148
0
pub fn read_str_ref(rd: &[u8]) -> Result<&[u8], DecodeStringError<'_, super::bytes::BytesReadError>> {
149
0
    let mut cur = super::Bytes::new(rd);
150
0
    let len = read_str_len(&mut cur)?;
151
0
    Ok(&cur.remaining_slice()[..len as usize])
152
0
}
153
154
/// Attempts to read and decode a string value from the reader, returning a borrowed slice from it.
155
///
156
/// # Examples
157
///
158
/// ```
159
/// use rmp::encode::write_str;
160
/// use rmp::decode::read_str_from_slice;
161
///
162
/// let mut buf = Vec::new();
163
/// write_str(&mut buf, "Unpacking").unwrap();
164
/// write_str(&mut buf, "multiple").unwrap();
165
/// write_str(&mut buf, "strings").unwrap();
166
///
167
/// let mut chunks = Vec::new();
168
/// let mut unparsed = &buf[..];
169
/// while let Ok((chunk, tail)) = read_str_from_slice(unparsed) {
170
///     chunks.push(chunk);
171
///     unparsed = tail;
172
/// }
173
///
174
/// assert_eq!(vec!["Unpacking", "multiple", "strings"], chunks);
175
/// ```
176
0
pub fn read_str_from_slice<T: ?Sized + AsRef<[u8]>>(
177
0
    buf: &T,
178
0
) -> Result<(&str, &[u8]), DecodeStringError<'_, super::bytes::BytesReadError>> {
179
0
    let buf = buf.as_ref();
180
0
    let (len, nread) = read_str_len_with_nread(&mut super::Bytes::new(buf))?;
181
0
    let ulen = len as usize;
182
183
0
    if buf[nread..].len() >= ulen {
184
0
        let (head, tail) = buf.split_at(nread + ulen);
185
0
        match from_utf8(&head[nread..]) {
186
0
            Ok(val) => Ok((val, tail)),
187
0
            Err(err) => Err(DecodeStringError::InvalidUtf8(buf, err)),
188
        }
189
    } else {
190
0
        Err(DecodeStringError::BufferSizeTooSmall(len))
191
    }
192
0
}