Skip to main content

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}