use super::types::ZeroCopyTagMatch;
pub fn parse_tags_zero_copy(html: &str) -> Vec<ZeroCopyTagMatch<'_>> {
let mut tags = Vec::with_capacity(100000);
let bytes = html.as_bytes();
let mut i = 0;
while i < bytes.len() {
if bytes[i] == b'<' {
let tag_start = i;
if i + 4 < bytes.len()
&& bytes[i + 1] == b'!'
&& bytes[i + 2] == b'-'
&& bytes[i + 3] == b'-'
{
let mut j = i + 4;
while j + 2 < bytes.len() {
if bytes[j] == b'-' && bytes[j + 1] == b'-' && bytes[j + 2] == b'>' {
let end_pos = j + 3;
tags.push(ZeroCopyTagMatch {
start: tag_start,
end: end_pos,
is_comment: true,
is_closing: false,
tag_name: "", attrs: "",
self_closing: false,
});
i = end_pos;
break;
}
j += 1;
}
if j + 2 >= bytes.len() {
i = bytes.len();
}
continue;
}
i += 1;
let is_closing = if i < bytes.len() && bytes[i] == b'/' {
i += 1;
true
} else {
false
};
let tag_name_start = i;
if i >= bytes.len() || !bytes[i].is_ascii_alphabetic() {
i += 1;
continue;
}
i += 1;
while i < bytes.len() {
let b = bytes[i];
if b.is_ascii_alphanumeric()
|| b == b'.' || b == b'_'
|| b == b':' || b == b'@'
|| b == b'-'
{
i += 1;
} else if b >= 0x80 {
i += 1; } else {
break;
}
}
let tag_name = &html[tag_name_start..i];
let mut self_closing = false;
let attr_start = i;
let mut valid_attrs = true;
while i < bytes.len() && bytes[i].is_ascii_whitespace() {
i += 1;
}
while i < bytes.len() && valid_attrs {
if bytes[i] == b'>' {
break;
} else if bytes[i] == b'/' {
let mut j = i + 1;
while j < bytes.len() && bytes[j].is_ascii_whitespace() {
j += 1;
}
if j < bytes.len() && bytes[j] == b'>' {
self_closing = true;
i = j;
break;
} else {
i += 1;
}
} else if bytes[i] == b'"' {
i += 1;
while i < bytes.len() && bytes[i] != b'"' {
i += 1;
}
if i < bytes.len() {
i += 1;
} else {
valid_attrs = false;
}
} else if bytes[i] == b'\'' {
i += 1;
while i < bytes.len() && bytes[i] != b'\'' {
i += 1;
}
if i < bytes.len() {
i += 1;
} else {
valid_attrs = false;
}
} else if bytes[i] == b'>' || bytes[i] == b'"' || bytes[i] == b'\'' {
valid_attrs = false;
} else {
i += 1;
}
}
let attrs = if valid_attrs && attr_start < i {
html[attr_start..i].trim()
} else {
""
};
if i < bytes.len() && bytes[i] == b'>' {
i += 1;
} else {
continue;
}
tags.push(ZeroCopyTagMatch {
start: tag_start,
end: i,
is_comment: false,
is_closing,
tag_name,
attrs,
self_closing,
});
continue;
}
i += 1;
}
tags
}