lilliput_core/decoder/
string.rs

1use 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    // MARK: - Value
18
19    /// Decodes a string value, as a reference.
20    #[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    /// Decodes a string value's raw-bytes, as a reference.
30    #[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    /// Decodes a string value, as an owned string.
40    #[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    /// Decodes a string value's raw-bytes, as an owned buffer.
47    #[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    /// Decodes a string value, as a `StringValue`.
54    #[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    // MARK: - Header
61
62    /// Decodes a string value's header.
63    #[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    // MARK: - Skip
96
97    /// Skips the map value for a given `header`.
98    #[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    // MARK: - Body
109
110    /// Decodes map value for a given `header`, as a `MapValue`.
111    #[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    // MARK: - Private
117
118    #[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}