use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
#[derive(Debug, PartialEq)]
pub enum PathError {
MultipleMatch,
NoMatch,
NoRemainder,
NotUnique,
OutOfBounds,
Parse(String, usize),
PathNotUnique,
Remove,
RootIndex,
SegmentImmut,
}
impl fmt::Display for PathError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PathError::MultipleMatch => write!(f, "Multiple matches."),
PathError::NoMatch => write!(f, "No match."),
PathError::NoRemainder => write!(f, "No remainder."),
PathError::NotUnique => write!(f, "Path not unique."),
PathError::OutOfBounds => write!(f, "Index out of bounds."),
PathError::Parse(s, pos) => write!(f, "Could not parse \"{}\" at position {}.", s, pos),
PathError::PathNotUnique => write!(f, "Can't get last index of non-unique path."),
PathError::Remove => write!(f, "Removed too many segments."),
PathError::RootIndex => write!(f, "Root index is not zero."),
PathError::SegmentImmut => write!(f, "Cannot mutate unique segment."),
}
}
}
enum PS {
Segment,
Separator,
}
#[derive(Clone)]
pub struct Segment {
pub index: usize,
start: usize,
end: usize,
}
impl Segment {
fn new(index: usize, start: usize, end: usize) -> Segment {
Segment {
index: index,
start: start,
end: end,
}
}
fn right_shift(&self, n: usize) -> Segment {
Segment {
start: self.start + n,
end: self.end + n,
index: self.index,
}
}
fn left_shift(&self, n: usize) -> Segment {
Segment {
start: self.start - n,
end: self.end - n,
index: self.index,
}
}
}
impl fmt::Debug for Segment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})[{}]", self.start, self.end, self.index)
}
}
#[derive(Clone)]
pub struct UniquePath {
s: String,
segments: Vec<Segment>,
}
impl UniquePath {
pub fn new() -> Self {
UniquePath {
s: String::new(),
segments: Vec::new(),
}
}
pub fn from(s: &str) -> Result<Self, PathError> {
Ok(
NonUniquePath::from(s)?
.unique(0)
)
}
pub fn non_unique(self) -> NonUniquePath {
NonUniquePath {
s: self.s,
segments: self.segments,
}
}
pub fn set_last_index(&mut self, index: usize) {
let len = self.len() - 1;
self.segments[len].index = index;
}
pub fn index(&self, index: usize) -> usize {
if index > self.len() - 1 {
panic!("Out of bounds.")
} else {
self.segments[index].index
}
}
pub fn eq_base(&self, other: &UniquePath) -> bool {
self.clone().non_unique() == other.clone().non_unique()
}
pub fn last_index(&self) -> usize {
self.segments[self.len() - 1].index
}
pub fn is_empty(&self) -> bool {
self.s.is_empty()
}
pub fn segment_str(&self, n: usize) -> &str {
&self.s[self.segments[n].start..=self.segments[n].end]
}
pub fn len(&self) -> usize {
self.segments.len()
}
pub fn append_unique(self, other: &UniquePath) -> UniquePath {
if self.is_empty() { return other.clone() };
if other.is_empty() { return self };
let mut segments = self.segments;
let rshift = self.s.len() + 2;
for seg in other.segments.iter() {
segments.push(seg.right_shift(rshift));
}
let mut s = self.s;
if s != "" { s.push_str("::") };
s.push_str(&other.s);
UniquePath {
s: s,
segments: segments,
}
}
pub fn append_non_unique(self, other: &NonUniquePath) -> NonUniquePath {
if self.is_empty() { return other.clone() };
if other.is_empty() { panic!("other must not be empty.") };
let mut segments = self.segments;
let rshift = self.s.len() + 2;
for seg in other.segments.iter() {
segments.push(seg.right_shift(rshift));
}
let mut s = self.s;
if s != "" { s.push_str("::") };
s.push_str(&other.s);
NonUniquePath {
s: s,
segments: segments,
}
}
pub fn truncate(self, n: usize) -> UniquePath {
if n == 0 {
UniquePath {
s: String::new(),
segments: Vec::new(),
}
} else if n <= self.len() {
let l = self.segments[0].start;
let r = self.segments[n - 1].end;
let mut segments = self.segments;
segments.truncate(n);
UniquePath {
s: self.s[l..=r].to_string(),
segments: segments,
}
} else {
panic!("Out of bounds.");
}
}
pub fn remove(self, n: usize) -> UniquePath {
if n > self.len() { panic!("remove() Out of bounds") };
let len = self.len();
self.truncate(len - n)
}
pub fn debug(&self) -> String {
format!("{:?}", self)
}
}
impl PartialEq for UniquePath {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() { return false };
(0..self.len())
.all(|i| {
self.segment_str(i) == other.segment_str(i) &&
self.segments[i].index == other.segments[i].index
})
}
}
impl Hash for UniquePath {
fn hash<H: Hasher>(&self, state: &mut H) {
self
.segments
.iter()
.map(|seg| seg.index)
.for_each(|i| i.hash(state));
}
}
impl Eq for UniquePath {}
impl Ord for UniquePath {
fn cmp(&self, other: &Self) -> Ordering {
let min = self.len().min(other.len());
for n in 0..min {
match self.len().cmp(&other.len()) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => {
match self.segment_str(n).cmp(other.segment_str(n)) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => {
match (self.segments[n].index).cmp(&other.segments[n].index) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => { continue },
}
},
}
},
}
};
Ordering::Equal
}
}
impl PartialOrd for UniquePath {
fn partial_cmp(&self, other: &UniquePath) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Display for UniquePath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.s)
}
}
impl fmt::Debug for UniquePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_empty() {
write!(f, "{}", "(empty)")
} else {
let mut s = String::new();
for i in 0..self.len() {
s.push_str(self.segment_str(i));
if i < self.len() {
s.push_str(&format!("[{}]", self.index(i)));
s.push_str("::");
}
};
s.pop();
s.pop();
write!(f, "{}", s)
}
}
}
#[derive(Clone)]
pub struct NonUniquePath {
s: String,
segments: Vec<Segment>,
}
impl NonUniquePath {
pub fn len(&self) -> usize {
self.segments.len()
}
pub fn unique(self, index: usize) -> UniquePath {
let mut segments = self.segments;
let len = segments.len() - 1;
segments[len].index = index;
UniquePath {
s: self.s,
segments: segments,
}
}
pub fn index(&self, index: usize) -> usize {
if index <= self.len() - 2 {
self.segments[index].index
} else {
panic!("Out of bounds.");
}
}
pub fn is_empty(&self) -> bool {
self.s.is_empty()
}
pub fn segment_str(&self, n: usize) -> &str {
&self.s[self.segments[n].start..=self.segments[n].end]
}
pub fn from(s: &str) -> Result<Self, PathError> {
let mut parser_state = PS::Segment;
let mut leftpos = 0usize;
let mut segments: Vec<Segment> = Vec::new();
if s == "" {
return Ok(
NonUniquePath {
s: String::new(),
segments: segments,
}
)
};
for (pos, ch) in s.char_indices() {
match (&parser_state, ch) {
(_, '\n') => {
return Err(PathError::Parse(s.to_string(), pos))
},
(PS::Segment, ':') => {
if pos > leftpos {
segments.push(Segment::new(0, leftpos, pos - 1));
parser_state = PS::Separator;
} else {
return Err(PathError::Parse(s.to_string(), pos))
}
},
(PS::Segment, ch) => {
if ch.is_whitespace() {
return Err(PathError::Parse(s.to_string(), pos));
}
},
(PS::Separator, ':') => {
leftpos = pos + 1;
parser_state = PS::Segment;
},
(PS::Separator, _) => {
return Err(PathError::Parse(s.to_string(), pos))
},
}
};
if leftpos == s.len() {
return Err(PathError::Parse(s.to_string(), s.len()))
};
match parser_state {
PS::Segment => segments.push(Segment::new(0, leftpos, s.len() - 1)),
_ => return Err(PathError::Parse(s.to_string(), s.len())),
};
Ok(NonUniquePath {
s: s.to_string(),
segments: segments,
})
}
pub fn truncate(&self, n: usize) -> Result<UniquePath, PathError> {
if n == 0 {
Ok(
UniquePath {
s: String::new(),
segments: Vec::new(),
}
)
} else if n > self.len() - 1 {
Err(PathError::OutOfBounds)
} else {
let s = self.s
.clone()[self.segments[0].start..=self.segments[n].end]
.to_string();
let mut segments = self.segments.clone();
segments.truncate(n);
Ok(
UniquePath {
s: s,
segments: segments,
}
)
}
}
pub fn tail(self) -> NonUniquePath {
if self.is_empty() {
self
} else if self.len() == 1 {
NonUniquePath {
s: String::new(),
segments: Vec::new(),
}
} else {
let len = self.segments.len();
let s = self.s[self.segments[1].start..=self.segments[len - 1].end]
.to_string();
let lshift = self.segments[0].end - self.segments[0].start + 3;
let segments = self.segments[1..]
.iter()
.map(|seg| {
seg.left_shift(lshift)
})
.collect();
NonUniquePath {
s: s,
segments: segments,
}
}
}
pub fn debug(&self) -> String {
format!("{:?}", self)
}
}
impl Hash for NonUniquePath {
fn hash<H: Hasher>(&self, state: &mut H) {
&self.s.hash(state);
if self.len() > 1 {
let len = self.segments.len() - 2;
self
.segments
.iter()
.take(len)
.map(|seg| seg.index)
.for_each(|i| i.hash(state));
};
}
}
impl PartialEq for NonUniquePath {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() { return false };
(0..self.len() - 1)
.all(|i| {
self.segment_str(i) == other.segment_str(i) &&
self.segments[i].index == other.segments[i].index
})
&&
self.segment_str(self.len() - 1) == other.segment_str(self.len() - 1)
}
}
impl Eq for NonUniquePath {}
impl Ord for NonUniquePath {
fn cmp(&self, other: &Self) -> Ordering {
let min = self.len().min(other.len());
for n in 0..min - 1 {
match self.segment_str(n).cmp(other.segment_str(n)) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => {
match (self.segments[n].index).cmp(&other.segments[n].index) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => continue,
};
},
};
};
match self.segment_str(min - 1).cmp(other.segment_str(min - 1)) {
Ordering::Less => { return Ordering::Less },
Ordering::Greater => { return Ordering::Greater },
Ordering::Equal => { return self.len().cmp(&other.len()) },
};
}
}
impl PartialOrd for NonUniquePath {
fn partial_cmp(&self, other: &NonUniquePath) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Debug for NonUniquePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
if self.is_empty() {
write!(f, "{}", "(empty)")
} else {
for i in 0..self.len() - 1 {
s.push_str(&format!("{}[{}]::", self.segment_str(i), self.index(i)));
};
s.push_str(&format!("{}[..]", self.segment_str(self.len() - 1)));
write!(f, "{}", s)
}
}
}