use proc_macro::Span; use crate::format_description::component::{Component, NakedComponent}; use crate::format_description::error::InvalidFormatDescription; use crate::format_description::{helper, modifier, FormatItem}; use crate::Error; struct ParsedItem<'a> { item: FormatItem<'a>, remaining: &'a [u8], } fn parse_component(mut s: &[u8], index: &mut usize) -> Result { s = helper::consume_whitespace(s, index); let component_index = *index; let whitespace_loc = s .iter() .position(u8::is_ascii_whitespace) .unwrap_or(s.len()); *index += whitespace_loc; let component_name = &s[..whitespace_loc]; s = &s[whitespace_loc..]; s = helper::consume_whitespace(s, index); Ok(NakedComponent::parse(component_name, component_index)? .attach_modifiers(modifier::Modifiers::parse(component_name, s, index)?)) } fn parse_literal<'a>(s: &'a [u8], index: &mut usize) -> ParsedItem<'a> { let loc = s.iter().position(|&c| c == b'[').unwrap_or(s.len()); *index += loc; ParsedItem { item: FormatItem::Literal(&s[..loc]), remaining: &s[loc..], } } fn parse_item<'a>( s: &'a [u8], index: &mut usize, ) -> Result, InvalidFormatDescription> { if let [b'[', b'[', remaining @ ..] = s { *index += 2; return Ok(ParsedItem { item: FormatItem::Literal(b"["), remaining, }); }; if s.starts_with(b"[") { if let Some(bracket_index) = s.iter().position(|&c| c == b']') { *index += 1; // opening bracket let ret_val = ParsedItem { item: FormatItem::Component(parse_component(&s[1..bracket_index], index)?), remaining: &s[bracket_index + 1..], }; *index += 1; // closing bracket Ok(ret_val) } else { Err(InvalidFormatDescription::UnclosedOpeningBracket { index: *index }) } } else { Ok(parse_literal(s, index)) } } pub(crate) fn parse(mut s: &[u8], span: Span) -> Result>, Error> { let mut compound = Vec::new(); let mut loc = 0; while !s.is_empty() { let ParsedItem { item, remaining } = parse_item(s, &mut loc).map_err(|error| Error::InvalidFormatDescription { error, span_start: Some(span), span_end: Some(span), })?; s = remaining; compound.push(item); } Ok(compound) }