1use core::fmt;
20
21use alloc::{borrow::Cow, string::String, vec::Vec};
22
23use crate::tree::{
24 codec::{
25 encode::{encode_component, encode_leaf},
26 escape::escape_with,
27 mode::VcardEscaper,
28 unescape::{unescape_bytes, unescape_with},
29 },
30 leaf::VcardValueLeaf,
31};
32
33#[derive(Clone, Debug, Default)]
43pub struct VcardValueNode<'a> {
44 raw: Option<Cow<'a, [u8]>>,
48 components: Vec<Vec<VcardValueLeaf<'a>>>,
51 pub escaper: VcardEscaper,
53}
54
55impl<'a> VcardValueNode<'a> {
56 pub fn parse(value: &'a [u8]) -> Self {
60 Self {
61 raw: Some(Cow::Borrowed(value)),
62 components: Vec::new(),
63 escaper: VcardEscaper::default(),
64 }
65 }
66
67 pub(crate) fn from_components(
70 components: Vec<Vec<VcardValueLeaf<'a>>>,
71 escaper: VcardEscaper,
72 ) -> Self {
73 Self {
74 raw: None,
75 components,
76 escaper,
77 }
78 }
79
80 pub fn component_count(&self) -> usize {
83 match &self.raw {
84 Some(raw) => {
85 let mut count = 0;
86 split_on(raw, b';', |_| count += 1);
87 count
88 }
89 None => self.components.len(),
90 }
91 }
92
93 pub fn decode_at(&self, i: usize) -> Vec<Cow<'_, str>> {
95 match self.component_at(i) {
96 Some(Component::Raw(bytes)) => {
97 let mut values = Vec::new();
98 split_on(bytes, b',', |value| {
99 values.push(unescape_with(value, self.escaper))
100 });
101 values
102 }
103 Some(Component::Split(leaves)) => leaves
104 .iter()
105 .map(|leaf| unescape_with(leaf.as_bytes(), self.escaper))
106 .collect(),
107 None => Vec::new(),
108 }
109 }
110
111 pub fn decode_bytes_at(&self, i: usize) -> Cow<'_, [u8]> {
114 match self.component_at(i) {
115 Some(Component::Raw(bytes)) => unescape_bytes(first_value(bytes), self.escaper),
116 Some(Component::Split(leaves)) => leaves
117 .first()
118 .map(|leaf| unescape_bytes(leaf.as_bytes(), self.escaper))
119 .unwrap_or(Cow::Borrowed(b"")),
120 None => Cow::Borrowed(b""),
121 }
122 }
123
124 pub fn decode_scalar_at(&self, i: usize) -> Cow<'_, str> {
126 match self.component_at(i) {
127 Some(Component::Raw(bytes)) => unescape_with(first_value(bytes), self.escaper),
128 Some(Component::Split(leaves)) => leaves
129 .first()
130 .map(|leaf| unescape_with(leaf.as_bytes(), self.escaper))
131 .unwrap_or(Cow::Borrowed("")),
132 None => Cow::Borrowed(""),
133 }
134 }
135
136 pub fn decode_joined_at(&self, i: usize) -> Cow<'_, str> {
140 match self.component_at(i) {
141 Some(Component::Raw(bytes)) => unescape_with(bytes, self.escaper),
144 Some(Component::Split(leaves)) => {
145 if leaves.len() <= 1 {
146 return leaves
147 .first()
148 .map(|leaf| unescape_with(leaf.as_bytes(), self.escaper))
149 .unwrap_or(Cow::Borrowed(""));
150 }
151
152 let mut raw = Vec::new();
153 for (j, leaf) in leaves.iter().enumerate() {
154 if j > 0 {
155 raw.push(b',');
156 }
157 raw.extend_from_slice(leaf.as_bytes());
158 }
159
160 Cow::Owned(unescape_with(&raw, self.escaper).into_owned())
161 }
162 None => Cow::Borrowed(""),
163 }
164 }
165
166 pub(crate) fn first_value_bytes(&self) -> &[u8] {
169 match self.component_at(0) {
170 Some(Component::Raw(bytes)) => first_value(bytes),
171 Some(Component::Split(leaves)) => {
172 leaves.first().map(|leaf| leaf.as_bytes()).unwrap_or(b"")
173 }
174 None => b"",
175 }
176 }
177
178 pub fn set_at<S: AsRef<str>>(&mut self, i: usize, values: &[S]) {
181 self.materialize();
182
183 while self.components.len() <= i {
184 self.components.push(Vec::new());
185 }
186
187 self.components[i] = encode_component(values, self.escaper);
188 }
189
190 pub fn set_bytes_at<B: AsRef<[u8]>>(&mut self, i: usize, values: &[B]) {
193 self.materialize();
194
195 while self.components.len() <= i {
196 self.components.push(Vec::new());
197 }
198
199 self.components[i] = values
200 .iter()
201 .map(|v| VcardValueLeaf::from(escape_with(v.as_ref(), self.escaper).into_owned()))
202 .collect();
203 }
204
205 pub fn value_count(&self, i: usize) -> usize {
208 match self.component_at(i) {
209 Some(Component::Raw(bytes)) => {
210 let mut count = 0;
211 split_on(bytes, b',', |_| count += 1);
212 count
213 }
214 Some(Component::Split(leaves)) => leaves.len(),
215 None => 0,
216 }
217 }
218
219 pub fn set_value_at<S: AsRef<str>>(&mut self, i: usize, j: usize, value: S) {
222 let escaper = self.escaper;
223 let component = self.component_mut(i);
224
225 while component.len() <= j {
226 component.push(encode_leaf("", escaper));
227 }
228
229 component[j] = encode_leaf(value, escaper);
230 }
231
232 pub fn insert_value_at<S: AsRef<str>>(&mut self, i: usize, j: usize, value: S) {
235 let escaper = self.escaper;
236 let component = self.component_mut(i);
237 let at = j.min(component.len());
238
239 component.insert(at, encode_leaf(value, escaper));
240 }
241
242 pub fn push_value<S: AsRef<str>>(&mut self, i: usize, value: S) {
244 let escaper = self.escaper;
245 let component = self.component_mut(i);
246
247 component.push(encode_leaf(value, escaper));
248 }
249
250 pub fn remove_value_at(&mut self, i: usize, j: usize) {
253 self.materialize();
254
255 if let Some(component) = self.components.get_mut(i)
256 && j < component.len()
257 {
258 component.remove(j);
259 }
260 }
261
262 pub(crate) fn write_bytes(&self, out: &mut Vec<u8>) {
266 if let Some(raw) = &self.raw {
267 out.extend_from_slice(raw);
268 return;
269 }
270
271 for (i, component) in self.components.iter().enumerate() {
272 if i > 0 {
273 out.push(b';');
274 }
275
276 for (j, leaf) in component.iter().enumerate() {
277 if j > 0 {
278 out.push(b',');
279 }
280
281 out.extend_from_slice(leaf.as_bytes());
282 }
283 }
284 }
285
286 pub(crate) fn into_static(self) -> VcardValueNode<'static> {
289 match self.raw {
290 Some(raw) => VcardValueNode {
291 raw: Some(Cow::Owned(raw.into_owned())),
292 components: Vec::new(),
293 escaper: self.escaper,
294 },
295 None => VcardValueNode {
296 raw: None,
297 components: self
298 .components
299 .into_iter()
300 .map(|component| {
301 component
302 .into_iter()
303 .map(VcardValueLeaf::into_static)
304 .collect()
305 })
306 .collect(),
307 escaper: self.escaper,
308 },
309 }
310 }
311
312 fn component_at(&self, i: usize) -> Option<Component<'_, 'a>> {
315 match &self.raw {
316 Some(raw) => {
317 let mut found = None;
318 let mut index = 0;
319 split_on(raw, b';', |component| {
320 if index == i {
321 found = Some(component);
322 }
323 index += 1;
324 });
325 found.map(Component::Raw)
326 }
327 None => self
328 .components
329 .get(i)
330 .map(|leaves| Component::Split(leaves)),
331 }
332 }
333
334 fn component_mut(&mut self, i: usize) -> &mut Vec<VcardValueLeaf<'a>> {
337 self.materialize();
338
339 while self.components.len() <= i {
340 self.components.push(Vec::new());
341 }
342
343 &mut self.components[i]
344 }
345
346 fn materialize(&mut self) {
349 let Some(raw) = self.raw.take() else {
350 return;
351 };
352
353 self.components = match raw {
354 Cow::Borrowed(bytes) => split_all(bytes),
355 Cow::Owned(bytes) => split_all_owned(&bytes),
356 };
357 }
358}
359
360impl fmt::Display for VcardValueNode<'_> {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 if let Some(raw) = &self.raw {
363 return f.write_str(&String::from_utf8_lossy(raw));
364 }
365
366 for (i, component) in self.components.iter().enumerate() {
367 if i > 0 {
368 f.write_str(";")?;
369 }
370
371 for (j, leaf) in component.iter().enumerate() {
372 if j > 0 {
373 f.write_str(",")?;
374 }
375
376 f.write_str(&String::from_utf8_lossy(leaf.as_bytes()))?;
377 }
378 }
379
380 Ok(())
381 }
382}
383
384enum Component<'s, 'a> {
387 Raw(&'s [u8]),
390 Split(&'s [VcardValueLeaf<'a>]),
392}
393
394fn first_value(component: &[u8]) -> &[u8] {
397 let mut first = None;
398 split_on(component, b',', |value| {
399 first.get_or_insert(value);
400 });
401 first.unwrap_or(component)
402}
403
404fn split_all(bytes: &[u8]) -> Vec<Vec<VcardValueLeaf<'_>>> {
407 let mut components = Vec::new();
408 split_on(bytes, b';', |component| {
409 let mut values = Vec::new();
410 split_on(component, b',', |value| {
411 values.push(VcardValueLeaf::from(value));
412 });
413 components.push(values);
414 });
415 components
416}
417
418fn split_all_owned(bytes: &[u8]) -> Vec<Vec<VcardValueLeaf<'static>>> {
421 let mut components = Vec::new();
422 split_on(bytes, b';', |component| {
423 let mut values = Vec::new();
424 split_on(component, b',', |value| {
425 values.push(VcardValueLeaf::from(value.to_vec()));
426 });
427 components.push(values);
428 });
429 components
430}
431
432fn split_on<'b>(bytes: &'b [u8], sep: u8, mut piece: impl FnMut(&'b [u8])) {
438 let mut start = 0;
439 let mut i = 0;
440
441 while let Some(offset) = memchr::memchr2(b'\\', sep, &bytes[i..]) {
442 let pos = i + offset;
443 if bytes[pos] == b'\\' {
444 i = (pos + 2).min(bytes.len());
445 } else {
446 piece(&bytes[start..pos]);
447 start = pos + 1;
448 i = pos + 1;
449 }
450 }
451
452 piece(&bytes[start..]);
453}
454
455#[cfg(test)]
456mod tests {
457 use alloc::{borrow::Cow, string::ToString, vec};
458
459 use crate::tree::value::node::VcardValueNode;
460
461 #[test]
462 fn splits_components_and_values_then_round_trips() {
463 let node = VcardValueNode::parse(b"a;b,c;");
464 assert_eq!(node.component_count(), 3);
465 assert_eq!(
466 node.decode_at(1),
467 vec![Cow::Borrowed("b"), Cow::Borrowed("c")]
468 );
469 assert_eq!(node.to_string(), "a;b,c;");
470 }
471
472 #[test]
473 fn keeps_escaped_separators_inside_one_value() {
474 let node = VcardValueNode::parse(br"a\,b\;c;d");
475 assert_eq!(node.component_count(), 2);
476 assert_eq!(node.decode_at(0).len(), 1);
477 assert_eq!(node.to_string(), r"a\,b\;c;d");
478 }
479
480 #[test]
481 fn an_edit_splits_and_preserves_untouched_components() {
482 let mut node = VcardValueNode::parse(b"a;b;c");
483 node.set_at(1, &["X"]);
484 assert_eq!(node.to_string(), "a;X;c");
485 }
486
487 fn assert_readers_agree(node: &VcardValueNode<'_>, components: usize) {
495 assert_eq!(node.component_count(), components);
496 assert_eq!(node.value_count(1), 2);
497 assert_eq!(node.decode_scalar_at(0), "a");
498 assert_eq!(
499 node.decode_at(1),
500 vec![Cow::Borrowed("b"), Cow::Borrowed("c")],
501 );
502 assert_eq!(node.decode_joined_at(1), "b,c");
503 assert_eq!(node.decode_bytes_at(2).as_ref(), b"d");
504 }
505
506 #[test]
507 fn readers_agree_before_and_after_an_edit_materializes_the_node() {
508 let mut node = VcardValueNode::parse(b"a;b,c;d");
509 assert_readers_agree(&node, 3);
510
511 node.set_at(3, &["e"]);
514 assert_readers_agree(&node, 4);
515 assert_eq!(node.to_string(), "a;b,c;d;e");
516 }
517
518 #[test]
519 fn readers_agree_after_an_owned_node_is_edited() {
520 let mut node = VcardValueNode::parse(b"a;b,c;d").into_static();
521 assert_readers_agree(&node, 3);
522
523 node.set_at(3, &["e"]);
524 assert_readers_agree(&node, 4);
525 assert_eq!(node.to_string(), "a;b,c;d;e");
526 }
527}