use crate::form::name::*;
#[derive(Copy, Clone)]
pub struct NameView<'v> {
name: &'v Name,
start: usize,
end: usize,
}
impl<'v> NameView<'v> {
pub fn new<N: Into<&'v Name>>(name: N) -> Self {
let mut view = NameView {
name: name.into(),
start: 0,
end: 0,
};
view.shift();
view
}
pub fn shift(&mut self) {
const START_DELIMS: &[char] = &['.', '['];
let string = &self.name[self.end..];
let bytes = string.as_bytes();
let shift = match bytes.first() {
None | Some(b'=') => 0,
Some(b'[') => match memchr::memchr(b']', bytes) {
Some(j) => j + 1,
None => bytes.len(),
},
Some(b'.') => match string[1..].find(START_DELIMS) {
Some(j) => j + 1,
None => bytes.len(),
},
_ => match string.find(START_DELIMS) {
Some(j) => j,
None => bytes.len(),
},
};
debug_assert!(self.end + shift <= self.name.len());
*self = NameView {
name: self.name,
start: self.end,
end: self.end + shift,
};
}
pub fn key(&self) -> Option<&'v Key> {
let lossy_key = self.key_lossy();
if lossy_key.is_empty() {
return None;
}
Some(lossy_key)
}
pub fn key_lossy(&self) -> &'v Key {
let view = &self.name[self.start..self.end];
let key = match view.as_bytes().first() {
Some(b'.') => &view[1..],
Some(b'[') if view.ends_with(']') => &view[1..view.len() - 1],
Some(b'[') if self.is_at_last() => &view[1..],
_ => view,
};
key.as_str().into()
}
pub fn as_name(&self) -> &'v Name {
&self.name[..self.end]
}
pub fn parent(&self) -> Option<&'v Name> {
if self.start > 0 {
Some(&self.name[..self.start])
} else {
None
}
}
pub fn source(&self) -> &'v Name {
self.name
}
fn is_at_last(&self) -> bool {
self.end == self.name.len()
}
pub(crate) fn exhausted(&self) -> bool {
self.start == self.name.len()
}
}
impl std::fmt::Debug for NameView<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_name().fmt(f)
}
}
impl std::fmt::Display for NameView<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_name().fmt(f)
}
}
impl<'a, 'b> PartialEq<NameView<'b>> for NameView<'a> {
fn eq(&self, other: &NameView<'b>) -> bool {
self.as_name() == other.as_name()
}
}
impl<B: PartialEq<Name>> PartialEq<B> for NameView<'_> {
fn eq(&self, other: &B) -> bool {
other == self.as_name()
}
}
impl Eq for NameView<'_> {}
impl std::hash::Hash for NameView<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_name().hash(state)
}
}
impl std::borrow::Borrow<Name> for NameView<'_> {
fn borrow(&self) -> &Name {
self.as_name()
}
}