messagepack_core/decode/
str.rs

1//! String decoding helpers.
2
3use super::{DecodeBorrowed, Error, NbyteReader};
4use crate::{Decode, formats::Format, io::IoRead};
5
6/// Decode a MessagePack string and return a borrowed `&str`.
7pub struct StrDecoder;
8
9impl<'de> DecodeBorrowed<'de> for StrDecoder {
10    type Value = &'de str;
11
12    fn decode_borrowed_with_format<R>(
13        format: Format,
14        reader: &mut R,
15    ) -> core::result::Result<Self::Value, Error<R::Error>>
16    where
17        R: IoRead<'de>,
18    {
19        let str_ref = ReferenceStrDecoder::decode_with_format(format, reader)?;
20        match str_ref {
21            ReferenceStr::Borrowed(s) => Ok(s),
22            ReferenceStr::Copied(_) => Err(Error::InvalidData),
23        }
24    }
25}
26
27impl<'de> DecodeBorrowed<'de> for &'de str {
28    type Value = &'de str;
29
30    fn decode_borrowed_with_format<R>(
31        format: Format,
32        reader: &mut R,
33    ) -> core::result::Result<Self::Value, Error<R::Error>>
34    where
35        R: IoRead<'de>,
36    {
37        StrDecoder::decode_borrowed_with_format(format, reader)
38    }
39}
40
41/// Borrowed or copied UTF‑8 string reference
42pub enum ReferenceStr<'de, 'a> {
43    /// Borrowed from the input (`'de`).
44    Borrowed(&'de str),
45    /// Copied into a transient buffer bound to `'a`.
46    Copied(&'a str),
47}
48
49/// Decode a MessagePack string and return a [ReferenceStr]
50pub struct ReferenceStrDecoder;
51
52impl<'de> Decode<'de> for ReferenceStrDecoder {
53    type Value<'a>
54        = ReferenceStr<'de, 'a>
55    where
56        Self: 'a,
57        'de: 'a;
58    fn decode_with_format<'a, R>(
59        format: Format,
60        reader: &'a mut R,
61    ) -> Result<Self::Value<'a>, Error<R::Error>>
62    where
63        R: IoRead<'de>,
64        'de: 'a,
65    {
66        let len = match format {
67            Format::FixStr(n) => n.into(),
68            Format::Str8 => NbyteReader::<1>::read(reader)?,
69            Format::Str16 => NbyteReader::<2>::read(reader)?,
70            Format::Str32 => NbyteReader::<4>::read(reader)?,
71            _ => return Err(Error::UnexpectedFormat),
72        };
73        let data = reader.read_slice(len).map_err(Error::Io)?;
74        match data {
75            crate::io::Reference::Borrowed(items) => {
76                let s = str::from_utf8(items).map_err(|_| Error::InvalidData)?;
77                Ok(ReferenceStr::Borrowed(s))
78            }
79            crate::io::Reference::Copied(items) => {
80                let s = str::from_utf8(items).map_err(|_| Error::InvalidData)?;
81                Ok(ReferenceStr::Copied(s))
82            }
83        }
84    }
85}
86
87#[cfg(feature = "alloc")]
88impl<'de> DecodeBorrowed<'de> for alloc::string::String {
89    type Value = alloc::string::String;
90
91    fn decode_borrowed_with_format<R>(
92        format: Format,
93        reader: &mut R,
94    ) -> core::result::Result<Self::Value, Error<R::Error>>
95    where
96        R: IoRead<'de>,
97    {
98        let sref = ReferenceStrDecoder::decode_with_format(format, reader)?;
99        let owned = match sref {
100            ReferenceStr::Borrowed(s) => alloc::string::String::from(s),
101            ReferenceStr::Copied(s) => alloc::string::String::from(s),
102        };
103        Ok(owned)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110    use crate::decode::Decode;
111
112    #[test]
113    fn decode_str() {
114        let buf: &[u8] = &[
115            0xab, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64,
116        ];
117
118        let mut r = crate::io::SliceReader::new(buf);
119        let decoded = StrDecoder::decode(&mut r).unwrap();
120        let expect = "Hello World";
121        assert_eq!(decoded, expect);
122        assert_eq!(r.rest().len(), 0);
123    }
124
125    #[test]
126    fn decode_invalid_str() {
127        let buf: &[u8] = &[0xa2, 0xc3, 0x28];
128        let mut r = crate::io::SliceReader::new(buf);
129        let err = StrDecoder::decode(&mut r).unwrap_err();
130        assert_eq!(err, Error::InvalidData);
131
132        let buf: &[u8] = &[0xa1, 0x80];
133        let mut r = crate::io::SliceReader::new(buf);
134        let err = StrDecoder::decode(&mut r).unwrap_err();
135        assert_eq!(err, Error::InvalidData);
136    }
137
138    #[cfg(feature = "alloc")]
139    #[test]
140    fn decode_string_owned() {
141        let buf: &[u8] = &[0xa3, b'f', b'o', b'o'];
142        let mut r = crate::io::SliceReader::new(buf);
143        let s = <alloc::string::String as Decode>::decode(&mut r).unwrap();
144        assert_eq!(s.as_str(), "foo");
145        assert!(r.rest().is_empty());
146    }
147}