use crate::segment::Segment;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Variable<'a> {
field: &'a str,
sub: &'a str,
}
impl<'a> Variable<'a> {
pub(crate) fn new(field: &'a str, sub: &'a str) -> Self {
Self { field, sub }
}
#[must_use]
pub fn field_path(&self) -> &'a str {
self.field
}
#[must_use]
pub fn segments(&self) -> SegmentIter<'a> {
SegmentIter {
rest: Some(self.sub),
remaining: self.sub.bytes().filter(|&byte| byte == b'/').count() + 1,
}
}
pub(crate) fn sub(&self) -> &'a str {
self.sub
}
}
#[derive(Debug, Clone)]
pub struct SegmentIter<'a> {
rest: Option<&'a str>,
remaining: usize,
}
impl<'a> Iterator for SegmentIter<'a> {
type Item = Segment<'a>;
fn next(&mut self) -> Option<Self::Item> {
let rest = self.rest?;
debug_assert!(self.remaining > 0);
self.remaining -= 1;
let seg = if let Some(idx) = rest.as_bytes().iter().position(|&b| b == b'/') {
let (seg, after) = rest.split_at(idx);
self.rest = Some(&after[1..]);
seg
} else {
self.rest = None;
rest
};
Some(match seg {
"*" => Segment::Single,
"**" => Segment::Rest,
other => Segment::Literal(other),
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let length = self.len();
(length, Some(length))
}
}
impl ExactSizeIterator for SegmentIter<'_> {
fn len(&self) -> usize {
self.remaining
}
}
impl core::iter::FusedIterator for SegmentIter<'_> {}