use memchr::memchr2;
use crate::{Error, Indexer, Result};
use std::{
collections::VecDeque,
convert::TryFrom,
fmt::{self, Display, Formatter},
ops::{Deref, DerefMut},
str::FromStr,
};
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct IndexPath<'a>(VecDeque<Indexer<'a>>);
impl<'a> Deref for IndexPath<'a> {
type Target = VecDeque<Indexer<'a>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> DerefMut for IndexPath<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum IndexPathState {
Start,
BracketOpen,
BracketClose,
End,
}
impl FromStr for IndexPath<'static> {
type Err = Error<'static>;
fn from_str(s: &str) -> Result<'static, Self> {
IndexPath::parse(s)
.map(IndexPath::into_owned)
.map_err(Error::into_owned)
}
}
impl<'a> IndexPath<'a> {
pub fn into_owned(self) -> IndexPath<'static> {
IndexPath(self.0.into_iter().map(Indexer::into_owned).collect())
}
pub fn parse(mut s: &'a str) -> Result<'a, Self> {
let orig = s;
use IndexPathState::*;
let mut v = VecDeque::new();
let mut state = Start;
loop {
if s.is_empty() || state == End {
break;
}
let (divider, current) = if let Some(divider) = memchr2(b']', b'[', s.as_bytes()) {
let ret = (Some(s.as_bytes()[divider] as char), &s[..divider]);
s = &s[divider + 1..];
ret
} else {
(None, s)
};
let mut push = || {
v.push_back(if current.is_empty() {
Indexer::Empty
} else if let Ok(u) = current.parse::<usize>() {
Indexer::Number(u)
} else {
Indexer::from(current)
});
};
state = match (state, divider) {
(_, None) => {
push();
End
}
(Start, Some('[')) => {
push();
BracketOpen
}
(BracketOpen, Some(']')) => {
push();
BracketClose
}
(BracketClose, Some('[')) => BracketOpen,
_ => return Err(Error::CouldNotParseIndexer(divider, state, orig.into())),
};
}
Ok(IndexPath(v))
}
}
impl From<usize> for IndexPath<'static> {
fn from(path: usize) -> Self {
Self(vec![Indexer::Number(path)].into())
}
}
impl TryFrom<String> for IndexPath<'static> {
type Error = Error<'static>;
fn try_from(path: String) -> Result<'static, Self> {
IndexPath::parse(&path)
.map_err(Error::into_owned)
.map(IndexPath::into_owned)
}
}
impl<'a> TryFrom<&'a str> for IndexPath<'a> {
type Error = Error<'a>;
fn try_from(path: &'a str) -> Result<'a, Self> {
IndexPath::parse(path)
}
}
impl<'a> TryFrom<&'a String> for IndexPath<'a> {
type Error = Error<'a>;
fn try_from(path: &'a String) -> Result<'a, Self> {
IndexPath::parse(path.as_str())
}
}
impl<'a, T> From<Vec<T>> for IndexPath<'a>
where
Indexer<'a>: From<T>,
{
fn from(other: Vec<T>) -> Self {
Self(other.into_iter().map(Indexer::from).collect())
}
}
impl<'a, T> From<&'a Vec<T>> for IndexPath<'a>
where
T: 'a,
Indexer<'a>: From<&'a T>,
{
fn from(other: &'a Vec<T>) -> Self {
Self(other.iter().map(Indexer::from).collect())
}
}
impl<'a, T> PartialEq<Vec<T>> for IndexPath<'a>
where
T: Clone,
Indexer<'a>: From<T>,
{
fn eq(&self, other: &Vec<T>) -> bool {
self.0 == other.iter().map(|i| i.clone().into()).collect::<Vec<_>>()
}
}
impl Display for IndexPath<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut iter = self.0.iter();
if let Some(first) = iter.next() {
f.write_fmt(format_args!("{first}"))?;
}
for indexer in iter {
f.write_fmt(format_args!("[{indexer}]"))?;
}
Ok(())
}
}
impl From<()> for IndexPath<'static> {
fn from(_: ()) -> Self {
Self::from(vec![()])
}
}
impl<'a> From<Indexer<'a>> for IndexPath<'a> {
fn from(indexer: Indexer<'a>) -> Self {
Self::from(vec![indexer])
}
}