Skip to main content

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")]
88mod alloc_impl {
89    use super::*;
90    impl<'de> DecodeBorrowed<'de> for alloc::string::String {
91        type Value = alloc::string::String;
92
93        fn decode_borrowed_with_format<R>(
94            format: Format,
95            reader: &mut R,
96        ) -> core::result::Result<Self::Value, Error<R::Error>>
97        where
98            R: IoRead<'de>,
99        {
100            let sref = ReferenceStrDecoder::decode_with_format(format, reader)?;
101            let owned = match sref {
102                ReferenceStr::Borrowed(s) => alloc::string::String::from(s),
103                ReferenceStr::Copied(s) => alloc::string::String::from(s),
104            };
105            Ok(owned)
106        }
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use crate::decode::Decode;
114
115    #[test]
116    fn decode_str() {
117        let buf: &[u8] = &[
118            0xab, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64,
119        ];
120
121        let mut r = crate::io::SliceReader::new(buf);
122        let decoded = StrDecoder::decode(&mut r).unwrap();
123        let expect = "Hello World";
124        assert_eq!(decoded, expect);
125        assert_eq!(r.rest().len(), 0);
126    }
127
128    #[test]
129    fn decode_invalid_str() {
130        let buf: &[u8] = &[0xa2, 0xc3, 0x28];
131        let mut r = crate::io::SliceReader::new(buf);
132        let err = StrDecoder::decode(&mut r).unwrap_err();
133        assert_eq!(err, Error::InvalidData);
134
135        let buf: &[u8] = &[0xa1, 0x80];
136        let mut r = crate::io::SliceReader::new(buf);
137        let err = StrDecoder::decode(&mut r).unwrap_err();
138        assert_eq!(err, Error::InvalidData);
139    }
140
141    #[cfg(feature = "alloc")]
142    #[test]
143    fn decode_string_owned() {
144        let buf: &[u8] = &[0xa3, b'f', b'o', b'o'];
145        let mut r = crate::io::SliceReader::new(buf);
146        let s = <alloc::string::String as Decode>::decode(&mut r).unwrap();
147        assert_eq!(s.as_str(), "foo");
148        assert!(r.rest().is_empty());
149    }
150}