lilliput_core/decoder/
string.rs1use std::ops::Range;
2
3use crate::{
4 error::{Error, Result},
5 header::StringHeader,
6 io::{Read, Reference},
7 marker::Marker,
8 value::StringValue,
9};
10
11use super::Decoder;
12
13impl<'de, R> Decoder<R>
14where
15 R: Read<'de>,
16{
17 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
21 pub fn decode_str<'s>(
22 &'s mut self,
23 scratch: &'s mut Vec<u8>,
24 ) -> Result<Reference<'de, 's, str>> {
25 let header = self.decode_string_header()?;
26 self.decode_str_of(header, scratch)
27 }
28
29 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
31 pub fn decode_str_bytes<'s>(
32 &'s mut self,
33 scratch: &'s mut Vec<u8>,
34 ) -> Result<Reference<'de, 's, [u8]>> {
35 let header = self.decode_string_header()?;
36 self.decode_str_bytes_of(header, scratch)
37 }
38
39 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
41 pub fn decode_string(&mut self) -> Result<String> {
42 let header = self.decode_string_header()?;
43 self.decode_string_of(header)
44 }
45
46 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
48 pub fn decode_string_bytes_buf(&mut self) -> Result<Vec<u8>> {
49 let header = self.decode_string_header()?;
50 self.decode_string_bytes_buf_of(header)
51 }
52
53 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
55 pub fn decode_string_value(&mut self) -> Result<StringValue> {
56 let header = self.decode_string_header()?;
57 self.decode_string_value_of(header)
58 }
59
60 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
64 pub fn decode_string_header(&mut self) -> Result<StringHeader> {
65 let byte = self.pull_byte_expecting(Marker::String)?;
66
67 let is_compact = (byte & StringHeader::COMPACT_VARIANT_BIT) != 0b0;
68
69 if is_compact {
70 let len = byte & StringHeader::COMPACT_LEN_BITS;
71
72 #[cfg(feature = "tracing")]
73 tracing::debug!(
74 byte = crate::binary::fmt_byte(byte),
75 is_compact = true,
76 len = len
77 );
78
79 Ok(StringHeader::compact(len))
80 } else {
81 let len_width = 1 + (byte & StringHeader::EXTENDED_LEN_WIDTH_BITS);
82 let len = self.pull_len_bytes(len_width)?;
83
84 #[cfg(feature = "tracing")]
85 tracing::debug!(
86 byte = crate::binary::fmt_byte(byte),
87 is_compact = false,
88 len = len
89 );
90
91 Ok(StringHeader::extended(len))
92 }
93 }
94
95 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
99 pub fn skip_string_value_of(&mut self, header: StringHeader) -> Result<()> {
100 let len: usize = match header {
101 StringHeader::Compact(header) => header.len().into(),
102 StringHeader::Extended(header) => header.len(),
103 };
104
105 self.reader.skip(len)
106 }
107
108 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
112 pub fn decode_string_value_of(&mut self, header: StringHeader) -> Result<StringValue> {
113 self.decode_string_of(header).map(From::from)
114 }
115
116 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
119 fn decode_str_of<'s>(
120 &'s mut self,
121 header: StringHeader,
122 scratch: &'s mut Vec<u8>,
123 ) -> Result<Reference<'de, 's, str>> {
124 let (bytes, range) = self.decode_str_bytes_and_range_of(header, scratch)?;
125
126 let str_ref = match bytes {
127 Reference::Borrowed(bytes) => std::str::from_utf8(bytes).map(Reference::Borrowed),
128 Reference::Copied(bytes) => std::str::from_utf8(bytes).map(Reference::Copied),
129 }
130 .map_err(|err| {
131 let pos = range.start + err.valid_up_to() + 1;
132 Error::utf8(err, Some(pos))
133 })?;
134
135 Ok(str_ref)
136 }
137
138 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
139 fn decode_str_bytes_of<'s>(
140 &'s mut self,
141 header: StringHeader,
142 scratch: &'s mut Vec<u8>,
143 ) -> Result<Reference<'de, 's, [u8]>> {
144 Ok(self.decode_str_bytes_and_range_of(header, scratch)?.0)
145 }
146
147 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
148 fn decode_string_of(&mut self, header: StringHeader) -> Result<String> {
149 let (bytes_buf, range) = self.decode_string_bytes_buf_and_range_of(header)?;
150
151 let string = String::from_utf8(bytes_buf).map_err(|err| {
152 let err = err.utf8_error();
153 let pos = range.start + err.valid_up_to() + 1;
154 Error::utf8(err, Some(pos))
155 })?;
156
157 Ok(string)
158 }
159
160 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
161 fn decode_string_bytes_buf_of(&mut self, header: StringHeader) -> Result<Vec<u8>> {
162 Ok(self.decode_string_bytes_buf_and_range_of(header)?.0)
163 }
164
165 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
166 fn decode_string_bytes_buf_and_range_of(
167 &mut self,
168 header: StringHeader,
169 ) -> Result<(Vec<u8>, Range<usize>)> {
170 let mut buf = Vec::new();
171
172 let (bytes, range) = self.decode_str_bytes_and_range_of(header, &mut buf)?;
173
174 match bytes {
175 Reference::Borrowed(slice) => {
176 debug_assert_eq!(buf.len(), 0);
177 buf.extend_from_slice(slice);
178 }
179 Reference::Copied(slice) => {
180 debug_assert_eq!(slice.len(), buf.len());
181 }
182 }
183
184 Ok((buf, range))
185 }
186
187 #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
188 fn decode_str_bytes_and_range_of<'s>(
189 &'s mut self,
190 header: StringHeader,
191 scratch: &'s mut Vec<u8>,
192 ) -> Result<(Reference<'de, 's, [u8]>, Range<usize>)> {
193 scratch.clear();
194
195 let start = self.pos;
196 let bytes = self.pull_bytes(header.len(), scratch)?;
197 let range = start..(start + bytes.len());
198
199 Ok((bytes, range))
200 }
201}