@@ -6,12 +6,11 @@ use rustler::env::OwnedEnv;
6
6
use rustler:: types:: binary:: Binary ;
7
7
use rustler:: { Decoder , Encoder , Env , Error , NifResult , Term , rustler_export_nifs} ;
8
8
9
- use html5ever:: rcdom:: RcDom ;
9
+ // use html5ever::rcdom::RcDom;
10
10
use tendril:: TendrilSink ;
11
11
12
12
mod common;
13
13
mod flat_dom;
14
- mod rc_dom;
15
14
16
15
mod atoms {
17
16
rustler:: rustler_atoms! {
@@ -56,6 +55,21 @@ lazy_static! {
56
55
static ref POOL : scoped_pool:: Pool = scoped_pool:: Pool :: new( 4 ) ;
57
56
}
58
57
58
+ fn parse_sync < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
59
+ let binary: Binary = args[ 0 ] . decode ( ) ?;
60
+ let sink = flat_dom:: FlatSink :: new ( ) ;
61
+
62
+ // TODO: Use Parser.from_bytes instead?
63
+ let parser = html5ever:: parse_document ( sink, Default :: default ( ) ) ;
64
+ let result = parser. one ( std:: str:: from_utf8 ( binary. as_slice ( ) ) . unwrap ( ) ) ;
65
+
66
+ // std::thread::sleep(std::time::Duration::from_millis(10));
67
+
68
+ let result_term = flat_dom:: flat_sink_to_rec_term ( env, & result) ;
69
+
70
+ Ok ( ( atoms:: html5ever_nif_result ( ) , atoms:: ok ( ) , result_term) . encode ( env) )
71
+ }
72
+
59
73
fn parse_async < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
60
74
let mut owned_env = OwnedEnv :: new ( ) ;
61
75
@@ -78,17 +92,17 @@ fn parse_async<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult<Term<'a>> {
78
92
Err ( _) => panic ! ( "argument is not a binary" ) ,
79
93
} ;
80
94
81
- let sink = RcDom :: default ( ) ;
95
+ let sink = flat_dom :: FlatSink :: new ( ) ;
82
96
83
97
// TODO: Use Parser.from_bytes instead?
84
98
let parser = html5ever:: parse_document ( sink, Default :: default ( ) ) ;
85
99
let result = parser. one ( std:: str:: from_utf8 ( binary. as_slice ( ) ) . unwrap ( ) ) ;
86
100
87
- let result_term = rc_dom :: handle_to_term ( inner_env, & result. document ) ;
101
+ let result_term = flat_dom :: flat_sink_to_rec_term ( inner_env, & result) ;
88
102
(
89
103
atoms:: html5ever_nif_result ( ) ,
90
104
atoms:: ok ( ) ,
91
- result_term. unwrap ( ) ,
105
+ result_term,
92
106
) . encode ( inner_env)
93
107
} ) {
94
108
Ok ( term) => term,
@@ -111,46 +125,83 @@ fn parse_async<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult<Term<'a>> {
111
125
Ok ( atoms:: ok ( ) . encode ( env) )
112
126
}
113
127
114
- fn parse_sync < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
128
+ fn flat_parse_sync < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
115
129
let binary: Binary = args[ 0 ] . decode ( ) ?;
116
- let sink = RcDom :: default ( ) ;
130
+ let sink = flat_dom :: FlatSink :: new ( ) ;
117
131
118
132
// TODO: Use Parser.from_bytes instead?
119
133
let parser = html5ever:: parse_document ( sink, Default :: default ( ) ) ;
120
134
let result = parser. one ( std:: str:: from_utf8 ( binary. as_slice ( ) ) . unwrap ( ) ) ;
121
135
122
136
// std::thread::sleep(std::time::Duration::from_millis(10));
123
137
124
- let result_term = rc_dom :: handle_to_term ( env, & result. document ) ;
138
+ let result_term = flat_dom :: flat_sink_to_flat_term ( env, & result) ;
125
139
126
- Ok ( (
127
- atoms:: html5ever_nif_result ( ) ,
128
- atoms:: ok ( ) ,
129
- result_term. unwrap ( ) ,
130
- ) . encode ( env) )
140
+ Ok ( ( atoms:: html5ever_nif_result ( ) , atoms:: ok ( ) , result_term) . encode ( env) )
131
141
}
132
142
133
- fn flat_parse_sync < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
134
- let binary: Binary = args[ 0 ] . decode ( ) ?;
135
- let sink = flat_dom:: FlatSink :: new ( ) ;
143
+ fn flat_parse_async < ' a > ( env : Env < ' a > , args : & [ Term < ' a > ] ) -> NifResult < Term < ' a > > {
144
+ let mut owned_env = OwnedEnv :: new ( ) ;
136
145
137
- // TODO: Use Parser.from_bytes instead?
138
- let parser = html5ever:: parse_document ( sink, Default :: default ( ) ) ;
139
- let result = parser. one ( std:: str:: from_utf8 ( binary. as_slice ( ) ) . unwrap ( ) ) ;
146
+ // Copies the term into the inner env. Since this term is normally a large
147
+ // binary term, copying it over should be cheap, since the binary will be
148
+ // refcounted within the BEAM.
149
+ let input_term = owned_env. save ( args[ 0 ] ) ;
140
150
141
- // std::thread::sleep(std::time::Duration::from_millis(10) );
151
+ let return_pid = env . pid ( ) ;
142
152
143
- let result_term = flat_dom :: flat_sink_to_term ( env , & result ) ;
153
+ // let config = term_to_configs(args[1] );
144
154
145
- Ok ( ( atoms:: html5ever_nif_result ( ) , atoms:: ok ( ) , result_term) . encode ( env) )
155
+ POOL . spawn ( move || {
156
+ owned_env. send_and_clear ( & return_pid, |inner_env| {
157
+ // This should not really be done in user code. We (Rustler project)
158
+ // need to find a better abstraction that eliminates this.
159
+ match panic:: catch_unwind ( || {
160
+ let binary: Binary = match input_term. load ( inner_env) . decode ( ) {
161
+ Ok ( inner) => inner,
162
+ Err ( _) => panic ! ( "argument is not a binary" ) ,
163
+ } ;
164
+
165
+ let sink = flat_dom:: FlatSink :: new ( ) ;
166
+
167
+ // TODO: Use Parser.from_bytes instead?
168
+ let parser = html5ever:: parse_document ( sink, Default :: default ( ) ) ;
169
+ let result = parser. one ( std:: str:: from_utf8 ( binary. as_slice ( ) ) . unwrap ( ) ) ;
170
+
171
+ let result_term = flat_dom:: flat_sink_to_flat_term ( inner_env, & result) ;
172
+ (
173
+ atoms:: html5ever_nif_result ( ) ,
174
+ atoms:: ok ( ) ,
175
+ result_term,
176
+ ) . encode ( inner_env)
177
+ } ) {
178
+ Ok ( term) => term,
179
+ Err ( err) => {
180
+ // Try to extract a panic reason and return that. If this
181
+ // fails, fail generically.
182
+ let reason = if let Some ( s) = err. downcast_ref :: < String > ( ) {
183
+ s. encode ( inner_env)
184
+ } else if let Some ( & s) = err. downcast_ref :: < & ' static str > ( ) {
185
+ s. encode ( inner_env)
186
+ } else {
187
+ atoms:: nif_panic ( ) . encode ( inner_env)
188
+ } ;
189
+ ( atoms:: html5ever_nif_result ( ) , atoms:: error ( ) , reason) . encode ( inner_env)
190
+ }
191
+ }
192
+ } ) ;
193
+ } ) ;
194
+
195
+ Ok ( atoms:: ok ( ) . encode ( env) )
146
196
}
147
197
148
198
rustler_export_nifs ! (
149
199
"Elixir.Html5ever.Native" ,
150
200
[
151
- ( "parse_async" , 1 , parse_async) ,
152
201
( "parse_sync" , 1 , parse_sync) ,
153
- ( "flat_parse_sync" , 1 , flat_parse_sync)
202
+ ( "parse_async" , 1 , parse_async) ,
203
+ ( "flat_parse_sync" , 1 , flat_parse_sync) ,
204
+ ( "flat_parse_async" , 1 , flat_parse_async)
154
205
] ,
155
206
Some ( on_load)
156
207
) ;
0 commit comments