1#[derive(Clone, Debug)]
2enum PathList<'a> {
3 Nil,
4 Node {
5 path: &'a str,
6 rest: &'a PathList<'a>,
7 total_length: usize,
8 node_count: usize,
9 },
10}
11
12impl<'a> PathList<'a> {
13 pub fn node_count(&self) -> usize {
14 match self {
15 PathList::Nil => 0,
16 PathList::Node {
17 total_length: l, ..
18 } => *l,
19 }
20 }
21
22 pub fn total_len(&self) -> usize {
23 match self {
24 PathList::Nil => 0,
25 PathList::Node { node_count: c, .. } => *c,
26 }
27 }
28
29 fn first(&self) -> &'a str {
30 match self {
31 PathList::Nil => panic!("No nodes in path list"),
32 PathList::Node { path: p, .. } => p,
33 }
34 }
35
36 pub fn iter(&self) -> ::std::vec::IntoIter<&'a str> {
37 let len = self.node_count();
38 let mut vec = Vec::with_capacity(len);
39 let mut node = self;
40
41 while let PathList::Node {
42 path: p, rest: r, ..
43 } = *node
44 {
45 vec.push(p);
46 node = r;
47 }
48
49 vec.reverse();
50 vec.into_iter()
51 }
52}
53
54bitflags! {
55 struct Flags: u32 {
56 const NONE = 0;
57 const LIST = 1 << 0;
58 const OPTIONAL = 1 << 1;
59 const VARIANT = 1 << 2;
60 }
61}
62
63#[derive(Clone, Debug)]
64pub struct Context<'a> {
65 path: PathList<'a>,
66 flags: Flags,
67}
68
69impl<'a> Default for Context<'a> {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl<'a> Context<'a> {
76 pub fn new() -> Self {
77 Context {
78 path: PathList::Nil,
79 flags: Flags::NONE,
80 }
81 }
82
83 pub fn child<'b>(&'a self, path: &'b str) -> Context<'b>
84 where
85 'a: 'b,
86 {
87 let len = path.len();
88 Context {
89 path: PathList::Node {
90 path,
91 rest: &self.path,
92 total_length: self.path.total_len() + len,
93 node_count: self.path.node_count() + 1,
94 },
95 flags: self.flags,
96 }
97 }
98
99 pub fn list(self) -> Self {
100 Context {
101 path: self.path,
102 flags: self.flags | Flags::LIST,
103 }
104 }
105
106 pub fn optional(self) -> Self {
107 Context {
108 path: self.path,
109 flags: self.flags | Flags::OPTIONAL,
110 }
111 }
112
113 pub fn variant(self) -> Self {
114 Context {
115 path: self.path,
116 flags: self.flags | Flags::VARIANT,
117 }
118 }
119
120 pub fn is_list(&self) -> bool {
121 self.flags.contains(Flags::LIST)
122 }
123
124 pub fn is_optional(&self) -> bool {
125 self.flags.contains(Flags::OPTIONAL)
126 }
127
128 pub fn is_variant(&self) -> bool {
129 self.flags.contains(Flags::VARIANT)
130 }
131
132 pub fn join_path(&self, separator: &str) -> String {
133 let node_count = self.path.node_count();
134 if node_count == 0 {
135 "".to_owned()
136 } else if node_count == 1 {
137 self.path.first().to_owned()
138 } else {
139 let path_str_len = self.path.total_len();
140 let mut ret = String::with_capacity(path_str_len + (node_count - 1) * separator.len());
141 let mut first = true;
142 for chunk in self.path.iter() {
143 if first {
144 first = false;
145 } else {
146 ret.push_str(separator);
147 }
148
149 ret.push_str(chunk);
150 }
151
152 ret
153 }
154 }
155}