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