1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6pub struct ConfigPath {
7 segments: Vec<String>,
8}
9
10impl ConfigPath {
11 pub fn parse(path: &str) -> Self {
12 Self { segments: path.split('.').filter(|s| !s.is_empty()).map(|s| s.to_string()).collect() }
13 }
14
15 pub fn segments(&self) -> &[String] {
16 &self.segments
17 }
18
19 pub fn is_empty(&self) -> bool {
20 self.segments.is_empty()
21 }
22
23 pub fn push(&mut self, segment: impl Into<String>) {
24 self.segments.push(segment.into());
25 }
26}
27
28impl fmt::Display for ConfigPath {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.write_str(&self.segments.join("."))
31 }
32}
33
34impl From<&str> for ConfigPath {
35 fn from(s: &str) -> Self {
36 Self::parse(s)
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn parses_dotted_path() {
46 let p = ConfigPath::parse("akka.actor.default-dispatcher");
47 assert_eq!(p.segments(), &["akka", "actor", "default-dispatcher"]);
48 assert_eq!(p.to_string(), "akka.actor.default-dispatcher");
49 }
50
51 #[test]
52 fn parses_empty() {
53 assert!(ConfigPath::parse("").is_empty());
54 }
55}