#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct Path {
path: Vec<String>,
}
impl Path {
pub fn new<S: ToString, I: IntoIterator<Item = S>>(path: I) -> Self {
Path {
path: path.into_iter().map(|x| x.to_string()).collect(),
}
}
pub fn empty() -> Self {
Path { path: vec![] }
}
pub fn from_name<S: ToString>(name: S) -> Self {
Path {
path: vec![name.to_string()],
}
}
pub fn first(&self) -> &str {
self.path.first().unwrap()
}
pub fn last(&self) -> &str {
self.path.last().unwrap()
}
pub fn parent(&self) -> Option<&[String]> {
if self.is_empty() {
None
} else {
Some(&self.path[0..(self.len() - 1)])
}
}
pub fn as_steps(&self) -> &[String] {
&self.path
}
pub fn len(&self) -> usize {
self.path.len()
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn prepend(&mut self, mut prefix: Path) {
prefix.path.append(&mut self.path);
self.path = prefix.path;
}
pub fn append(mut self, suffix: Path) -> Path {
self.path.extend(suffix.path);
self
}
pub fn extend(&mut self, suffix: Path) {
self.path.extend(suffix);
}
pub fn push(&mut self, name: String) {
self.path.push(name);
}
pub fn pop(&mut self) -> Option<String> {
self.path.pop()
}
pub fn pop_first(&mut self) -> Option<String> {
if self.is_empty() {
return None;
}
let remaining = self.path.split_off(1);
let first = std::mem::replace(&mut self.path, remaining);
Some(first.into_iter().next().unwrap())
}
pub fn with_name<S: ToString>(mut self, name: S) -> Self {
*self.path.last_mut().unwrap() = name.to_string();
self
}
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &String> {
self.path.iter()
}
pub fn starts_with(&self, prefix: &Path) -> bool {
if prefix.len() > self.len() {
return false;
}
prefix
.iter()
.zip(self.iter())
.all(|(prefix_component, self_component)| prefix_component == self_component)
}
pub fn starts_with_path<S: AsRef<str>>(&self, prefix: &[S]) -> bool {
if prefix.len() > self.len() {
return false;
}
prefix
.iter()
.zip(self.iter())
.all(|(prefix_component, self_component)| prefix_component.as_ref() == self_component)
}
pub fn starts_with_part(&self, prefix: &str) -> bool {
self.starts_with_path(&[prefix])
}
}
impl std::fmt::Debug for Path {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&display_path(self))
}
}
impl std::fmt::Display for Path {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&display_path(self))
}
}
impl IntoIterator for Path {
type Item = String;
type IntoIter = std::vec::IntoIter<std::string::String>;
fn into_iter(self) -> Self::IntoIter {
self.path.into_iter()
}
}
impl std::ops::Add<Path> for Path {
type Output = Path;
fn add(mut self, rhs: Path) -> Self::Output {
self.path.extend(rhs.path);
self
}
}
fn display_path(ident: &Path) -> String {
let path = &ident.path[..];
let mut r = String::new();
for (index, part) in path.iter().enumerate() {
if index > 0 {
r += "::";
}
r += lutra_bin::ident::display(part).as_ref();
}
r
}