ddbug_parser/
namespace.rs1use std::cmp;
2use std::sync::Arc;
3
4#[derive(Debug, PartialEq, Eq, Clone, Copy)]
6pub enum NamespaceKind {
7 Namespace,
9 Function,
11 Type,
13}
14
15#[derive(Debug)]
17pub struct Namespace<'input> {
18 pub(crate) parent: Option<Arc<Namespace<'input>>>,
19 pub(crate) name: Option<&'input str>,
20 pub(crate) kind: NamespaceKind,
21}
22
23impl<'input> Namespace<'input> {
24 pub(crate) fn new(
25 parent: &Option<Arc<Namespace<'input>>>,
26 name: Option<&'input str>,
27 kind: NamespaceKind,
28 ) -> Arc<Namespace<'input>> {
29 Arc::new(Namespace {
30 parent: parent.clone(),
31 name,
32 kind,
33 })
34 }
35
36 pub fn parent(&self) -> Option<&Namespace<'input>> {
38 self.parent.as_deref()
39 }
40
41 #[inline]
43 pub fn name(&self) -> Option<&str> {
44 self.name
45 }
46
47 #[inline]
49 pub fn kind(&self) -> NamespaceKind {
50 self.kind
51 }
52
53 fn len(&self) -> usize {
54 match &self.parent {
55 Some(parent) => parent.len() + 1,
56 None => 1,
57 }
58 }
59
60 fn up(&self, len: usize) -> &Namespace {
61 if len == 0 {
62 self
63 } else {
64 match &self.parent {
65 Some(parent) => parent.up(len - 1),
66 None => self,
67 }
68 }
69 }
70
71 pub(crate) fn is_anon_type(namespace: &Option<Arc<Namespace>>) -> bool {
72 match namespace {
73 Some(namespace) => {
74 namespace.kind == NamespaceKind::Type
75 && (namespace.name.is_none() || Namespace::is_anon_type(&namespace.parent))
76 }
77 None => false,
78 }
79 }
80
81 fn _is_within<T: AsRef<str>>(&self, namespace: &[T]) -> (bool, usize) {
82 let (ret, offset) = match &self.parent {
83 Some(parent) => parent._is_within(namespace),
84 None => (true, 0),
85 };
86
87 if ret {
88 if offset < namespace.len() {
89 match self.name() {
90 Some(name) => (name == namespace[offset].as_ref(), offset + 1),
91 None => (false, offset + 1),
92 }
93 } else {
94 (true, offset)
95 }
96 } else {
97 (false, 0)
98 }
99 }
100
101 pub fn is_within<T: AsRef<str>>(&self, namespace: &[T]) -> bool {
105 self._is_within(namespace) == (true, namespace.len())
106 }
107
108 fn _cmp(a: &Namespace, b: &Namespace) -> cmp::Ordering {
109 debug_assert_eq!(a.len(), b.len());
110 match (a.parent.as_ref(), b.parent.as_ref()) {
111 (Some(p1), Some(p2)) => {
112 let ord = Self::_cmp(p1, p2);
113 if ord != cmp::Ordering::Equal {
114 return ord;
115 }
116 }
117 _ => {}
118 }
119 a.name.cmp(&b.name)
120 }
121
122 fn cmp(a: &Namespace, b: &Namespace) -> cmp::Ordering {
123 let len_a = a.len();
124 let len_b = b.len();
125 match len_a.cmp(&len_b) {
126 cmp::Ordering::Equal => Self::_cmp(a, b),
127 cmp::Ordering::Less => {
128 let b = b.up(len_b - len_a);
129 match Self::_cmp(a, b) {
130 cmp::Ordering::Equal => cmp::Ordering::Less,
131 other => other,
132 }
133 }
134 cmp::Ordering::Greater => {
135 let a = a.up(len_a - len_b);
136 match Self::_cmp(a, b) {
137 cmp::Ordering::Equal => cmp::Ordering::Greater,
138 other => other,
139 }
140 }
141 }
142 }
143
144 pub(crate) fn cmp_ns_and_name(
145 ns1: Option<&Namespace>,
146 name1: Option<&str>,
147 ns2: Option<&Namespace>,
148 name2: Option<&str>,
149 ) -> cmp::Ordering {
150 match (ns1, ns2) {
151 (Some(ns1), Some(ns2)) => match Namespace::cmp(ns1, ns2) {
152 cmp::Ordering::Equal => name1.cmp(&name2),
153 o => o,
154 },
155 (Some(_), None) => cmp::Ordering::Greater,
156 (None, Some(_)) => cmp::Ordering::Less,
157 (None, None) => name1.cmp(&name2),
158 }
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165
166 #[test]
167 fn cmp() {
168 let ns1 = Namespace::new(&None, Some("a".into()), NamespaceKind::Namespace);
169 let ns2 = Namespace::new(&None, Some("b".into()), NamespaceKind::Namespace);
170 assert_eq!(Namespace::cmp(&ns1, &ns2), cmp::Ordering::Less);
171 }
172}