1const EMPTY: &str = "";
2const KEY_DELIMITER: &str = ":";
3
4#[derive(Copy, Clone, Debug, PartialEq)]
6pub enum ConfigurationPath {
7 Absolute,
9
10 Relative
12}
13
14impl ConfigurationPath {
15 pub fn key_delimiter() -> &'static str {
17 KEY_DELIMITER
18 }
19
20 pub fn combine(segments: &[&str]) -> String {
26 segments.join(KEY_DELIMITER)
27 }
28
29 pub fn section_key(path: &str) -> &str {
35 if let Some(index) = path.rfind(KEY_DELIMITER) {
36 &path[(index + 1)..]
37 } else {
38 path
39 }
40 }
41
42 pub fn parent_path(path: &str) -> &str {
48 if let Some(index) = path.rfind(KEY_DELIMITER) {
49 &path[..index]
50 } else {
51 EMPTY
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58
59 use super::*;
60 use test_case::test_case;
61
62 #[test_case(&["parent", ""], "parent:" ; "with 1 segment")]
63 #[test_case(&["parent", "", ""], "parent::" ; "with 2 segments")]
64 #[test_case(&["parent", "", "", "key"], "parent:::key" ; "with segments in between")]
65 fn combine_with_empty_segment_leaves_delimiter(segments: &[&str], expected: &str) {
66 let path = ConfigurationPath::combine(segments);
70
71 assert_eq!(&path, expected);
73 }
74
75 #[test_case("", "" ; "when empty")]
76 #[test_case(":::", "" ; "when only delimiters")]
77 #[test_case("a::b:::c", "c" ; "with empty segments in the middle")]
78 #[test_case("a:::b:", "" ; "when last segment is empty")]
79 #[test_case("key", "key" ; "with no parent")]
80 #[test_case(":key", "key" ; "with 1 empty parent")]
81 #[test_case("::key", "key" ; "with 2 empty parents")]
82 #[test_case("parent:key", "key" ; "with parent")]
83 fn section_key_should_return_expected_segment(path: &str, expected: &str) {
84 let key = ConfigurationPath::section_key(path);
88
89 assert_eq!(key, expected);
91 }
92
93 #[test_case("", "" ; "when empty")]
94 #[test_case(":::", "::" ; "when only delimiters")]
95 #[test_case("a::b:::c", "a::b::" ; "with empty segments in the middle")]
96 #[test_case("a:::b:", "a:::b" ; "when last segment is empty")]
97 #[test_case("key", "" ; "with no parent")]
98 #[test_case(":key", "" ; "with 1 empty parent")]
99 #[test_case("::key", ":" ; "with 2 empty parents")]
100 #[test_case("parent:key", "parent" ; "with parent")]
101 fn parent_path_should_return_expected_segment(path: &str, expected: &str) {
102 let key = ConfigurationPath::parent_path(path);
106
107 assert_eq!(key, expected);
109 }
110}