use crate::parser::ParseError;
use crate::JsonPointer;
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Token {
Slash,
Literal(char),
Escaped(Escape),
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Escape {
Tilde = 0,
Slash = 1,
}
impl From<Escape> for char {
fn from(val: Escape) -> Self {
match val {
Escape::Tilde => '~',
Escape::Slash => '/',
}
}
}
pub fn parse<II: IntoIterator<Item=char>>(ii: II) -> Result<JsonPointer<String, Vec<String>>, ParseError> {
let toks = Tokenizer::new(ii).collect::<Result<Vec<_>, _>>()?;
let mut iter = toks.split(|t| t == &Token::Slash);
if iter.next().map(|s| !s.is_empty()).unwrap_or(false) {
return Err(ParseError::NoLeadingSlash);
}
let mut parts = Vec::new();
for s in iter {
let mut part = String::new();
for ch in s {
part.push(match *ch {
Token::Slash => unreachable!(),
Token::Literal(c) => c,
Token::Escaped(e) => e.into(),
});
}
parts.push(part);
}
Ok(JsonPointer::new(parts.into_iter().collect()))
}
pub struct Tokenizer<I: Iterator<Item=char>> {
iter: I,
}
impl<I: Iterator<Item=char>> Tokenizer<I> {
pub fn new<II: IntoIterator<Item=char, IntoIter=I>>(ii: II) -> Tokenizer<I> {
Tokenizer {
iter: ii.into_iter(),
}
}
}
impl<I: Iterator<Item=char>> Iterator for Tokenizer<I> {
type Item = Result<Token, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some('/') => Some(Ok(Token::Slash)),
Some('~') => match self.iter.next() {
Some('0') => Some(Ok(Token::Escaped(Escape::Tilde))),
Some('1') => Some(Ok(Token::Escaped(Escape::Slash))),
Some(c) => Some(Err(ParseError::InvalidEscape(format!("~{}", c)))),
None => Some(Err(ParseError::InvalidEscape("~".to_string()))),
},
Some(c) => Some(Ok(Token::Literal(c))),
None => None,
}
}
}