1use super::{DecodeBorrowed, Error, NbyteReader};
4use crate::{Decode, formats::Format, io::IoRead};
5
6pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
43pub enum ReferenceStr<'de, 'a> {
44 Borrowed(&'de str),
46 Copied(&'a str),
48}
49
50impl ReferenceStr<'_, '_> {
51 pub const fn as_str(&self) -> &str {
53 match self {
54 ReferenceStr::Borrowed(s) => s,
55 ReferenceStr::Copied(s) => s,
56 }
57 }
58}
59
60impl PartialEq<str> for ReferenceStr<'_, '_> {
61 fn eq(&self, other: &str) -> bool {
62 self.as_str() == other
63 }
64}
65
66impl PartialEq<ReferenceStr<'_, '_>> for str {
67 fn eq(&self, other: &ReferenceStr<'_, '_>) -> bool {
68 other.as_str() == self
69 }
70}
71
72pub struct ReferenceStrDecoder;
74
75impl<'de> Decode<'de> for ReferenceStrDecoder {
76 type Value<'a>
77 = ReferenceStr<'de, 'a>
78 where
79 Self: 'a,
80 'de: 'a;
81 fn decode_with_format<'a, R>(
82 format: Format,
83 reader: &'a mut R,
84 ) -> Result<Self::Value<'a>, Error<R::Error>>
85 where
86 R: IoRead<'de>,
87 'de: 'a,
88 {
89 let len = match format {
90 Format::FixStr(n) => n.into(),
91 Format::Str8 => NbyteReader::<1>::read(reader)?,
92 Format::Str16 => NbyteReader::<2>::read(reader)?,
93 Format::Str32 => NbyteReader::<4>::read(reader)?,
94 _ => return Err(Error::UnexpectedFormat),
95 };
96 let data = reader.read_slice(len).map_err(Error::Io)?;
97 match data {
98 crate::io::Reference::Borrowed(items) => {
99 let s = str::from_utf8(items).map_err(|_| Error::InvalidData)?;
100 Ok(ReferenceStr::Borrowed(s))
101 }
102 crate::io::Reference::Copied(items) => {
103 let s = str::from_utf8(items).map_err(|_| Error::InvalidData)?;
104 Ok(ReferenceStr::Copied(s))
105 }
106 }
107 }
108}
109
110pub struct ReferenceStrBinDecoder;
113
114impl<'de> Decode<'de> for ReferenceStrBinDecoder {
115 type Value<'a>
116 = crate::io::Reference<'de, 'a>
117 where
118 Self: 'a,
119 'de: 'a;
120
121 fn decode_with_format<'a, R>(
122 format: Format,
123 reader: &'a mut R,
124 ) -> Result<Self::Value<'a>, Error<R::Error>>
125 where
126 R: IoRead<'de>,
127 'de: 'a,
128 {
129 let len = match format {
130 Format::FixStr(n) => n.into(),
131 Format::Str8 => NbyteReader::<1>::read(reader)?,
132 Format::Str16 => NbyteReader::<2>::read(reader)?,
133 Format::Str32 => NbyteReader::<4>::read(reader)?,
134 _ => return Err(Error::UnexpectedFormat),
135 };
136 reader.read_slice(len).map_err(Error::Io)
137 }
138}
139
140#[cfg(feature = "alloc")]
141mod alloc_impl {
142 use super::*;
143 impl<'de> DecodeBorrowed<'de> for alloc::string::String {
144 type Value = alloc::string::String;
145
146 fn decode_borrowed_with_format<R>(
147 format: Format,
148 reader: &mut R,
149 ) -> core::result::Result<Self::Value, Error<R::Error>>
150 where
151 R: IoRead<'de>,
152 {
153 let sref = ReferenceStrDecoder::decode_with_format(format, reader)?;
154 let owned = match sref {
155 ReferenceStr::Borrowed(s) => alloc::string::String::from(s),
156 ReferenceStr::Copied(s) => alloc::string::String::from(s),
157 };
158 Ok(owned)
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use crate::decode::Decode;
167
168 #[test]
169 fn decode_str() {
170 let buf: &[u8] = &[
171 0xab, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64,
172 ];
173
174 let mut r = crate::io::SliceReader::new(buf);
175 let decoded = StrDecoder::decode(&mut r).unwrap();
176 let expect = "Hello World";
177 assert_eq!(decoded, expect);
178 assert_eq!(r.rest().len(), 0);
179 }
180
181 #[test]
182 fn decode_invalid_str() {
183 let buf: &[u8] = &[0xa2, 0xc3, 0x28];
184 let mut r = crate::io::SliceReader::new(buf);
185 let err = StrDecoder::decode(&mut r).unwrap_err();
186 assert_eq!(err, Error::InvalidData);
187
188 let buf: &[u8] = &[0xa1, 0x80];
189 let mut r = crate::io::SliceReader::new(buf);
190 let err = StrDecoder::decode(&mut r).unwrap_err();
191 assert_eq!(err, Error::InvalidData);
192 }
193
194 #[cfg(feature = "alloc")]
195 #[test]
196 fn decode_string_owned() {
197 let buf: &[u8] = &[0xa3, b'f', b'o', b'o'];
198 let mut r = crate::io::SliceReader::new(buf);
199 let s = <alloc::string::String as Decode>::decode(&mut r).unwrap();
200 assert_eq!(s.as_str(), "foo");
201 assert!(r.rest().is_empty());
202 }
203}