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: Allocator = Global> {
66    content: Vec<u8, A>,
67}
68
69impl<A: Allocator> ItemBuf<A> {
70    /// Construct a new item buffer inside of the given allocator.
71    pub(crate) const fn new_in(alloc: A) -> Self {
72        Self {
73            content: Vec::new_in(alloc),
74        }
75    }
76
77    /// Internal raw constructor for an item.
78    ///
79    /// # Safety
80    ///
81    /// Caller must ensure that its representation is valid.
82    pub(super) const unsafe fn from_raw(content: Vec<u8, A>) -> Self {
83        Self { content }
84    }
85
86    /// Construct a new item with the given path in the given allocator.
87    pub(crate) fn with_item_in(
88        iter: impl IntoIterator<Item: IntoComponent>,
89        alloc: A,
90    ) -> alloc::Result<Self> {
91        let mut content = Vec::new_in(alloc);
92
93        for c in iter {
94            c.write_component(&mut content)?;
95        }
96
97        Ok(Self { content })
98    }
99
100    /// Push the given component to the current item.
101    pub fn push<C>(&mut self, c: C) -> alloc::Result<()>
102    where
103        C: IntoComponent,
104    {
105        c.write_component(&mut self.content)?;
106        Ok(())
107    }
108
109    /// Pop a the tail component, returning `true` if there was something to pop.
110    pub fn pop(&mut self) -> bool {
111        let mut it = self.iter();
112
113        if it.next_back().is_none() {
114            return false;
115        };
116
117        let new_len = it.len();
118
119        // SAFETY: Advancing the back end of the iterator ensures that the new
120        // length is smaller than the original, and an item buffer is a byte
121        // array which does not need to be dropped.
122        unsafe {
123            debug_assert!(new_len < self.content.len());
124            self.content.set_len(new_len);
125        }
126
127        true
128    }
129
130    /// Extend the current item with an iterator.
131    pub fn extend<I>(&mut self, i: I) -> alloc::Result<()>
132    where
133        I: IntoIterator,
134        I::Item: IntoComponent,
135    {
136        for c in i {
137            self.push(c)?;
138        }
139
140        Ok(())
141    }
142
143    /// Clear the current item.
144    pub fn clear(&mut self) {
145        self.content.clear();
146    }
147}
148
149impl ItemBuf {
150    /// Construct a new empty item.
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// use rune::ItemBuf;
156    ///
157    /// let item = ItemBuf::new();
158    /// let mut it = item.iter();
159    ///
160    /// assert_eq!(it.next(), None);
161    /// ```
162    pub const fn new() -> Self {
163        Self {
164            content: Vec::new(),
165        }
166    }
167
168    /// Construct a new item with the given path.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// use rune::ItemBuf;
174    /// use rune::item::ComponentRef;
175    ///
176    /// let item = ItemBuf::with_item(["foo", "bar"])?;
177    /// let mut it = item.iter();
178    ///
179    /// assert_eq!(it.next(), Some(ComponentRef::Str("foo")));
180    /// assert_eq!(it.next(), Some(ComponentRef::Str("bar")));
181    /// assert_eq!(it.next(), None);
182    /// # Ok::<(), rune::support::Error>(())
183    /// ```
184    pub fn with_item(iter: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<Self> {
185        Self::with_item_in(iter, Global)
186    }
187
188    /// Construct item for a crate.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use rune::ItemBuf;
194    /// use rune::item::ComponentRef;
195    ///
196    /// let mut item = ItemBuf::with_crate("std")?;
197    /// item.push("foo");
198    /// assert_eq!(item.as_crate(), Some("std"));
199    ///
200    /// let mut it = item.iter();
201    /// assert_eq!(it.next(), Some(ComponentRef::Crate("std")));
202    /// assert_eq!(it.next(), Some(ComponentRef::Str("foo")));
203    /// assert_eq!(it.next(), None);
204    /// # Ok::<(), rune::support::Error>(())
205    /// ```
206    pub fn with_crate(name: &str) -> alloc::Result<Self> {
207        Self::with_item(&[ComponentRef::Crate(name)])
208    }
209
210    /// Create a crated item with the given name.
211    ///
212    /// # Examples
213    ///
214    /// ```
215    /// use rune::ItemBuf;
216    /// use rune::item::ComponentRef;
217    ///
218    /// let item = ItemBuf::with_crate_item("std", ["option"])?;
219    /// assert_eq!(item.as_crate(), Some("std"));
220    ///
221    /// let mut it = item.iter();
222    /// assert_eq!(it.next(), Some(ComponentRef::Crate("std")));
223    /// assert_eq!(it.next(), Some(ComponentRef::Str("option")));
224    /// assert_eq!(it.next(), None);
225    /// # Ok::<(), rune::support::Error>(())
226    /// ```
227    pub fn with_crate_item<I>(name: &str, iter: I) -> alloc::Result<Self>
228    where
229        I: IntoIterator,
230        I::Item: IntoComponent,
231    {
232        let mut content = Vec::new();
233        ComponentRef::Crate(name).write_component(&mut content)?;
234
235        for c in iter {
236            c.write_component(&mut content)?;
237        }
238
239        Ok(Self { content })
240    }
241}
242
243impl<A: Allocator> Default for ItemBuf<A>
244where
245    A: Default,
246{
247    fn default() -> Self {
248        Self {
249            content: Vec::new_in(A::default()),
250        }
251    }
252}
253
254impl<A: Allocator> PartialEq for ItemBuf<A> {
255    #[inline]
256    fn eq(&self, other: &Self) -> bool {
257        self.content == other.content
258    }
259}
260
261impl<A: Allocator> Eq for ItemBuf<A> {}
262
263impl<A: Allocator> PartialOrd for ItemBuf<A> {
264    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
265        Some(self.content.cmp(&other.content))
266    }
267}
268
269impl<A: Allocator> Ord for ItemBuf<A> {
270    fn cmp(&self, other: &Self) -> Ordering {
271        self.content.cmp(&other.content)
272    }
273}
274
275impl<A: Allocator> Hash for ItemBuf<A> {
276    fn hash<H: Hasher>(&self, state: &mut H) {
277        self.content.hash(state);
278    }
279}
280
281impl<A: Allocator + Clone> TryClone for ItemBuf<A> {
282    #[inline]
283    fn try_clone(&self) -> alloc::Result<Self> {
284        Ok(Self {
285            content: self.content.try_clone()?,
286        })
287    }
288}
289
290impl<A: Allocator> AsRef<Item> for ItemBuf<A> {
291    #[inline]
292    fn as_ref(&self) -> &Item {
293        self
294    }
295}
296
297impl<A: Allocator> Borrow<Item> for ItemBuf<A> {
298    #[inline]
299    fn borrow(&self) -> &Item {
300        self
301    }
302}
303
304impl<C, A: Allocator> TryFromIteratorIn<C, A> for ItemBuf<A>
305where
306    C: IntoComponent,
307{
308    #[inline]
309    fn try_from_iter_in<T: IntoIterator<Item = C>>(iter: T, alloc: A) -> alloc::Result<Self> {
310        Self::with_item_in(iter, alloc)
311    }
312}
313
314impl<A: Allocator> Deref for ItemBuf<A> {
315    type Target = Item;
316
317    fn deref(&self) -> &Self::Target {
318        // SAFETY: Item ensures that content is valid.
319        unsafe { Item::from_bytes(self.content.as_ref()) }
320    }
321}
322
323/// Format implementation for an [ItemBuf], defers to [Item].
324impl<A: Allocator> fmt::Display for ItemBuf<A> {
325    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326        Item::fmt(self, f)
327    }
328}
329
330impl<A: Allocator> fmt::Debug for ItemBuf<A> {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        Item::fmt(self, f)
333    }
334}
335
336impl<'a, A: Allocator> IntoIterator for &'a ItemBuf<A> {
337    type IntoIter = Iter<'a>;
338    type Item = ComponentRef<'a>;
339
340    fn into_iter(self) -> Self::IntoIter {
341        self.iter()
342    }
343}
344
345impl<A: Allocator> PartialEq<Item> for ItemBuf<A> {
346    fn eq(&self, other: &Item) -> bool {
347        self.content.as_slice() == other.as_bytes()
348    }
349}
350
351impl<A: Allocator> PartialEq<Item> for &ItemBuf<A> {
352    fn eq(&self, other: &Item) -> bool {
353        self.content.as_slice() == other.as_bytes()
354    }
355}
356
357impl<A: Allocator> PartialEq<&Item> for ItemBuf<A> {
358    fn eq(&self, other: &&Item) -> bool {
359        self.content.as_slice() == other.as_bytes()
360    }
361}
362
363impl<A: Allocator> PartialEq<Iter<'_>> for ItemBuf<A> {
364    fn eq(&self, other: &Iter<'_>) -> bool {
365        self == other.as_item()
366    }
367}
368
369impl<A: Allocator> PartialEq<Iter<'_>> for &ItemBuf<A> {
370    fn eq(&self, other: &Iter<'_>) -> bool {
371        *self == other.as_item()
372    }
373}
374
375/// Error when parsing an item.
376#[derive(Debug)]
377#[non_exhaustive]
378pub struct FromStrError {
379    kind: FromStrErrorKind,
380}
381
382impl From<alloc::Error> for FromStrError {
383    fn from(error: alloc::Error) -> Self {
384        Self {
385            kind: FromStrErrorKind::AllocError(error),
386        }
387    }
388}
389
390impl From<FromStrErrorKind> for FromStrError {
391    fn from(kind: FromStrErrorKind) -> Self {
392        Self { kind }
393    }
394}
395
396#[derive(Debug)]
397enum FromStrErrorKind {
398    /// Error during parse.
399    ParseError,
400    /// An error occured when allocating.
401    AllocError(alloc::Error),
402}
403
404impl fmt::Display for FromStrError {
405    #[inline]
406    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407        match &self.kind {
408            FromStrErrorKind::ParseError => write!(f, "String is not a valid item"),
409            FromStrErrorKind::AllocError(error) => error.fmt(f),
410        }
411    }
412}
413
414impl core::error::Error for FromStrError {}
415
416impl<A: Allocator> FromStr for ItemBuf<A>
417where
418    A: Default,
419{
420    type Err = FromStrError;
421
422    fn from_str(s: &str) -> Result<Self, Self::Err> {
423        let mut item = ItemBuf::new_in(A::default());
424
425        let (s, mut next_crate) = if let Some(remainder) = s.strip_prefix("::") {
426            (remainder, true)
427        } else {
428            (s, false)
429        };
430
431        for c in s.split("::") {
432            if take(&mut next_crate) {
433                item.push(ComponentRef::Crate(c))?;
434            } else if let Some(num) = c.strip_prefix('$') {
435                item.push(ComponentRef::Id(
436                    num.parse().map_err(|_| FromStrErrorKind::ParseError)?,
437                ))?;
438            } else {
439                item.push(ComponentRef::Str(c))?;
440            }
441        }
442
443        Ok(item)
444    }
445}