use core::fmt::Display;
use std::borrow::Cow;
use genco::{lang::Lang, tokens::FormatInto};
pub type Part<'a> = Cow<'a, str>;
pub type FullPath<'a> = Cow<'a, str>;
#[derive(Debug, Hash, Eq, PartialEq, Clone, PartialOrd, Ord)]
pub struct PathBuf<'a> {
parts: Vec<Part<'a>>,
}
impl Default for PathBuf<'_> {
fn default() -> Self {
Self::new()
}
}
impl<'a> PathBuf<'a> {
pub fn new() -> Self {
PathBuf { parts: Vec::new() }
}
pub fn join(mut self, joiner: impl Into<Part<'a>>) -> Self {
self.parts.push(joiner.into());
self
}
pub fn push(&mut self, part: impl Into<Part<'a>>) {
self.parts.push(part.into());
}
pub fn push_front(&mut self, part: impl Into<Part<'a>>) {
self.parts.insert(0, part.into());
}
pub fn pop_front(&mut self) {
if !self.parts.is_empty() {
let _ = self.parts.remove(0);
}
}
pub fn parts(&self) -> impl Iterator<Item = &Part<'a>> {
self.parts.iter()
}
pub fn is_empty(&self) -> bool {
self.parts.is_empty()
}
pub fn into_path<'b>(self, joiner: impl Into<Part<'b>>) -> Path<'a, 'b> {
let joiner = joiner.into();
Path {
path: Some(self.parts.join(joiner.as_ref()).into()),
joiner,
}
}
pub fn flatten(&mut self) {
self.parts.clear();
}
pub fn into_owned(self) -> PathBuf<'static> {
PathBuf {
parts: self
.parts
.into_iter()
.map(|p| p.into_owned().into())
.collect(),
}
}
}
impl<'a> FromIterator<Part<'a>> for PathBuf<'a> {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Part<'a>>,
{
PathBuf {
parts: iter.into_iter().collect(),
}
}
}
impl<'a> From<&'a str> for PathBuf<'a> {
fn from(value: &'a str) -> Self {
PathBuf {
parts: vec![Cow::Borrowed(value)],
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Path<'a, 'b> {
path: Option<FullPath<'a>>,
joiner: Cow<'b, str>,
}
impl<'a, 'b> Path<'a, 'b> {
pub fn new(path: impl Into<FullPath<'a>>, joiner: impl Into<Cow<'b, str>>) -> Self {
Path {
path: Some(path.into()),
joiner: joiner.into(),
}
}
pub fn parts(&self) -> impl Iterator<Item = &str> {
self.path
.as_ref()
.map(|p| p.split(self.joiner.as_ref()))
.into_iter()
.flatten()
}
pub fn flatten(&mut self) {
self.path = None;
}
pub fn into_buf(self) -> PathBuf<'a> {
PathBuf {
parts: self
.path
.map(|p| {
p.split(self.joiner.as_ref())
.map(|p| p.to_owned().into())
.collect::<Vec<Part<'a>>>()
})
.unwrap_or_default(),
}
}
pub fn is_empty(&self) -> bool {
self.path.as_ref().map(|p| p.is_empty()).unwrap_or(true)
}
pub fn into_owned(self) -> Path<'static, 'static> {
Path {
joiner: self.joiner.into_owned().into(),
path: self.path.map(|p| p.into_owned().into()),
}
}
}
impl<'a, 'b> From<Path<'a, 'b>> for String {
fn from(value: Path<'a, 'b>) -> Self {
value.path.map(|c| c.into_owned()).unwrap_or_default()
}
}
impl Display for Path<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(path) = &self.path {
write!(f, "{}", path)
} else {
write!(f, "")
}
}
}
impl<L: Lang> FormatInto<L> for Path<'_, '_> {
fn format_into(self, t: &mut genco::tokens::Tokens<L>) {
if let Some(path) = &self.path {
path.format_into(t);
}
}
}