use core::{fmt::Display, str::FromStr};
use rfham_core::{Name, error::CoreError};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConfigPath(Vec<Name>);
impl Display for ConfigPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.0
.iter()
.map(Name::to_string)
.collect::<Vec<_>>()
.join(".")
)
}
}
impl FromStr for ConfigPath {
type Err = CoreError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let results: Result<Vec<Name>, CoreError> = s.split('.').map(Name::from_str).collect();
let values = results?;
if !values.is_empty() {
Ok(Self(values))
} else {
Err(CoreError::InvalidValueFromStr(s.to_string(), "ConfigPath"))
}
}
}
impl From<Name> for ConfigPath {
fn from(value: Name) -> Self {
Self::from(vec![value])
}
}
impl From<Vec<Name>> for ConfigPath {
fn from(values: Vec<Name>) -> Self {
assert!(
!values.is_empty(),
"ConfigPath must have at least one component"
);
Self(values)
}
}
#[cfg(test)]
mod tests {
use super::ConfigPath;
use pretty_assertions::assert_eq;
#[test]
fn test_single_component() {
let path: ConfigPath = "station".parse().unwrap();
assert_eq!("station", path.to_string());
}
#[test]
fn test_multi_component() {
let path: ConfigPath = "station.callsign".parse().unwrap();
assert_eq!("station.callsign", path.to_string());
}
#[test]
fn test_empty_string_is_error() {
assert!("".parse::<ConfigPath>().is_err());
}
#[test]
fn test_invalid_component_is_error() {
assert!("station.has space".parse::<ConfigPath>().is_err());
}
}