code_moniker_core/core/moniker/
builder.rs1use super::encoding::{HEADER_FIXED_LEN, VERSION, write_u16};
2use super::{Moniker, MonikerView};
3
4const MAX_COMPONENT_LEN: usize = u16::MAX as usize;
5
6#[derive(Default, Debug)]
7pub struct MonikerBuilder {
8 project: Vec<u8>,
9 segments: Vec<(Vec<u8>, Vec<u8>)>,
10}
11
12impl MonikerBuilder {
13 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn from_view(view: MonikerView<'_>) -> Self {
18 let mut b = Self::new();
19 b.project(view.project());
20 for seg in view.segments() {
21 b.segment(seg.kind, seg.name);
22 }
23 b
24 }
25
26 pub fn truncate(&mut self, len: usize) {
27 self.segments.truncate(len);
28 }
29
30 pub fn project(&mut self, project: &[u8]) -> &mut Self {
31 self.project.clear();
32 self.project.extend_from_slice(project);
33 self
34 }
35
36 pub fn segment(&mut self, kind: &[u8], name: &[u8]) -> &mut Self {
37 self.segments.push((kind.to_vec(), name.to_vec()));
38 self
39 }
40
41 pub fn build(&self) -> Moniker {
42 assert!(
43 self.project.len() <= MAX_COMPONENT_LEN,
44 "moniker project longer than u16::MAX bytes ({})",
45 self.project.len()
46 );
47 let mut buf = Vec::with_capacity(self.estimated_size());
48 buf.push(VERSION);
49 write_u16(&mut buf, self.project.len() as u16);
50 buf.extend_from_slice(&self.project);
51 for (kind, name) in &self.segments {
52 assert!(
53 kind.len() <= MAX_COMPONENT_LEN,
54 "moniker segment kind longer than u16::MAX bytes ({})",
55 kind.len()
56 );
57 assert!(
58 name.len() <= MAX_COMPONENT_LEN,
59 "moniker segment name longer than u16::MAX bytes ({})",
60 name.len()
61 );
62 write_u16(&mut buf, kind.len() as u16);
63 buf.extend_from_slice(kind);
64 write_u16(&mut buf, name.len() as u16);
65 buf.extend_from_slice(name);
66 }
67 Moniker::from_canonical_bytes(buf)
68 }
69
70 fn estimated_size(&self) -> usize {
71 HEADER_FIXED_LEN
72 + self.project.len()
73 + self
74 .segments
75 .iter()
76 .map(|(k, n)| 2 + k.len() + 2 + n.len())
77 .sum::<usize>()
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::super::Segment;
84 use super::*;
85
86 #[test]
87 fn builder_empty() {
88 let m = MonikerBuilder::new().build();
89 let v = m.as_view();
90 assert_eq!(v.project(), b"");
91 assert_eq!(v.segment_count(), 0);
92 assert_eq!(v.segments().count(), 0);
93 }
94
95 #[test]
96 fn builder_with_project_no_segments() {
97 let m = MonikerBuilder::new().project(b"my-app").build();
98 let v = m.as_view();
99 assert_eq!(v.project(), b"my-app");
100 assert_eq!(v.segment_count(), 0);
101 }
102
103 #[test]
104 fn builder_with_segments() {
105 let m = MonikerBuilder::new()
106 .project(b"my-app")
107 .segment(b"module", b"main")
108 .segment(b"package", b"com")
109 .segment(b"package", b"acme")
110 .segment(b"class", b"Foo")
111 .build();
112 let v = m.as_view();
113 assert_eq!(v.segment_count(), 4);
114 let segs: Vec<_> = v.segments().collect();
115 assert_eq!(
116 segs[0],
117 Segment {
118 kind: b"module",
119 name: b"main"
120 }
121 );
122 assert_eq!(
123 segs[3],
124 Segment {
125 kind: b"class",
126 name: b"Foo"
127 }
128 );
129 }
130
131 #[test]
132 fn builder_method_with_arity_in_name() {
133 let m = MonikerBuilder::new()
134 .project(b"app")
135 .segment(b"class", b"Foo")
136 .segment(b"method", b"bar()")
137 .segment(b"method", b"bar(2)")
138 .build();
139 let segs: Vec<_> = m.as_view().segments().collect();
140 assert_eq!(segs[1].name, b"bar()");
141 assert_eq!(segs[2].name, b"bar(2)");
142 }
143
144 #[test]
145 fn builder_accepts_max_length_component() {
146 let big = vec![b'a'; MAX_COMPONENT_LEN];
147 let m = MonikerBuilder::new()
148 .project(&big)
149 .segment(b"path", &big)
150 .build();
151 let v = m.as_view();
152 assert_eq!(v.project().len(), MAX_COMPONENT_LEN);
153 let seg = v.segments().next().unwrap();
154 assert_eq!(seg.name.len(), MAX_COMPONENT_LEN);
155 }
156
157 #[test]
158 #[should_panic(expected = "moniker project longer than u16::MAX bytes")]
159 fn builder_panics_on_oversized_project() {
160 let oversize = vec![b'a'; MAX_COMPONENT_LEN + 1];
161 MonikerBuilder::new().project(&oversize).build();
162 }
163
164 #[test]
165 #[should_panic(expected = "moniker segment kind longer than u16::MAX bytes")]
166 fn builder_panics_on_oversized_segment_kind() {
167 let oversize = vec![b'a'; MAX_COMPONENT_LEN + 1];
168 MonikerBuilder::new()
169 .project(b"app")
170 .segment(&oversize, b"x")
171 .build();
172 }
173
174 #[test]
175 #[should_panic(expected = "moniker segment name longer than u16::MAX bytes")]
176 fn builder_panics_on_oversized_segment_name() {
177 let oversize = vec![b'a'; MAX_COMPONENT_LEN + 1];
178 MonikerBuilder::new()
179 .project(b"app")
180 .segment(b"path", &oversize)
181 .build();
182 }
183}