Parse the cursor's content to ASCII lowercase using any allocator that implements the Allocator trait.
(&self, allocator: A)
| 652 | |
| 653 | /// Parse the cursor's content to ASCII lowercase using any allocator that implements the Allocator trait. |
| 654 | pub fn parse_ascii_lower<A: Allocator + Clone + 'a>(&self, allocator: A) -> CowStr<'a, A> { |
| 655 | debug_assert!(self.token() != Kind::Delim); |
| 656 | let start = self.token().leading_len() as usize; |
| 657 | let end = self.source.len() - self.token().trailing_len() as usize; |
| 658 | if !self.token().contains_escape_chars() && self.token().is_lower_case() { |
| 659 | return CowStr::Borrowed(&self.source[start..end]); |
| 660 | } |
| 661 | let mut chars = self.source[start..end].chars().peekable(); |
| 662 | let mut i = 0; |
| 663 | let mut vec: Vec<u8, A> = Vec::new_in(allocator.clone()); |
| 664 | while let Some(c) = chars.next() { |
| 665 | if c == '\0' { |
| 666 | let mut buf = [0; 4]; |
| 667 | let bytes = REPLACEMENT_CHARACTER.encode_utf8(&mut buf).as_bytes(); |
| 668 | vec.extend_from_slice(bytes); |
| 669 | i += 1; |
| 670 | } else if c == '\\' { |
| 671 | // String has special rules |
| 672 | // https://drafts.csswg.org/css-syntax-3/#consume-string-cursor |
| 673 | if self.token().kind_bits() == Kind::String as u8 { |
| 674 | // When the token is a string, escaped EOF points are not consumed |
| 675 | // U+005C REVERSE SOLIDUS (\) |
| 676 | // If the next input code point is EOF, do nothing. |
| 677 | // Otherwise, if the next input code point is a newline, consume it. |
| 678 | let c = chars.peek(); |
| 679 | if let Some(c) = c { |
| 680 | if is_newline(*c) { |
| 681 | chars.next(); |
| 682 | if chars.peek() == Some(&'\n') { |
| 683 | i += 1; |
| 684 | } |
| 685 | i += 2; |
| 686 | chars = self.source[(start + i)..end].chars().peekable(); |
| 687 | continue; |
| 688 | } |
| 689 | } else { |
| 690 | break; |
| 691 | } |
| 692 | } |
| 693 | i += 1; |
| 694 | let (ch, n) = self.source[(start + i)..].chars().parse_escape_sequence(); |
| 695 | let char_to_push = if ch == '\0' { REPLACEMENT_CHARACTER } else { ch.to_ascii_lowercase() }; |
| 696 | let mut buf = [0; 4]; |
| 697 | let bytes = char_to_push.encode_utf8(&mut buf).as_bytes(); |
| 698 | vec.extend_from_slice(bytes); |
| 699 | i += n as usize; |
| 700 | chars = self.source[(start + i)..end].chars().peekable(); |
| 701 | } else { |
| 702 | let mut buf = [0; 4]; |
| 703 | let bytes = c.to_ascii_lowercase().encode_utf8(&mut buf).as_bytes(); |
| 704 | vec.extend_from_slice(bytes); |
| 705 | i += c.len_utf8(); |
| 706 | } |
| 707 | } |
| 708 | let boxed_slice = vec.into_boxed_slice(); |
| 709 | // SAFETY: The source is valid UTF-8, so the slice is valid UTF-8 |
| 710 | unsafe { CowStr::Owned(Box::from_raw_in(Box::into_raw(boxed_slice) as *mut str, allocator)) } |
| 711 | } |
nothing calls this directly
no test coverage detected