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}