agent_first_data/document/
path.rs1use crate::document::{DocumentError, DocumentResult};
7
8pub fn parse_path(path: &str) -> DocumentResult<Vec<String>> {
9 if path.is_empty() {
10 return Err(DocumentError::EmptyPath);
11 }
12 let mut segments = Vec::new();
13 let mut segment = String::new();
14 let mut escaped = false;
15 for character in path.chars() {
16 if escaped {
17 match character {
18 '.' | '\\' => segment.push(character),
19 other => {
20 return Err(DocumentError::ParseError {
21 format: "path".to_string(),
22 detail: format!("invalid escape `\\{other}`"),
23 });
24 }
25 }
26 escaped = false;
27 } else {
28 match character {
29 '\\' => escaped = true,
30 '.' => {
31 if segment.is_empty() {
32 return Err(DocumentError::ParseError {
33 format: "path".to_string(),
34 detail: "empty path segment".to_string(),
35 });
36 }
37 segments.push(std::mem::take(&mut segment));
38 }
39 other => segment.push(other),
40 }
41 }
42 }
43 if escaped {
44 return Err(DocumentError::ParseError {
45 format: "path".to_string(),
46 detail: "trailing path escape".to_string(),
47 });
48 }
49 if segment.is_empty() {
50 return Err(DocumentError::ParseError {
51 format: "path".to_string(),
52 detail: "empty path segment".to_string(),
53 });
54 }
55 segments.push(segment);
56 Ok(segments)
57}
58
59pub fn join_path(segments: &[String]) -> String {
60 segments
61 .iter()
62 .map(|segment| segment.replace('\\', "\\\\").replace('.', "\\."))
63 .collect::<Vec<_>>()
64 .join(".")
65}