use regex::RegexBuilder;
use serde::Serialize;
#[derive(Clone, Debug, Serialize)]
#[serde(try_from = "String")]
pub struct DotDelimitedPath(String);
impl DotDelimitedPath {
pub const DOT_DELIMITED_REGEX: &str = r"^[a-zA-Z_]+(\.[a-zA-Z_]+)*$";
}
impl TryFrom<String> for DotDelimitedPath {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.is_empty() {
return Ok(Self(value));
}
let regex = RegexBuilder::new(Self::DOT_DELIMITED_REGEX)
.build()
.map_err(|e| e.to_string())?;
if regex.is_match(&value) {
Ok(Self(value))
} else {
Err(format!(
"String '{}' does not match pattern '{}'",
value,
Self::DOT_DELIMITED_REGEX
))
}
}
}
impl DotDelimitedPath {
pub fn to_jsonpath(&self) -> String {
prepend_if_missing(&self.0, "$.")
}
pub fn to_jsonpointer(&self) -> String {
prepend_if_missing(&self.0.replace(".", "/"), "/")
}
}
impl std::fmt::Display for DotDelimitedPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
fn prepend_if_missing(path: &str, prefix: &str) -> String {
if !path.starts_with(prefix) {
format!("{prefix}{path}")
} else {
path.to_string()
}
}