1use alloc::string::ToString;
2use udled::{Lex, Span, Tokenizer};
3use unicode_segmentation::UnicodeSegmentation;
4
5pub struct IgnoreCase<T>(pub T);
6
7impl<T> Tokenizer for IgnoreCase<T>
8where
9 T: AsRef<str>,
10{
11 type Token<'a> = Lex<'a>;
12
13 fn to_token<'a>(
14 &self,
15 reader: &mut udled::Reader<'_, 'a>,
16 ) -> Result<Self::Token<'a>, udled::Error> {
17 let tokens = self.0.as_ref().graphemes(true);
18
19 let start = reader.position();
20
21 for token in tokens {
22 let next = reader.eat_ch()?;
23 if token.to_lowercase() != next.to_lowercase() {
24 return Err(reader.error(self.0.as_ref().to_string()));
25 }
26 }
27
28 if start == reader.position() {
29 return Err(reader.error(self.0.as_ref().to_string()));
30 }
31
32 let span = Span::new(start, reader.position());
33 let lex = span.slice(reader.source()).expect("Slice");
34
35 Ok(Lex::new(lex, span))
36 }
37}
38
39#[cfg(test)]
40mod test {
41 use udled::Input;
42
43 use super::IgnoreCase;
44
45 macro_rules! parse {
46 ($parser: literal, $($input:literal),+) => {
47 $(
48 let mut input = Input::new($input);
49 let ret = input.parse(IgnoreCase($parser)).expect("parse");
50
51 assert_eq!($input,ret.as_str());
52 )+
53 };
54 }
55
56 #[test]
57
58 fn ignore_case() {
59 parse!("DOCTYPE", "docType", "DOCTYPE", "DocType");
60 parse!("ÆæpÅLLÆ", "ææpållæ");
61 }
62}