use std::path::PathBuf;
use derive_more::Display;
use thiserror::Error;
use zarrs_storage::{StorePrefix, StorePrefixError};
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)]
#[display("{}", _0.to_string_lossy())]
pub struct NodePath(PathBuf);
#[derive(Clone, Debug, Error)]
#[error("invalid node path {0}")]
pub struct NodePathError(String);
impl NodePath {
pub fn new(path: &str) -> Result<Self, NodePathError> {
if Self::validate(path) {
Ok(Self(PathBuf::from(path)))
} else {
Err(NodePathError(path.to_string()))
}
}
#[must_use]
pub fn root() -> Self {
Self(PathBuf::from("/"))
}
#[allow(clippy::missing_panics_doc)]
#[must_use]
pub fn as_str(&self) -> &str {
self.0.to_str().unwrap()
}
#[must_use]
pub fn as_path(&self) -> &std::path::Path {
&self.0
}
#[must_use]
pub fn validate(path: &str) -> bool {
path.eq("/") || (path.starts_with('/') && !path.ends_with('/') && !path.contains("//"))
}
}
impl TryFrom<&str> for NodePath {
type Error = NodePathError;
fn try_from(path: &str) -> Result<Self, Self::Error> {
Self::new(path)
}
}
impl TryFrom<&StorePrefix> for NodePath {
type Error = NodePathError;
fn try_from(prefix: &StorePrefix) -> Result<Self, Self::Error> {
let path = "/".to_string() + prefix.as_str().strip_suffix('/').unwrap();
Self::new(&path)
}
}
impl TryInto<StorePrefix> for &NodePath {
type Error = StorePrefixError;
fn try_into(self) -> Result<StorePrefix, StorePrefixError> {
let path = self.as_str();
if path.eq("/") {
StorePrefix::new("")
} else {
StorePrefix::new(path.strip_prefix('/').unwrap_or(path).to_string() + "/")
}
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::*;
#[test]
fn node_path() {
assert!(NodePath::new("/").is_ok());
assert!(NodePath::new("/a/b").is_ok());
assert_eq!(NodePath::new("/a/b").unwrap().to_string(), "/a/b");
assert!(NodePath::new("/a/b/").is_err());
assert_eq!(
NodePath::new("/a/b/").unwrap_err().to_string(),
"invalid node path /a/b/"
);
assert!(NodePath::new("/a//b").is_err());
assert_eq!(NodePath::new("/a/b").unwrap().as_path(), Path::new("/a/b/"));
}
}