nuit_core/utils/
id_path.rs

1use std::{ops::Deref, borrow::Borrow};
2
3use ref_cast::RefCast;
4use serde::{Serialize, Deserialize};
5
6use crate::Id;
7
8/// A borrowed path of ids.
9#[derive(Debug, Hash, PartialEq, Eq, RefCast)]
10#[repr(transparent)]
11pub struct IdPath([Id]);
12
13/// An owned path of ids.
14#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
15pub struct IdPathBuf(Vec<Id>);
16
17impl IdPath {
18    pub fn root() -> &'static Self {
19        Self::ref_cast(&[])
20    }
21
22    pub fn is_root(&self) -> bool {
23        self.0.is_empty()
24    }
25
26    pub fn head(&self) -> Option<Id> {
27        self.0.first().cloned()
28    }
29
30    pub fn tail(&self) -> &Self {
31        Self::ref_cast(&self.0[1..])
32    }
33
34    pub fn child(&self, id: impl Into<Id>) -> IdPathBuf {
35        self.to_owned().child(id)
36    }
37
38    pub fn join(&self, path: &IdPath) -> IdPathBuf {
39        self.to_owned().join(path)
40    }
41}
42
43impl IdPathBuf {
44    pub fn root() -> Self {
45        Self(Vec::new())
46    }
47
48    pub fn child(&self, id: impl Into<Id>) -> Self {
49        let mut components = self.0.clone();
50        components.push(id.into());
51        Self(components)
52    }
53
54    pub fn join(&self, path: &IdPath) -> Self {
55        let mut components = self.0.clone();
56        components.extend(path.0.into_iter().cloned());
57        Self(components)
58    }
59}
60
61impl ToOwned for IdPath {
62    type Owned = IdPathBuf;
63
64    fn to_owned(&self) -> IdPathBuf {
65        IdPathBuf(self.0.to_vec())
66    }
67}
68
69impl Default for IdPathBuf {
70    fn default() -> Self {
71        Self::root()
72    }
73}
74
75impl From<Id> for IdPathBuf {
76    fn from(id: Id) -> Self {
77        Self(vec![id])
78    }
79}
80
81impl Deref for IdPathBuf {
82    type Target = IdPath;
83
84    fn deref(&self) -> &IdPath {
85        // Unfortunately, casting `&[Id]` to our (newtype-style) DST `IdPath`
86        // cannot be done easily and safely using the language only, see
87        // https://internals.rust-lang.org/t/brainstorming-newtypes-for-dsts-without-needing-unsafe/8515/7
88        // We therefore use the ref-cell library providing a safe abstraction.
89        IdPath::ref_cast(&self.0[..])
90    }
91}
92
93impl AsRef<IdPath> for IdPathBuf {
94    fn as_ref(&self) -> &IdPath {
95        self.deref()
96    }
97}
98
99impl Borrow<IdPath> for IdPathBuf {
100    fn borrow(&self) -> &IdPath {
101        self.deref()
102    }
103}
104
105impl From<&IdPath> for IdPathBuf {
106    fn from(id_path: &IdPath) -> Self {
107        id_path.to_owned()
108    }
109}