parse_net/sfv/owned.rs
1//! Owned Structured Field values (`alloc`): one buffer per value, the same
2//! view back.
3//!
4//! # Examples
5//!
6//! ```
7//! use parse_net::sfv::{self, owned::OwnedDictionary, BareItem, Member};
8//!
9//! let owned: OwnedDictionary = {
10//! let input = b"u=1, i".to_vec();
11//! sfv::parse_dictionary(&input)?.to_owned()
12//! };
13//! assert!(matches!(owned.as_view().get("u"), Some(Member::Item(i)) if i.bare == BareItem::Integer(1)));
14//! # Ok::<(), parse_net::ParseError>(())
15//! ```
16
17use alloc::vec::Vec;
18
19use super::{
20 BareItem, ByteSeq, Decimal, Dictionary, DisplayString, Item, List, SfParams, SfString,
21};
22
23/// The scalar part of a bare item; text kinds keep their bytes in a buffer.
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25enum Kind {
26 Integer(i64),
27 Decimal(Decimal),
28 String { escapes: bool },
29 Token,
30 ByteSeq,
31 Boolean(bool),
32 Date(i64),
33 DisplayString,
34}
35
36fn split<'a>(b: &BareItem<'a>) -> (Kind, &'a [u8]) {
37 match *b {
38 BareItem::Integer(i) => (Kind::Integer(i), &[]),
39 BareItem::Decimal(d) => (Kind::Decimal(d), &[]),
40 BareItem::String(s) => (Kind::String { escapes: s.escapes }, s.raw.as_bytes()),
41 BareItem::Token(t) => (Kind::Token, t.as_bytes()),
42 BareItem::ByteSeq(s) => (Kind::ByteSeq, s.raw),
43 BareItem::Boolean(v) => (Kind::Boolean(v), &[]),
44 BareItem::Date(d) => (Kind::Date(d), &[]),
45 BareItem::DisplayString(s) => (Kind::DisplayString, s.raw),
46 }
47}
48
49fn view(kind: Kind, bytes: &[u8]) -> BareItem<'_> {
50 // Text kinds hold ASCII copied from a validated view.
51 let text = core::str::from_utf8(bytes).unwrap_or("");
52 match kind {
53 Kind::Integer(i) => BareItem::Integer(i),
54 Kind::Decimal(d) => BareItem::Decimal(d),
55 Kind::String { escapes } => BareItem::String(SfString { raw: text, escapes }),
56 Kind::Token => BareItem::Token(text),
57 Kind::ByteSeq => BareItem::ByteSeq(ByteSeq { raw: bytes }),
58 Kind::Boolean(v) => BareItem::Boolean(v),
59 Kind::Date(d) => BareItem::Date(d),
60 Kind::DisplayString => BareItem::DisplayString(DisplayString { raw: bytes }),
61 }
62}
63
64/// An owned [`BareItem`].
65///
66/// # Examples
67///
68/// ```
69/// use parse_net::sfv::{self, owned::OwnedBareItem, BareItem};
70///
71/// let owned: OwnedBareItem = {
72/// let input = b"tok".to_vec();
73/// sfv::parse_item(&input)?.bare.to_owned()
74/// };
75/// assert_eq!(owned.as_view(), BareItem::Token("tok"));
76/// # Ok::<(), parse_net::ParseError>(())
77/// ```
78#[derive(Clone, Debug, PartialEq, Eq, Hash)]
79pub struct OwnedBareItem {
80 kind: Kind,
81 buf: Vec<u8>,
82}
83
84impl BareItem<'_> {
85 /// Copies the bare item (one allocation for a text kind, none otherwise).
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use parse_net::sfv::{self, BareItem};
91 ///
92 /// let bare = sfv::parse_item(b"\"hi\"")?.bare;
93 /// assert_eq!(bare.to_owned().as_view(), bare);
94 /// # Ok::<(), parse_net::ParseError>(())
95 /// ```
96 #[must_use]
97 pub fn to_owned(&self) -> OwnedBareItem {
98 let (kind, bytes) = split(self);
99 OwnedBareItem {
100 kind,
101 buf: bytes.to_vec(),
102 }
103 }
104}
105
106impl OwnedBareItem {
107 /// The view over the owned bytes.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// use parse_net::sfv::{self, BareItem};
113 ///
114 /// let owned = BareItem::Integer(9).to_owned();
115 /// assert_eq!(owned.as_view(), BareItem::Integer(9));
116 /// ```
117 #[must_use]
118 pub fn as_view(&self) -> BareItem<'_> {
119 view(self.kind, &self.buf)
120 }
121}
122
123/// An owned [`Item`]: the bare item's bytes and the parameter text in one
124/// buffer.
125///
126/// # Examples
127///
128/// ```
129/// use parse_net::sfv::{self, owned::OwnedItem, BareItem};
130///
131/// let owned: OwnedItem = {
132/// let input = b"tok;v=2".to_vec();
133/// sfv::parse_item(&input)?.to_owned()
134/// };
135/// assert_eq!(owned.as_view().params.get("v"), Some(BareItem::Integer(2)));
136/// # Ok::<(), parse_net::ParseError>(())
137/// ```
138#[derive(Clone, Debug, PartialEq, Eq, Hash)]
139pub struct OwnedItem {
140 kind: Kind,
141 buf: Vec<u8>,
142 split: usize,
143 count: usize,
144}
145
146impl Item<'_> {
147 /// Copies the item (one allocation).
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use parse_net::sfv;
153 ///
154 /// let item = sfv::parse_item(b"a;x=1")?;
155 /// assert_eq!(item.to_owned().as_view(), item);
156 /// # Ok::<(), parse_net::ParseError>(())
157 /// ```
158 #[must_use]
159 pub fn to_owned(&self) -> OwnedItem {
160 let (kind, bytes) = split(&self.bare);
161 let mut buf = Vec::with_capacity(bytes.len() + self.params.text.len());
162 buf.extend_from_slice(bytes);
163 buf.extend_from_slice(self.params.text);
164 OwnedItem {
165 kind,
166 buf,
167 split: bytes.len(),
168 count: self.params.count,
169 }
170 }
171}
172
173impl OwnedItem {
174 /// The view over the owned bytes.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use parse_net::sfv::{self, BareItem};
180 ///
181 /// let owned = sfv::parse_item(b"5;unit=s")?.to_owned();
182 /// let view = owned.as_view();
183 /// assert_eq!(view.bare, BareItem::Integer(5));
184 /// assert_eq!(view.params.get("unit"), Some(BareItem::Token("s")));
185 /// # Ok::<(), parse_net::ParseError>(())
186 /// ```
187 #[must_use]
188 pub fn as_view(&self) -> Item<'_> {
189 let (bare, text) = self.buf.split_at(self.split.min(self.buf.len()));
190 Item {
191 bare: view(self.kind, bare),
192 params: SfParams {
193 text,
194 count: self.count,
195 },
196 }
197 }
198}
199
200/// An owned [`List`].
201///
202/// # Examples
203///
204/// ```
205/// use parse_net::sfv::{self, owned::OwnedList};
206///
207/// let owned: OwnedList = {
208/// let input = b"a, (b c)".to_vec();
209/// sfv::parse_list(&input)?.to_owned()
210/// };
211/// assert_eq!(owned.as_view().len(), 2);
212/// # Ok::<(), parse_net::ParseError>(())
213/// ```
214#[derive(Clone, Debug, PartialEq, Eq, Hash)]
215pub struct OwnedList {
216 text: Vec<u8>,
217 count: usize,
218}
219
220impl List<'_> {
221 /// Copies the list (one allocation).
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// use parse_net::sfv;
227 ///
228 /// let list = sfv::parse_list(b"a, b")?;
229 /// assert_eq!(list.to_owned().as_view(), list);
230 /// # Ok::<(), parse_net::ParseError>(())
231 /// ```
232 #[must_use]
233 pub fn to_owned(&self) -> OwnedList {
234 OwnedList {
235 text: self.text.to_vec(),
236 count: self.count,
237 }
238 }
239}
240
241impl OwnedList {
242 /// The view over the owned bytes.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use parse_net::sfv::{self, BareItem, Member};
248 ///
249 /// let owned = sfv::parse_list(b"1, 2")?.to_owned();
250 /// assert!(matches!(owned.as_view().iter().next(), Some(Member::Item(i)) if i.bare == BareItem::Integer(1)));
251 /// # Ok::<(), parse_net::ParseError>(())
252 /// ```
253 #[must_use]
254 pub fn as_view(&self) -> List<'_> {
255 List {
256 text: &self.text,
257 count: self.count,
258 }
259 }
260}
261
262/// An owned [`Dictionary`].
263///
264/// # Examples
265///
266/// ```
267/// use parse_net::sfv::{self, owned::OwnedDictionary};
268///
269/// let owned: OwnedDictionary = {
270/// let input = b"a=1, b".to_vec();
271/// sfv::parse_dictionary(&input)?.to_owned()
272/// };
273/// assert_eq!(owned.as_view().len(), 2);
274/// # Ok::<(), parse_net::ParseError>(())
275/// ```
276#[derive(Clone, Debug, PartialEq, Eq, Hash)]
277pub struct OwnedDictionary {
278 text: Vec<u8>,
279 count: usize,
280}
281
282impl Dictionary<'_> {
283 /// Copies the dictionary (one allocation).
284 ///
285 /// # Examples
286 ///
287 /// ```
288 /// use parse_net::sfv;
289 ///
290 /// let d = sfv::parse_dictionary(b"a=1, b")?;
291 /// assert_eq!(d.to_owned().as_view(), d);
292 /// # Ok::<(), parse_net::ParseError>(())
293 /// ```
294 #[must_use]
295 pub fn to_owned(&self) -> OwnedDictionary {
296 OwnedDictionary {
297 text: self.text.to_vec(),
298 count: self.count,
299 }
300 }
301}
302
303impl OwnedDictionary {
304 /// The view over the owned bytes.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use parse_net::sfv::{self, BareItem, Member};
310 ///
311 /// let owned = sfv::parse_dictionary(b"q=0.5")?.to_owned();
312 /// assert!(matches!(owned.as_view().get("q"), Some(Member::Item(i)) if i.bare == BareItem::Decimal(sfv::Decimal::from_thousandths(500)?)));
313 /// # Ok::<(), parse_net::ParseError>(())
314 /// ```
315 #[must_use]
316 pub fn as_view(&self) -> Dictionary<'_> {
317 Dictionary {
318 text: &self.text,
319 count: self.count,
320 }
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::super::{parse_dictionary, parse_item, parse_list};
327
328 #[test]
329 fn test_owned_sfv_gives_the_same_view() {
330 for v in [
331 &b"1;a=2"[..],
332 b"\"a\\\"b\";x",
333 b":YQ==:",
334 b"%\"%c3%a9\"",
335 b"?0",
336 b"@1",
337 b"tok;p=1.5",
338 b"-0.5",
339 ] {
340 let i = parse_item(v).unwrap();
341 assert_eq!(i.to_owned().as_view(), i);
342 assert_eq!(i.bare.to_owned().as_view(), i.bare);
343 }
344 let l = parse_list(b"a, (b c);d, \"e\"").unwrap();
345 assert_eq!(l.to_owned().as_view(), l);
346 let d = parse_dictionary(b"a=1, b, c=(x y);q").unwrap();
347 assert_eq!(d.to_owned().as_view(), d);
348 }
349}