-
Notifications
You must be signed in to change notification settings - Fork 93
Expand file tree
/
Copy pathmod.rs
More file actions
152 lines (137 loc) · 4.85 KB
/
mod.rs
File metadata and controls
152 lines (137 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use std::any::Any;
pub(crate) use self::mutations::{Mutations, StringChunk};
pub(crate) use self::text_decoder::TextDecoder;
pub(crate) use self::text_encoder::{IncompleteUtf8Resync, TextEncoder};
pub use self::document_end::*;
pub use self::element::*;
pub use self::mutations::{ContentType, StreamingHandler};
pub use self::streaming_sink::StreamingHandlerSink;
pub use self::text_encoder::Utf8Error;
pub use self::tokens::*;
/// Data that can be attached to a rewritable unit by a user and shared between content handler
/// invocations.
///
/// Same rewritable units can be passed to different content handlers if all of them capture the
/// unit. `UserData` trait provides capability to attach arbitrary data to a rewritable unit, so
/// handlers can make decision on how to process the unit based on the information provided by
/// previous handlers.
///
/// # Example
/// ```
/// use lol_html::{rewrite_str, element, RewriteStrSettings};
/// use lol_html::html_content::UserData;
///
/// rewrite_str(
/// r#"<div id="foo"></div>"#,
/// RewriteStrSettings {
/// element_content_handlers: vec![
/// element!("*", |el| {
/// el.set_user_data("Captured by `*`");
///
/// Ok(())
/// }),
/// element!("#foo", |el| {
/// let user_data = el.user_data_mut().downcast_mut::<&'static str>().unwrap();
///
/// assert_eq!(*user_data, "Captured by `*`");
///
/// *user_data = "Captured by `#foo`";
///
/// Ok(())
/// }),
/// element!("div", |el| {
/// let user_data = el.user_data().downcast_ref::<&'static str>().unwrap();
///
/// assert_eq!(*user_data, "Captured by `#foo`");
///
/// Ok(())
/// })
/// ],
/// ..RewriteStrSettings::new()
/// }
/// ).unwrap();
/// ```
pub trait UserData {
/// Returns a reference to the attached user data.
fn user_data(&self) -> &dyn Any;
/// Returns a mutable reference to the attached user data.
fn user_data_mut(&mut self) -> &mut dyn Any;
/// Attaches user data to a rewritable unit.
fn set_user_data(&mut self, data: impl Any);
}
macro_rules! impl_user_data {
($Unit:ident<$($lt:lifetime),+>) => {
impl crate::rewritable_units::UserData for $Unit<$($lt),+> {
#[inline]
fn user_data(&self) -> &dyn Any {
&*self.user_data
}
#[inline]
fn user_data_mut(&mut self) -> &mut dyn Any {
&mut *self.user_data
}
#[inline]
fn set_user_data(&mut self, data: impl Any){
self.user_data = Box::new(data);
}
}
};
}
#[macro_use]
mod mutations;
mod document_end;
mod element;
mod streaming_sink;
mod text_decoder;
mod text_encoder;
mod tokens;
#[cfg(test)]
mod test_utils {
use crate::rewriter::AsciiCompatibleEncoding;
use crate::test_utils::{Output, ASCII_COMPATIBLE_ENCODINGS};
use crate::*;
use encoding_rs::Encoding;
use std::borrow::Cow;
pub(crate) fn encoded(input: &str) -> Vec<(Vec<u8>, &'static Encoding)> {
ASCII_COMPATIBLE_ENCODINGS
.iter()
.filter_map(|enc| {
let (input, _, has_unmappable_characters) = enc.encode(input);
// NOTE: there is no character in existence outside of ASCII range
// that can be represented in all the ASCII-compatible encodings.
// So, if test cases contains some non-ASCII characters that can't
// be represented in the given encoding then we just skip it.
// It is OK to do so, because our intention is not to test the
// encoding library itself (it is already well tested), but test
// how our own code works with non-ASCII characters.
if has_unmappable_characters {
None
} else {
Some((input.into_owned(), *enc))
}
})
.collect()
}
pub(crate) fn rewrite_html<'h>(
html: &[u8],
encoding: &'static Encoding,
element_content_handlers: Vec<(Cow<'_, Selector>, ElementContentHandlers<'h>)>,
document_content_handlers: Vec<DocumentContentHandlers<'h>>,
) -> String {
let mut output = Output::new(encoding);
{
let mut rewriter = HtmlRewriter::new(
Settings {
element_content_handlers,
document_content_handlers,
encoding: AsciiCompatibleEncoding::new(encoding).unwrap(),
..Settings::new()
},
|c: &[u8]| output.push(c),
);
rewriter.write(html).unwrap();
rewriter.end().unwrap();
}
output.into()
}
}