1use std::fmt::Write;
2
3use super::consume::Consume;
4use super::error::{Error, Message, error};
5use super::whitespace::skip_whitespace;
6
7#[derive(Clone, Copy)]
10pub enum End<'a> {
11
12 EndOfFile,
14
15 Specific(&'static str),
17
18 MatchingBracket(&'a str, &'static str),
22
23 ElementEnd, }
28
29impl<'a> End<'a> {
30
31 fn consume(&self, source: &mut &[u8]) -> bool {
32 match self {
33 End::EndOfFile => source.is_empty(),
34 End::Specific(s) | End::MatchingBracket(_, s) => source.consume(s).is_some(),
35 End::ElementEnd => source.consume_one_of(",;\n").is_some(),
36 }
37 }
38
39 fn matches(&self, mut source: &[u8]) -> bool {
40 self.consume(&mut source)
41 }
42
43 pub fn description(&self) -> String {
46 match self {
47 End::EndOfFile => "end of file".to_string(),
48 End::Specific(s) | End::MatchingBracket(_, s) => format!("`{}'", s),
49 End::ElementEnd => "newline or `,` or `;'".to_string(),
50 }
51 }
52
53 fn error(&self, source: &'a [u8]) -> Error<'a> {
54 let mut e = error(&source[..0], format!("expected {}", self.description()));
55 if let &End::MatchingBracket(b, _) = self {
56 e.notes = vec![Message{
57 message: format!("... to match this `{}'", b),
58 location: Some(b.as_bytes())
59 }];
60 }
61 e
62 }
63
64 pub fn parse(&self, source: &mut &'a [u8]) -> Result<bool, Error<'a>> {
71 skip_whitespace(source, match self { &End::ElementEnd => false, _ => true });
72 let did_match = self.consume(source);
73 if !did_match && source.is_empty() {
74 Err(self.error(*source))
75 } else {
76 Ok(did_match)
77 }
78 }
79
80 pub fn or_before(self, or_before: Self) -> OptionalEnd<'a> {
81 OptionalEnd{ end: self, or_before: Some(or_before) }
82 }
83
84 pub fn as_optional(self) -> OptionalEnd<'a> {
85 OptionalEnd{ end: self, or_before: None }
86 }
87}
88
89pub struct OptionalEnd<'a> {
90 pub end: End<'a>,
91 pub or_before: Option<End<'a>>,
92}
93
94impl<'a> OptionalEnd<'a> {
95
96 pub fn parse(&self, source: &mut &'a [u8]) -> Result<bool, Error<'a>> {
97 skip_whitespace(source, match self.end { End::ElementEnd => false, _ => true });
98 let did_match = self.end.consume(source) || self.or_before.map(|e| e.matches(*source)).unwrap_or(false);
99 if !did_match && source.is_empty() {
100 Err(self.error(*source))
101 } else {
102 Ok(did_match)
103 }
104 }
105
106 pub fn description(&self) -> String {
107 let mut desc = self.end.description();
108 if let Some(e) = self.or_before {
109 write!(&mut desc, " or {}", e.description()).unwrap();
110 }
111 desc
112 }
113
114 fn error(&self, source: &'a [u8]) -> Error<'a> {
115 match self.or_before {
116 None => self.end.error(source),
117 Some(_) => error(&source[..0], format!("expected {}", self.description())),
118 }
119 }
120}
121
122