use crate::rewritable_units::{Comment, Doctype, DocumentEnd, Element, EndTag, TextChunk};
use crate::selectors_vm::Selector;
use super::AsciiCompatibleEncoding;
use std::borrow::Cow;
use std::error::Error;
pub trait HandlerTypes: Sized {
type DoctypeHandler<'h>: FnMut(&mut Doctype) -> HandlerResult + 'h;
type CommentHandler<'h>: FnMut(&mut Comment) -> HandlerResult + 'h;
type TextHandler<'h>: FnMut(&mut TextChunk) -> HandlerResult + 'h;
type ElementHandler<'h>: FnMut(&mut Element<'_, '_, Self>) -> HandlerResult + 'h;
type EndTagHandler<'h>: FnOnce(&mut EndTag) -> HandlerResult + 'h;
type EndHandler<'h>: FnOnce(&mut DocumentEnd) -> HandlerResult + 'h;
#[doc(hidden)]
fn new_end_tag_handler<'h>(
handler: impl IntoHandler<EndTagHandlerSend<'h>>,
) -> Self::EndTagHandler<'h>;
#[doc(hidden)]
fn new_element_handler<'h>(
handler: impl IntoHandler<ElementHandlerSend<'h, Self>>,
) -> Self::ElementHandler<'h>;
#[doc(hidden)]
fn combine_handlers(handlers: Vec<Self::EndTagHandler<'_>>) -> Self::EndTagHandler<'_>;
}
pub struct LocalHandlerTypes {}
impl HandlerTypes for LocalHandlerTypes {
type DoctypeHandler<'h> = DoctypeHandler<'h>;
type CommentHandler<'h> = CommentHandler<'h>;
type TextHandler<'h> = TextHandler<'h>;
type ElementHandler<'h> = ElementHandler<'h>;
type EndTagHandler<'h> = EndTagHandler<'h>;
type EndHandler<'h> = EndHandler<'h>;
fn new_end_tag_handler<'h>(
handler: impl IntoHandler<EndTagHandlerSend<'h>>,
) -> Self::EndTagHandler<'h> {
handler.into_handler()
}
fn new_element_handler<'h>(
handler: impl IntoHandler<ElementHandlerSend<'h, LocalHandlerTypes>>,
) -> Self::ElementHandler<'h> {
handler.into_handler()
}
fn combine_handlers(handlers: Vec<Self::EndTagHandler<'_>>) -> Self::EndTagHandler<'_> {
Box::new(move |end_tag: &mut EndTag| {
for handler in handlers {
handler(end_tag)?;
}
Ok(())
})
}
}
pub struct SendHandlerTypes {}
impl HandlerTypes for SendHandlerTypes {
type DoctypeHandler<'h> = DoctypeHandlerSend<'h>;
type CommentHandler<'h> = CommentHandlerSend<'h>;
type TextHandler<'h> = TextHandlerSend<'h>;
type ElementHandler<'h> = ElementHandlerSend<'h, SendHandlerTypes>;
type EndTagHandler<'h> = EndTagHandlerSend<'h>;
type EndHandler<'h> = EndHandlerSend<'h>;
fn new_end_tag_handler<'h>(
handler: impl IntoHandler<EndTagHandlerSend<'h>>,
) -> Self::EndTagHandler<'h> {
handler.into_handler()
}
fn new_element_handler<'h>(
handler: impl IntoHandler<ElementHandlerSend<'h, SendHandlerTypes>>,
) -> Self::ElementHandler<'h> {
handler.into_handler()
}
fn combine_handlers(handlers: Vec<Self::EndTagHandler<'_>>) -> Self::EndTagHandler<'_> {
Box::new(move |end_tag: &mut EndTag| {
for handler in handlers {
handler(end_tag)?;
}
Ok(())
})
}
}
pub type HandlerResult = Result<(), Box<dyn Error + Send + Sync>>;
pub type DoctypeHandler<'h> = Box<dyn FnMut(&mut Doctype) -> HandlerResult + 'h>;
pub type CommentHandler<'h> = Box<dyn FnMut(&mut Comment) -> HandlerResult + 'h>;
pub type TextHandler<'h> = Box<dyn FnMut(&mut TextChunk) -> HandlerResult + 'h>;
pub type ElementHandler<'h> =
Box<dyn FnMut(&mut Element<'_, '_, LocalHandlerTypes>) -> HandlerResult + 'h>;
pub type EndTagHandler<'h> = Box<dyn FnOnce(&mut EndTag) -> HandlerResult + 'h>;
pub type EndHandler<'h> = Box<dyn FnOnce(&mut DocumentEnd) -> HandlerResult + 'h>;
pub type DoctypeHandlerSend<'h> = Box<dyn FnMut(&mut Doctype) -> HandlerResult + Send + 'h>;
pub type CommentHandlerSend<'h> = Box<dyn FnMut(&mut Comment) -> HandlerResult + Send + 'h>;
pub type TextHandlerSend<'h> = Box<dyn FnMut(&mut TextChunk) -> HandlerResult + Send + 'h>;
pub type ElementHandlerSend<'h, H = SendHandlerTypes> =
Box<dyn FnMut(&mut Element<'_, '_, H>) -> HandlerResult + Send + 'h>;
pub type EndTagHandlerSend<'h> = Box<dyn FnOnce(&mut EndTag) -> HandlerResult + Send + 'h>;
pub type EndHandlerSend<'h> = Box<dyn FnOnce(&mut DocumentEnd) -> HandlerResult + Send + 'h>;
pub trait IntoHandler<T> {
fn into_handler(self) -> T;
}
impl<'h, F: FnMut(&mut Doctype) -> HandlerResult + 'h> IntoHandler<DoctypeHandler<'h>> for F {
fn into_handler(self) -> DoctypeHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut Comment) -> HandlerResult + 'h> IntoHandler<CommentHandler<'h>> for F {
fn into_handler(self) -> CommentHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut TextChunk) -> HandlerResult + 'h> IntoHandler<TextHandler<'h>> for F {
fn into_handler(self) -> TextHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut Element<'_, '_, LocalHandlerTypes>) -> HandlerResult + 'h>
IntoHandler<ElementHandler<'h>> for F
{
fn into_handler(self) -> ElementHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnOnce(&mut EndTag) -> HandlerResult + 'h> IntoHandler<EndTagHandler<'h>> for F {
fn into_handler(self) -> EndTagHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnOnce(&mut DocumentEnd) -> HandlerResult + 'h> IntoHandler<EndHandler<'h>> for F {
fn into_handler(self) -> EndHandler<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut Doctype) -> HandlerResult + Send + 'h> IntoHandler<DoctypeHandlerSend<'h>>
for F
{
fn into_handler(self) -> DoctypeHandlerSend<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut Comment) -> HandlerResult + Send + 'h> IntoHandler<CommentHandlerSend<'h>>
for F
{
fn into_handler(self) -> CommentHandlerSend<'h> {
Box::new(self)
}
}
impl<'h, F: FnMut(&mut TextChunk) -> HandlerResult + Send + 'h> IntoHandler<TextHandlerSend<'h>>
for F
{
fn into_handler(self) -> TextHandlerSend<'h> {
Box::new(self)
}
}
impl<'h, H: HandlerTypes, F: FnMut(&mut Element<'_, '_, H>) -> HandlerResult + Send + 'h>
IntoHandler<ElementHandlerSend<'h, H>> for F
{
fn into_handler(self) -> ElementHandlerSend<'h, H> {
Box::new(self)
}
}
impl<'h, F: FnOnce(&mut EndTag) -> HandlerResult + Send + 'h> IntoHandler<EndTagHandlerSend<'h>>
for F
{
fn into_handler(self) -> EndTagHandlerSend<'h> {
Box::new(self)
}
}
impl<'h, F: FnOnce(&mut DocumentEnd) -> HandlerResult + Send + 'h> IntoHandler<EndHandlerSend<'h>>
for F
{
fn into_handler(self) -> EndHandlerSend<'h> {
Box::new(self)
}
}
pub struct ElementContentHandlers<'h, H: HandlerTypes = LocalHandlerTypes> {
pub element: Option<H::ElementHandler<'h>>,
pub comments: Option<H::CommentHandler<'h>>,
pub text: Option<H::TextHandler<'h>>,
}
impl<'h, H: HandlerTypes> Default for ElementContentHandlers<'h, H> {
fn default() -> Self {
ElementContentHandlers {
element: None,
comments: None,
text: None,
}
}
}
impl<'h, H: HandlerTypes> ElementContentHandlers<'h, H> {
#[inline]
pub fn element(mut self, handler: impl IntoHandler<H::ElementHandler<'h>>) -> Self {
self.element = Some(handler.into_handler());
self
}
#[inline]
pub fn comments(mut self, handler: impl IntoHandler<H::CommentHandler<'h>>) -> Self {
self.comments = Some(handler.into_handler());
self
}
#[inline]
pub fn text(mut self, handler: impl IntoHandler<H::TextHandler<'h>>) -> Self {
self.text = Some(handler.into_handler());
self
}
}
pub struct DocumentContentHandlers<'h, H: HandlerTypes = LocalHandlerTypes> {
pub doctype: Option<H::DoctypeHandler<'h>>,
pub comments: Option<H::CommentHandler<'h>>,
pub text: Option<H::TextHandler<'h>>,
pub end: Option<H::EndHandler<'h>>,
}
impl<'h, H: HandlerTypes> Default for DocumentContentHandlers<'h, H> {
fn default() -> Self {
DocumentContentHandlers {
doctype: None,
comments: None,
text: None,
end: None,
}
}
}
impl<'h, H: HandlerTypes> DocumentContentHandlers<'h, H> {
#[inline]
pub fn doctype(mut self, handler: impl IntoHandler<H::DoctypeHandler<'h>>) -> Self {
self.doctype = Some(handler.into_handler());
self
}
#[inline]
pub fn comments(mut self, handler: impl IntoHandler<H::CommentHandler<'h>>) -> Self {
self.comments = Some(handler.into_handler());
self
}
#[inline]
pub fn text(mut self, handler: impl IntoHandler<H::TextHandler<'h>>) -> Self {
self.text = Some(handler.into_handler());
self
}
#[inline]
pub fn end(mut self, handler: impl IntoHandler<H::EndHandler<'h>>) -> Self {
self.end = Some(handler.into_handler());
self
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __element_content_handler {
($selector:expr, $handler_name:ident, $handler:expr) => {
(
::std::borrow::Cow::Owned($selector.parse::<$crate::Selector>().unwrap()),
$crate::ElementContentHandlers::default().$handler_name($handler),
)
};
}
#[macro_export(local_inner_macros)]
macro_rules! element {
($selector:expr, $handler:expr) => {{
#[inline(always)]
fn type_hint<'h, T, H: $crate::HandlerTypes>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::Element<'_, '_, H>) -> $crate::HandlerResult + 'h,
{
h
}
__element_content_handler!($selector, element, type_hint($handler))
}};
}
#[macro_export(local_inner_macros)]
macro_rules! text {
($selector:expr, $handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::TextChunk) -> $crate::HandlerResult,
{
h
}
__element_content_handler!($selector, text, type_hint($handler))
}};
}
#[macro_export(local_inner_macros)]
macro_rules! comments {
($selector:expr, $handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::Comment) -> $crate::HandlerResult,
{
h
}
__element_content_handler!($selector, comments, type_hint($handler))
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __document_content_handler {
($handler_name:ident, $handler:expr) => {
$crate::DocumentContentHandlers::default().$handler_name($handler)
};
}
#[macro_export(local_inner_macros)]
macro_rules! doctype {
($handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::Doctype) -> $crate::HandlerResult,
{
h
}
__document_content_handler!(doctype, type_hint($handler))
}};
}
#[macro_export(local_inner_macros)]
macro_rules! doc_text {
($handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::TextChunk) -> $crate::HandlerResult,
{
h
}
__document_content_handler!(text, type_hint($handler))
}};
}
#[macro_export(local_inner_macros)]
macro_rules! doc_comments {
($handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnMut(&mut $crate::html_content::Comment) -> $crate::HandlerResult,
{
h
}
__document_content_handler!(comments, type_hint($handler))
}};
}
#[macro_export(local_inner_macros)]
macro_rules! end {
($handler:expr) => {{
#[inline(always)]
fn type_hint<T>(h: T) -> T
where
T: FnOnce(&mut $crate::html_content::DocumentEnd) -> $crate::HandlerResult,
{
h
}
__document_content_handler!(end, type_hint($handler))
}};
}
#[repr(C)]
pub struct MemorySettings {
pub preallocated_parsing_buffer_size: usize,
pub max_allowed_memory_usage: usize,
}
impl Default for MemorySettings {
#[inline]
fn default() -> Self {
MemorySettings {
preallocated_parsing_buffer_size: 1024,
max_allowed_memory_usage: usize::MAX,
}
}
}
impl MemorySettings {
pub fn new() -> MemorySettings {
MemorySettings::default()
}
}
pub struct Settings<'h, 's, H: HandlerTypes = LocalHandlerTypes> {
pub element_content_handlers: Vec<(Cow<'s, Selector>, ElementContentHandlers<'h, H>)>,
pub document_content_handlers: Vec<DocumentContentHandlers<'h, H>>,
pub encoding: AsciiCompatibleEncoding,
pub memory_settings: MemorySettings,
pub strict: bool,
pub enable_esi_tags: bool,
pub adjust_charset_on_meta_tag: bool,
}
impl Default for Settings<'_, '_, LocalHandlerTypes> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Settings<'_, '_, LocalHandlerTypes> {
#[inline]
pub fn new() -> Self {
Self::new_for_handler_types()
}
}
impl Settings<'_, '_, SendHandlerTypes> {
#[inline]
pub fn new_send() -> Self {
Self::new_for_handler_types()
}
}
impl<H: HandlerTypes> Settings<'_, '_, H> {
#[inline]
pub fn new_for_handler_types() -> Self {
Settings {
element_content_handlers: vec![],
document_content_handlers: vec![],
encoding: AsciiCompatibleEncoding(encoding_rs::UTF_8),
memory_settings: MemorySettings::default(),
strict: true,
enable_esi_tags: false,
adjust_charset_on_meta_tag: false,
}
}
}
impl<'h, 's, H: HandlerTypes> From<RewriteStrSettings<'h, 's, H>> for Settings<'h, 's, H> {
#[inline]
fn from(settings: RewriteStrSettings<'h, 's, H>) -> Self {
Settings {
element_content_handlers: settings.element_content_handlers,
document_content_handlers: settings.document_content_handlers,
strict: settings.strict,
enable_esi_tags: settings.enable_esi_tags,
..Settings::new_for_handler_types()
}
}
}
pub struct RewriteStrSettings<'h, 's, H: HandlerTypes = LocalHandlerTypes> {
pub element_content_handlers: Vec<(Cow<'s, Selector>, ElementContentHandlers<'h, H>)>,
pub document_content_handlers: Vec<DocumentContentHandlers<'h, H>>,
pub strict: bool,
pub enable_esi_tags: bool,
}
impl Default for RewriteStrSettings<'_, '_, LocalHandlerTypes> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl RewriteStrSettings<'_, '_, LocalHandlerTypes> {
#[inline]
pub fn new() -> Self {
Self::new_for_handler_types()
}
}
impl RewriteStrSettings<'_, '_, SendHandlerTypes> {
#[inline]
pub fn new_send() -> Self {
Self::new_for_handler_types()
}
}
impl<H: HandlerTypes> RewriteStrSettings<'_, '_, H> {
#[inline]
pub fn new_for_handler_types() -> Self {
RewriteStrSettings {
element_content_handlers: vec![],
document_content_handlers: vec![],
strict: true,
enable_esi_tags: true,
}
}
}