rune_core/item/
item_buf.rs

1use core::borrow::Borrow;
2use core::cmp::Ordering;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::mem::take;
6use core::ops::Deref;
7use core::str::FromStr;
8
9use crate::alloc::alloc::{Allocator, Global};
10use crate::alloc::clone::TryClone;
11use crate::alloc::iter::TryFromIteratorIn;
12use crate::alloc::{self, Vec};
13
14use crate::item::{ComponentRef, IntoComponent, Item, Iter};
15
16/// The name of an item in the Rune Language.
17///
18/// This is made up of a collection of strings, like `["foo", "bar"]`.
19/// This is indicated in rune as `foo::bar`.
20///
21/// An item can also belongs to a crate, which in rune could be indicated as
22/// `::crate::foo::bar`. These items must be constructed using
23/// [ItemBuf::with_crate].
24///
25/// Items are inlined if they are smaller than 32 bytes.
26///
27/// # Panics
28///
29/// The max length of a string component is is 2**14 = 16384. Attempting to add
30/// a string larger than that will panic. This also constitutes the maximum
31/// number of *nested* sibling components that can exist in a single source file
32/// since they all use anonymous identifiers.
33///
34/// # Component encoding
35///
36/// The following details internal implementation details of an [`Item`], and is
37/// not exposed through its API. It is provided here in case you need to work
38/// with the internal of an item.
39///
40/// A single component is encoded as:
41///
42/// * A two byte tag as a u16 in native endianess, indicating its type (least
43///   significant 2 bits) and data (most significant 14 bits).
44/// * If the type is a `STRING`, the data is treated as the length of the
45///   string. Any other type this the `data` is treated as the numeric id of the
46///   component.
47/// * If the type is a `STRING`, the tag is repeated at the end of it to allow
48///   for seeking backwards. This is *not* the case for other types. Since they
49///   are fixed size its not necessary.
50///
51/// So all in all, a string is encoded as this where the `d` part indicates the
52/// length of the string:
53///
54/// ```text
55/// dddddddd ddddddtt *string content* dddddddd ddddddtt
56/// ```
57///
58/// And any other component is just the two bytes where the `d` part makes up a
59/// numerical component:
60///
61/// ```text
62/// dddddddd ddddddtt
63/// ```
64#[repr(transparent)]
65pub struct ItemBuf<A = Global>
66where
67    A: Allocator,
68{
69    content: Vec<u8, A>,
70}
71
72impl<A> ItemBuf<A>
73where
74    A: Allocator,
75{
76    /// Construct a new item buffer inside of the given allocator.
77    #[inline]
78    pub(crate) const fn new_in(alloc: A) -> Self {
79        Self {
80            content: Vec::new_in(alloc),
81        }
82    }
83
84    /// Internal raw constructor for an item.
85    ///
86    /// # Safety
87    ///
88    /// Caller must ensure that its representation is valid.
89    #[inline]
90    pub(super) const unsafe fn from_raw(content: Vec<u8, A>) -> Self {
91        Self { content }
92    }
93
94    /// Construct a new item with the given path in the given allocator.
95    #[inline]
96    pub(crate) fn with_item_in(
97        iter: impl IntoIterator<Item: IntoComponent>,
98        alloc: A,
99    ) -> alloc::Result<Self> {
100        let mut content = Vec::new_in(alloc);
101
102        for c in iter {
103            c.write_component(&mut content)?;
104        }
105
106        Ok(Self { content })
107    }
108
109    /// Push the given component to the current item.
110    #[inline]
111    pub fn push(&mut self, c: impl IntoComponent) -> alloc::Result<()> {
112        c.write_component(&mut self.content)?;
113        Ok(())
114    }
115
116    /// Pop a the tail component, returning `true` if there was something to pop.
117    pub fn pop(&mut self) -> bool {
118        let mut it = self.iter();
119
120        if it.next_back().is_none() {
121            return false;
122        };
123
124        let new_len = it.len();
125
126        // SAFETY: Advancing the back end of the iterator ensures that the new
127        // length is smaller than the original, and an item buffer is a byte
128        // array which does not need to be dropped.
129        unsafe {
130            debug_assert!(new_len < self.content.len());
131            self.content.set_len(new_len);
132        }
133
134        true
135    }
136
137    /// Extend the current item with an iterator.
138    #[inline]
139    pub fn extend(&mut self, iter: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<()> {
140        for c in iter {
141            self.push(c)?;
142        }
143
144        Ok(())
145    }
146
147    /// Clear the current item.
148    #[inline]
149    pub fn clear(&mut self) {
150        self.content.clear();
151    }
152}
153
154impl ItemBuf {
155    /// Construct a new empty item.
156    ///
157    /// # Examples
158    ///
159    /// ```
160    /// use rune::ItemBuf;
161    ///
162    /// let item = ItemBuf::new();
163    /// let mut it = item.iter();
164    ///
165    /// assert_eq!(it.next(), None);
166    /// ```
167    pub const fn new() -> Self {
168        Self {
169            content: Vec::new(),
170        }
171    }
172
173    /// Construct a new item with the given path.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// use rune::ItemBuf;
179    /// use rune::item::ComponentRef;
180    ///
181    /// let item = ItemBuf::with_item(["foo", "bar"])?;
182    /// let mut it = item.iter();
183    ///
184    /// assert_eq!(it.next(), Some(ComponentRef::Str("foo")));
185    /// assert_eq!(it.next(), Some(ComponentRef::Str("bar")));
186    /// assert_eq!(it.next(), None);
187    /// # Ok::<(), rune::support::Error>(())
188    /// ```
189    pub fn with_item(iter: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<Self> {
190        Self::with_item_in(iter, Global)
191    }
192
193    /// Construct item for a crate.
194    ///
195    /// # Examples
196    ///
197    /// ```
198    /// use rune::ItemBuf;
199    /// use rune::item::ComponentRef;
200    ///
201    /// let mut item = ItemBuf::with_crate("std")?;
202    /// item.push("foo");
203    /// assert_eq!(item.as_crate(), Some("std"));
204    ///
205    /// let mut it = item.iter();
206    /// assert_eq!(it.next(), Some(ComponentRef::Crate("std")));
207    /// assert_eq!(it.next(), Some(ComponentRef::Str("foo")));
208    /// assert_eq!(it.next(), None);
209    /// # Ok::<(), rune::support::Error>(())
210    /// ```
211    pub fn with_crate(name: &str) -> alloc::Result<Self> {
212        Self::with_item(&[ComponentRef::Crate(name)])
213    }
214
215    /// Create a crated item with the given name.
216    ///
217    /// # Examples
218    ///
219    /// ```
220    /// use rune::ItemBuf;
221    /// use rune::item::ComponentRef;
222    ///
223    /// let item = ItemBuf::with_crate_item("std", ["option"])?;
224    /// assert_eq!(item.as_crate(), Some("std"));
225    ///
226    /// let mut it = item.iter();
227    /// assert_eq!(it.next(), Some(ComponentRef::Crate("std")));
228    /// assert_eq!(it.next(), Some(ComponentRef::Str("option")));
229    /// assert_eq!(it.next(), None);
230    /// # Ok::<(), rune::support::Error>(())
231    /// ```
232    #[inline]
233    pub fn with_crate_item(
234        name: &str,
235        iter: impl IntoIterator<Item: IntoComponent>,
236    ) -> alloc::Result<Self> {
237        let mut content = Vec::new();
238        ComponentRef::Crate(name).write_component(&mut content)?;
239
240        for c in iter {
241            c.write_component(&mut content)?;
242        }
243
244        Ok(Self { content })
245    }
246}
247
248impl<A> Default for ItemBuf<A>
249where
250    A: Allocator + Default,
251{
252    #[inline]
253    fn default() -> Self {
254        Self {
255            content: Vec::new_in(A::default()),
256        }
257    }
258}
259
260impl<A> PartialEq for ItemBuf<A>
261where
262    A: Allocator,
263{
264    #[inline]
265    fn eq(&self, other: &Self) -> bool {
266        self.content == other.content
267    }
268}
269
270impl<A> Eq for ItemBuf<A> where A: Allocator {}
271
272impl<A> PartialOrd for ItemBuf<A>
273where
274    A: Allocator,
275{
276    #[inline]
277    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
278        Some(self.cmp(other))
279    }
280}
281
282impl<A> Ord for ItemBuf<A>
283where
284    A: Allocator,
285{
286    #[inline]
287    fn cmp(&self, other: &Self) -> Ordering {
288        self.content.cmp(&other.content)
289    }
290}
291
292impl<A> Hash for ItemBuf<A>
293where
294    A: Allocator,
295{
296    #[inline]
297    fn hash<H>(&self, state: &mut H)
298    where
299        H: Hasher,
300    {
301        self.content.hash(state);
302    }
303}
304
305impl<A> TryClone for ItemBuf<A>
306where
307    A: Allocator + Clone,
308{
309    #[inline]
310    fn try_clone(&self) -> alloc::Result<Self> {
311        Ok(Self {
312            content: self.content.try_clone()?,
313        })
314    }
315}
316
317impl<A> AsRef<Item> for ItemBuf<A>
318where
319    A: Allocator,
320{
321    #[inline]
322    fn as_ref(&self) -> &Item {
323        self
324    }
325}
326
327impl<A> Borrow<Item> for ItemBuf<A>
328where
329    A: Allocator,
330{
331    #[inline]
332    fn borrow(&self) -> &Item {
333        self
334    }
335}
336
337impl<C, A> TryFromIteratorIn<C, A> for ItemBuf<A>
338where
339    C: IntoComponent,
340    A: Allocator,
341{
342    #[inline]
343    fn try_from_iter_in<T: IntoIterator<Item = C>>(iter: T, alloc: A) -> alloc::Result<Self> {
344        Self::with_item_in(iter, alloc)
345    }
346}
347
348impl<A> Deref for ItemBuf<A>
349where
350    A: Allocator,
351{
352    type Target = Item;
353
354    #[inline]
355    fn deref(&self) -> &Self::Target {
356        // SAFETY: Item ensures that content is valid.
357        unsafe { Item::from_bytes(self.content.as_ref()) }
358    }
359}
360
361/// Format implementation for an [ItemBuf], defers to [Item].
362impl<A> fmt::Display for ItemBuf<A>
363where
364    A: Allocator,
365{
366    #[inline]
367    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368        Item::fmt(self, f)
369    }
370}
371
372impl<A> fmt::Debug for ItemBuf<A>
373where
374    A: Allocator,
375{
376    #[inline]
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378        Item::fmt(self, f)
379    }
380}
381
382impl<'a, A> IntoIterator for &'a ItemBuf<A>
383where
384    A: Allocator,
385{
386    type IntoIter = Iter<'a>;
387    type Item = ComponentRef<'a>;
388
389    #[inline]
390    fn into_iter(self) -> Self::IntoIter {
391        self.iter()
392    }
393}
394
395impl<A> PartialEq<Item> for ItemBuf<A>
396where
397    A: Allocator,
398{
399    #[inline]
400    fn eq(&self, other: &Item) -> bool {
401        self.content.as_slice() == other.as_bytes()
402    }
403}
404
405impl<A> PartialEq<Item> for &ItemBuf<A>
406where
407    A: Allocator,
408{
409    #[inline]
410    fn eq(&self, other: &Item) -> bool {
411        self.content.as_slice() == other.as_bytes()
412    }
413}
414
415impl<A> PartialEq<&Item> for ItemBuf<A>
416where
417    A: Allocator,
418{
419    #[inline]
420    fn eq(&self, other: &&Item) -> bool {
421        self.content.as_slice() == other.as_bytes()
422    }
423}
424
425impl<A> PartialEq<Iter<'_>> for ItemBuf<A>
426where
427    A: Allocator,
428{
429    #[inline]
430    fn eq(&self, other: &Iter<'_>) -> bool {
431        self == other.as_item()
432    }
433}
434
435impl<A> PartialEq<Iter<'_>> for &ItemBuf<A>
436where
437    A: Allocator,
438{
439    #[inline]
440    fn eq(&self, other: &Iter<'_>) -> bool {
441        *self == other.as_item()
442    }
443}
444
445/// Error when parsing an item.
446#[derive(Debug)]
447#[non_exhaustive]
448pub struct FromStrError {
449    kind: FromStrErrorKind,
450}
451
452impl From<alloc::Error> for FromStrError {
453    #[inline]
454    fn from(error: alloc::Error) -> Self {
455        Self {
456            kind: FromStrErrorKind::AllocError(error),
457        }
458    }
459}
460
461impl From<FromStrErrorKind> for FromStrError {
462    #[inline]
463    fn from(kind: FromStrErrorKind) -> Self {
464        Self { kind }
465    }
466}
467
468#[derive(Debug)]
469enum FromStrErrorKind {
470    /// Error during parse.
471    ParseError,
472    /// An error occured when allocating.
473    AllocError(alloc::Error),
474}
475
476impl fmt::Display for FromStrError {
477    #[inline]
478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        match &self.kind {
480            FromStrErrorKind::ParseError => write!(f, "String is not a valid item"),
481            FromStrErrorKind::AllocError(error) => error.fmt(f),
482        }
483    }
484}
485
486impl core::error::Error for FromStrError {}
487
488impl<A> FromStr for ItemBuf<A>
489where
490    A: Allocator + Default,
491{
492    type Err = FromStrError;
493
494    fn from_str(s: &str) -> Result<Self, Self::Err> {
495        let mut item = ItemBuf::new_in(A::default());
496
497        let (s, mut next_crate) = if let Some(remainder) = s.strip_prefix("::") {
498            (remainder, true)
499        } else {
500            (s, false)
501        };
502
503        for c in s.split("::") {
504            if take(&mut next_crate) {
505                item.push(ComponentRef::Crate(c))?;
506            } else if let Some(num) = c.strip_prefix('$') {
507                item.push(ComponentRef::Id(
508                    num.parse().map_err(|_| FromStrErrorKind::ParseError)?,
509                ))?;
510            } else {
511                item.push(ComponentRef::Str(c))?;
512            }
513        }
514
515        Ok(item)
516    }
517}