rune_core/item/
item.rs

1use core::fmt;
2
3#[cfg(feature = "alloc")]
4use crate::alloc::borrow::TryToOwned;
5#[cfg(feature = "alloc")]
6use crate::alloc::iter::IteratorExt;
7#[cfg(feature = "alloc")]
8use crate::alloc::{self, Vec};
9
10#[cfg(feature = "alloc")]
11use crate::item::Component;
12use crate::item::{ComponentRef, IntoComponent, ItemBuf, Iter};
13
14/// The reference to an [ItemBuf].
15#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(transparent)]
17pub struct Item {
18    content: [u8],
19}
20
21impl Item {
22    /// Construct an [Item] corresponding to the root item.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use rune::{Item, ItemBuf};
28    ///
29    /// assert_eq!(Item::new(), &*ItemBuf::new());
30    /// ```
31    #[inline]
32    pub const fn new() -> &'static Self {
33        // SAFETY: an empty slice is a valid bit pattern for the root.
34        unsafe { Self::from_bytes(&[]) }
35    }
36
37    /// Construct an [Item] from an [ItemBuf].
38    ///
39    /// # Safety
40    ///
41    /// Caller must ensure that content has a valid [ItemBuf] representation.
42    /// The easiest way to accomplish this is to use the `rune::item!` macro.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use rune::{Item, ItemBuf};
48    ///
49    /// let item = ItemBuf::with_item(["foo", "bar"])?;
50    ///
51    /// // SAFETY: item is constructed from a valid buffer.
52    /// let item = unsafe { Item::from_bytes(item.as_bytes()) };
53    /// # Ok::<_, rune::alloc::Error>(())
54    /// ```
55    pub const unsafe fn from_bytes(content: &[u8]) -> &Self {
56        &*(content as *const _ as *const _)
57    }
58
59    /// Return the underlying byte representation of the [Item].
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// use rune::{Item, ItemBuf};
65    ///
66    /// assert_eq!(Item::new().as_bytes(), b"");
67    ///
68    /// let item = ItemBuf::with_item(["foo", "bar"])?;
69    /// assert_eq!(item.as_bytes(), b"\x0d\0foo\x0d\0\x0d\0bar\x0d\0");
70    /// # Ok::<_, rune::alloc::Error>(())
71    /// ```
72    #[inline]
73    pub fn as_bytes(&self) -> &[u8] {
74        &self.content
75    }
76
77    /// Get the crate corresponding to the item.
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use rune::ItemBuf;
83    ///
84    /// let item = ItemBuf::with_crate("std")?;
85    /// assert_eq!(item.as_crate(), Some("std"));
86    ///
87    /// let item = ItemBuf::with_item(["local"])?;
88    /// assert_eq!(item.as_crate(), None);
89    /// # Ok::<_, rune::alloc::Error>(())
90    /// ```
91    pub fn as_crate(&self) -> Option<&str> {
92        if let Some(ComponentRef::Crate(s)) = self.iter().next() {
93            Some(s)
94        } else {
95            None
96        }
97    }
98
99    /// Access the first component of this item.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use rune::ItemBuf;
105    /// use rune::item::ComponentRef;
106    ///
107    /// let item = ItemBuf::with_item(["foo", "bar"])?;
108    /// assert_eq!(item.first(), Some(ComponentRef::Str("foo")));
109    /// # Ok::<_, rune::alloc::Error>(())
110    /// ```
111    #[inline]
112    pub fn first(&self) -> Option<ComponentRef<'_>> {
113        self.iter().next()
114    }
115
116    /// Check if the item is empty.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use rune::ItemBuf;
122    ///
123    /// let item = ItemBuf::new();
124    /// assert!(item.is_empty());
125    ///
126    /// let item = ItemBuf::with_crate("std")?;
127    /// assert!(!item.is_empty());
128    /// # Ok::<_, rune::alloc::Error>(())
129    /// ```
130    #[inline]
131    pub fn is_empty(&self) -> bool {
132        self.content.is_empty()
133    }
134
135    /// Construct a new vector from the current item.
136    #[cfg(feature = "alloc")]
137    pub fn as_vec(&self) -> alloc::Result<Vec<Component>> {
138        self.iter()
139            .map(ComponentRef::into_component)
140            .try_collect::<Result<Vec<_>, _>>()?
141    }
142
143    /// If the item only contains one element, return that element.
144    pub fn as_local(&self) -> Option<&str> {
145        let mut it = self.iter();
146
147        match it.next_back_str() {
148            Some(last) if it.is_empty() => Some(last),
149            _ => None,
150        }
151    }
152
153    /// Return an owned and joined variant of this item.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use rune::Item;
159    /// use rune::item::ComponentRef;
160    ///
161    /// let item = Item::new();
162    /// assert!(item.is_empty());
163    ///
164    /// let item2 = item.join(["hello", "world"])?;
165    /// assert_eq!(item2.first(), Some(ComponentRef::Str("hello")));
166    /// assert_eq!(item2.last(), Some(ComponentRef::Str("world")));
167    /// # Ok::<(), rune::support::Error>(())
168    /// ```
169    pub fn join(&self, other: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<ItemBuf> {
170        let mut content = self.content.try_to_owned()?;
171
172        for c in other {
173            c.write_component(&mut content)?;
174        }
175
176        // SAFETY: construction through write_component ensures valid
177        // construction of buffer.
178        Ok(unsafe { ItemBuf::from_raw(content) })
179    }
180
181    /// Return an owned and extended variant of this item.
182    ///
183    /// # Examples
184    ///
185    /// ```
186    /// use rune::Item;
187    /// use rune::item::ComponentRef;
188    ///
189    /// let item = Item::new();
190    /// assert!(item.is_empty());
191    ///
192    /// let item2 = item.extended("hello")?;
193    /// assert_eq!(item2.first(), Some(ComponentRef::Str("hello")));
194    /// # Ok::<(), rune::support::Error>(())
195    /// ```
196    pub fn extended<C>(&self, part: C) -> alloc::Result<ItemBuf>
197    where
198        C: IntoComponent,
199    {
200        let mut content = self.content.try_to_owned()?;
201        part.write_component(&mut content)?;
202
203        // SAFETY: construction through write_component ensures valid
204        // construction of buffer.
205        Ok(unsafe { ItemBuf::from_raw(content) })
206    }
207
208    /// Access the last component in the path.
209    #[inline]
210    pub fn last(&self) -> Option<ComponentRef<'_>> {
211        self.iter().next_back()
212    }
213
214    /// Access the base name of the item if available.
215    ///
216    /// The base name is the last string component of the item.
217    #[inline]
218    pub fn base_name(&self) -> Option<&str> {
219        self.iter().next_back()?.as_str()
220    }
221
222    /// An iterator over the [Component]s that constitute this item.
223    ///
224    /// # Examples
225    ///
226    /// ```
227    /// use rune::ItemBuf;
228    /// use rune::item::{ComponentRef, IntoComponent};
229    ///
230    /// let mut item = ItemBuf::new();
231    ///
232    /// item.push("start")?;
233    /// item.push(ComponentRef::Id(1))?;
234    /// item.push(ComponentRef::Id(2))?;
235    /// item.push("middle")?;
236    /// item.push(ComponentRef::Id(3))?;
237    /// item.push("end")?;
238    ///
239    /// let mut it = item.iter();
240    ///
241    /// assert_eq!(it.next(), Some("start".as_component_ref()));
242    /// assert_eq!(it.next(), Some(ComponentRef::Id(1)));
243    /// assert_eq!(it.next(), Some(ComponentRef::Id(2)));
244    /// assert_eq!(it.next(), Some("middle".as_component_ref()));
245    /// assert_eq!(it.next(), Some(ComponentRef::Id(3)));
246    /// assert_eq!(it.next(), Some("end".as_component_ref()));
247    /// assert_eq!(it.next(), None);
248    ///
249    /// assert!(!item.is_empty());
250    /// # Ok::<(), rune::support::Error>(())
251    /// ```
252    #[inline]
253    pub fn iter(&self) -> Iter<'_> {
254        Iter::new(&self.content)
255    }
256
257    /// Test if current item starts with another.
258    #[inline]
259    pub fn starts_with<U>(&self, other: U) -> bool
260    where
261        U: AsRef<Item>,
262    {
263        self.content.starts_with(&other.as_ref().content)
264    }
265
266    /// Test if current is immediate super of `other`.
267    ///
268    /// # Examples
269    ///
270    /// ```
271    /// use rune::{Item, ItemBuf};
272    ///
273    /// assert!(Item::new().is_super_of(Item::new(), 1));
274    /// assert!(!ItemBuf::with_item(["a"])?.is_super_of(Item::new(), 1));
275    ///
276    /// assert!(!ItemBuf::with_item(["a", "b"])?.is_super_of(ItemBuf::with_item(["a"])?, 1));
277    /// assert!(ItemBuf::with_item(["a", "b"])?.is_super_of(ItemBuf::with_item(["a", "b"])?, 1));
278    /// assert!(!ItemBuf::with_item(["a"])?.is_super_of(ItemBuf::with_item(["a", "b", "c"])?, 1));
279    /// # Ok::<_, rune::alloc::Error>(())
280    /// ```
281    pub fn is_super_of<U>(&self, other: U, n: usize) -> bool
282    where
283        U: AsRef<Item>,
284    {
285        let other = other.as_ref();
286
287        if self == other {
288            return true;
289        }
290
291        let mut it = other.iter();
292
293        for _ in 0..n {
294            if it.next_back().is_none() {
295                return false;
296            }
297
298            if self == it {
299                return true;
300            }
301        }
302
303        false
304    }
305
306    /// Get the ancestry of one module to another.
307    ///
308    /// This returns three things:
309    /// * The shared prefix between the current and the `other` path.
310    /// * The suffix to get to the `other` path from the shared prefix.
311    ///
312    /// # Examples
313    ///
314    /// ```
315    /// use rune::{Item, ItemBuf};
316    ///
317    /// assert_eq!(
318    ///     (ItemBuf::new(), ItemBuf::new()),
319    ///     Item::new().ancestry(Item::new())?
320    /// );
321    ///
322    /// assert_eq!(
323    ///     (ItemBuf::new(), ItemBuf::with_item(["a"])?),
324    ///     Item::new().ancestry(ItemBuf::with_item(["a"])?)?
325    /// );
326    ///
327    /// assert_eq!(
328    ///     (ItemBuf::new(), ItemBuf::with_item(["a", "b"])?),
329    ///     Item::new().ancestry(ItemBuf::with_item(["a", "b"])?)?
330    /// );
331    ///
332    /// assert_eq!(
333    ///     (ItemBuf::with_item(["a"])?, ItemBuf::with_item(["b"])?),
334    ///     ItemBuf::with_item(["a", "c"])?.ancestry(ItemBuf::with_item(["a", "b"])?)?
335    /// );
336    ///
337    /// assert_eq!(
338    ///     (ItemBuf::with_item(["a", "b"])?, ItemBuf::with_item(["d", "e"])?),
339    ///     ItemBuf::with_item(["a", "b", "c"])?.ancestry(ItemBuf::with_item(["a", "b", "d", "e"])?)?
340    /// );
341    /// # Ok::<_, rune::alloc::Error>(())
342    /// ```
343    pub fn ancestry<U>(&self, other: U) -> alloc::Result<(ItemBuf, ItemBuf)>
344    where
345        U: AsRef<Item>,
346    {
347        let mut a = self.iter();
348        let other = other.as_ref();
349        let mut b = other.iter();
350
351        let mut shared = ItemBuf::new();
352        let mut suffix = ItemBuf::new();
353
354        while let Some(v) = b.next() {
355            if let Some(u) = a.next() {
356                if u == v {
357                    shared.push(v)?;
358                    continue;
359                } else {
360                    suffix.push(v)?;
361                    suffix.extend(b)?;
362                    return Ok((shared, suffix));
363                }
364            }
365
366            suffix.push(v)?;
367            break;
368        }
369
370        suffix.extend(b)?;
371        Ok((shared, suffix))
372    }
373
374    /// Get the parent item for the current item.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// use rune::ItemBuf;
380    ///
381    /// let item = ItemBuf::with_item(["foo", "bar", "baz"])?;
382    /// let item2 = ItemBuf::with_item(["foo", "bar"])?;
383    ///
384    /// assert_eq!(item.parent(), Some(&*item2));
385    /// # Ok::<_, rune::alloc::Error>(())
386    /// ```
387    pub fn parent(&self) -> Option<&Item> {
388        let mut it = self.iter();
389        it.next_back()?;
390        Some(it.into_item())
391    }
392
393    /// Display an unqalified variant of the item which does not include `::` if
394    /// a crate is present.
395    pub fn unqalified(&self) -> Unqalified {
396        Unqalified::new(self)
397    }
398}
399
400impl AsRef<Item> for &Item {
401    #[inline]
402    fn as_ref(&self) -> &Item {
403        self
404    }
405}
406
407impl Default for &Item {
408    #[inline]
409    fn default() -> Self {
410        Item::new()
411    }
412}
413
414#[cfg(feature = "alloc")]
415impl TryToOwned for Item {
416    type Owned = ItemBuf;
417
418    #[inline]
419    fn try_to_owned(&self) -> alloc::Result<Self::Owned> {
420        // SAFETY: item ensures that content is valid.
421        Ok(unsafe { ItemBuf::from_raw(self.content.try_to_owned()?) })
422    }
423}
424
425/// Format implementation for an [ItemBuf].
426///
427/// An empty item is formatted as `{root}`, because it refers to the topmost
428/// root module.
429///
430/// # Examples
431///
432/// ```
433/// use rune::alloc::prelude::*;
434/// use rune::ItemBuf;
435/// use rune::item::ComponentRef;
436///
437/// let root = ItemBuf::new().try_to_string()?;
438/// assert_eq!("{root}", root);
439///
440/// let hello = ItemBuf::with_item(&[ComponentRef::Str("hello"), ComponentRef::Id(0)])?;
441/// assert_eq!("hello::$0", hello.try_to_string()?);
442/// # Ok::<_, rune::alloc::Error>(())
443/// ```
444impl fmt::Display for Item {
445    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446        let mut it = self.iter();
447
448        if let Some(last) = it.next_back() {
449            for p in it {
450                write!(f, "{}::", p)?;
451            }
452
453            write!(f, "{}", last)?;
454        } else {
455            f.write_str("{root}")?;
456        }
457
458        Ok(())
459    }
460}
461
462impl fmt::Debug for Item {
463    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
464        write!(f, "{}", self)
465    }
466}
467
468impl<'a> IntoIterator for &'a Item {
469    type IntoIter = Iter<'a>;
470    type Item = ComponentRef<'a>;
471
472    #[inline]
473    fn into_iter(self) -> Self::IntoIter {
474        self.iter()
475    }
476}
477
478impl PartialEq<ItemBuf> for Item {
479    fn eq(&self, other: &ItemBuf) -> bool {
480        self.content == other.content
481    }
482}
483
484impl PartialEq<ItemBuf> for &Item {
485    fn eq(&self, other: &ItemBuf) -> bool {
486        self.content == other.content
487    }
488}
489
490impl PartialEq<Iter<'_>> for Item {
491    fn eq(&self, other: &Iter<'_>) -> bool {
492        self == other.as_item()
493    }
494}
495
496impl PartialEq<Iter<'_>> for &Item {
497    fn eq(&self, other: &Iter<'_>) -> bool {
498        *self == other.as_item()
499    }
500}
501
502/// Display an unqalified path.
503pub struct Unqalified<'a> {
504    item: &'a Item,
505}
506
507impl<'a> Unqalified<'a> {
508    fn new(item: &'a Item) -> Self {
509        Self { item }
510    }
511}
512
513impl fmt::Display for Unqalified<'_> {
514    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
515        let mut it = self.item.iter();
516
517        if let Some(last) = it.next_back() {
518            for c in it {
519                match c {
520                    ComponentRef::Crate(name) => {
521                        write!(f, "{name}::")?;
522                    }
523                    ComponentRef::Str(name) => {
524                        write!(f, "{name}::")?;
525                    }
526                    c => {
527                        write!(f, "{c}::")?;
528                    }
529                }
530            }
531
532            write!(f, "{}", last)?;
533        } else {
534            f.write_str("{root}")?;
535        }
536
537        Ok(())
538    }
539}