summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvin <git@vineetk.net>2025-11-15 19:10:20 -0500
committervin <git@vineetk.net>2025-11-15 19:16:04 -0500
commitfb3aec03f48ef89c1eb28a225e30df8d92cea882 (patch)
treee727a6159d47c07d95af0eabbc49da8f7b00b802 /src
parent873ff13bb0659a56cfec2e07b464a5f1bf8e722f (diff)
update dependenciesHEADmaster
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs251
1 files changed, 88 insertions, 163 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e8797d2..7aa2ade 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,21 +12,18 @@
12)] 12)]
13 13
14use adblock::blocker::BlockerResult as RustBlockerResult; 14use adblock::blocker::BlockerResult as RustBlockerResult;
15use adblock::blocker::{BlockerError as RustBlockerError, Redirection};
16use adblock::cosmetic_filter_cache::UrlSpecificResources as RustUrlSpecificResources; 15use adblock::cosmetic_filter_cache::UrlSpecificResources as RustUrlSpecificResources;
17use adblock::engine::Engine as RustEngine; 16use adblock::engine::Engine as RustEngine;
18use adblock::lists::FilterSet as RustFilterSet; 17use adblock::lists::FilterSet as RustFilterSet;
19use adblock::lists::{FilterFormat, ParseOptions, RuleTypes}; 18use adblock::lists::{FilterFormat, ParseOptions, RuleTypes};
19use adblock::request::Request;
20use pyo3::create_exception; 20use pyo3::create_exception;
21use pyo3::exceptions::PyException; 21use pyo3::exceptions::PyException;
22use pyo3::prelude::*; 22use pyo3::prelude::*;
23use pyo3::types::PyBytes; 23use pyo3::types::PyBytes;
24use pyo3::PyErr; 24use pyo3::PyErr;
25 25
26use adblock::resources::{ 26use adblock::resources::{MimeType, PermissionMask, Resource, ResourceType};
27 AddResourceError as RustAddResourceError, MimeType, Resource, ResourceType,
28};
29use std::collections::HashMap;
30use std::collections::HashSet; 27use std::collections::HashSet;
31use std::error::Error; 28use std::error::Error;
32use std::fmt::{self, Display}; 29use std::fmt::{self, Display};
@@ -35,39 +32,39 @@ use std::io::{Read, Write};
35 32
36/// Brave's adblocking library in Python! 33/// Brave's adblocking library in Python!
37#[pymodule] 34#[pymodule]
38fn adblock(py: Python<'_>, m: &PyModule) -> PyResult<()> { 35fn adblock_py(m: &Bound<'_, PyModule>) -> PyResult<()> {
39 m.add("__version__", env!("CARGO_PKG_VERSION"))?; 36 m.add("__version__", env!("CARGO_PKG_VERSION"))?;
40 m.add_class::<Engine>()?; 37 m.add_class::<Engine>()?;
41 m.add_class::<FilterSet>()?; 38 m.add_class::<FilterSet>()?;
42 m.add_class::<BlockerResult>()?; 39 m.add_class::<BlockerResult>()?;
43 m.add_class::<UrlSpecificResources>()?; 40 m.add_class::<UrlSpecificResources>()?;
44 m.add("AdblockException", py.get_type::<AdblockException>())?; 41 m.add("AdblockException", m.py().get_type_bound::<AdblockException>())?;
45 m.add("BlockerException", py.get_type::<BlockerException>())?; 42 m.add("BlockerException", m.py().get_type_bound::<BlockerException>())?;
46 m.add("SerializationError", py.get_type::<SerializationError>())?; 43 m.add("SerializationError", m.py().get_type_bound::<SerializationError>())?;
47 m.add( 44 m.add(
48 "DeserializationError", 45 "DeserializationError",
49 py.get_type::<DeserializationError>(), 46 m.py().get_type_bound::<DeserializationError>(),
50 )?; 47 )?;
51 m.add( 48 m.add(
52 "OptimizedFilterExistence", 49 "OptimizedFilterExistence",
53 py.get_type::<OptimizedFilterExistence>(), 50 m.py().get_type_bound::<OptimizedFilterExistence>(),
54 )?; 51 )?;
55 m.add( 52 m.add(
56 "BadFilterAddUnsupported", 53 "BadFilterAddUnsupported",
57 py.get_type::<BadFilterAddUnsupported>(), 54 m.py().get_type_bound::<BadFilterAddUnsupported>(),
58 )?; 55 )?;
59 m.add("FilterExists", py.get_type::<FilterExists>())?; 56 m.add("FilterExists", m.py().get_type_bound::<FilterExists>())?;
60 m.add( 57 m.add(
61 "AddResourceException", 58 "AddResourceException",
62 py.get_type::<AddResourceException>(), 59 m.py().get_type_bound::<AddResourceException>(),
63 )?; 60 )?;
64 m.add( 61 m.add(
65 "InvalidBase64ContentError", 62 "InvalidBase64ContentError",
66 py.get_type::<InvalidBase64ContentError>(), 63 m.py().get_type_bound::<InvalidBase64ContentError>(),
67 )?; 64 )?;
68 m.add( 65 m.add(
69 "InvalidUtf8ContentError", 66 "InvalidUtf8ContentError",
70 py.get_type::<InvalidUtf8ContentError>(), 67 m.py().get_type_bound::<InvalidUtf8ContentError>(),
71 )?; 68 )?;
72 Ok(()) 69 Ok(())
73} 70}
@@ -94,14 +91,11 @@ pub struct BlockerResult {
94 /// 91 ///
95 /// [1]: https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#redirect 92 /// [1]: https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#redirect
96 #[pyo3(get)] 93 #[pyo3(get)]
97 pub redirect_type: Option<String>,
98 /// Exception is not `None` when the blocker matched on an exception rule.
99 /// Effectively this means that there was a match, but the request should
100 /// not be blocked. It is a non-empty string if the blocker was initialized
101 /// from a list of rules with debugging enabled, otherwise the original
102 /// string representation is discarded to reduce memory use.
103 #[pyo3(get)]
104 pub redirect: Option<String>, 94 pub redirect: Option<String>,
95 /// `removeparam` may remove URL parameters. If the original request URL was
96 /// modified at all, the new version will be here.
97 #[pyo3(get)]
98 pub rewritten_url: Option<String>,
105 /// Exception is not `None` when the blocker matched on an exception rule. 99 /// Exception is not `None` when the blocker matched on an exception rule.
106 /// Effectively this means that there was a match, but the request should 100 /// Effectively this means that there was a match, but the request should
107 /// not be blocked. It is a non-empty string if the blocker was initialized 101 /// not be blocked. It is a non-empty string if the blocker was initialized
@@ -114,32 +108,17 @@ pub struct BlockerResult {
114 /// a match, it is not `None`. 108 /// a match, it is not `None`.
115 #[pyo3(get)] 109 #[pyo3(get)]
116 pub filter: Option<String>, 110 pub filter: Option<String>,
117 /// The `error` field is only used to signal that there was an error in
118 /// parsing the provided URLs when using the simpler
119 /// `check_network_urls` method.
120 #[pyo3(get)]
121 pub error: Option<String>,
122} 111}
123 112
124impl From<RustBlockerResult> for BlockerResult { 113impl From<RustBlockerResult> for BlockerResult {
125 fn from(br: RustBlockerResult) -> Self { 114 fn from(br: RustBlockerResult) -> Self {
126 let (redirect, redirect_type) = if let Some(resource) = br.redirect {
127 match resource {
128 Redirection::Resource(resource) => (Some(resource), Some("resource".to_string())),
129 Redirection::Url(url) => (Some(url), Some("url".to_string())),
130 }
131 } else {
132 (None, None)
133 };
134
135 Self { 115 Self {
136 matched: br.matched, 116 matched: br.matched,
137 important: br.important, 117 important: br.important,
118 redirect: br.redirect,
119 rewritten_url: br.rewritten_url,
138 exception: br.exception, 120 exception: br.exception,
139 filter: br.filter, 121 filter: br.filter,
140 error: br.error,
141 redirect_type,
142 redirect,
143 } 122 }
144 } 123 }
145} 124}
@@ -148,13 +127,13 @@ impl From<RustBlockerResult> for BlockerResult {
148impl BlockerResult { 127impl BlockerResult {
149 fn __repr__(&self) -> PyResult<String> { 128 fn __repr__(&self) -> PyResult<String> {
150 Ok(format!( 129 Ok(format!(
151 "BlockerResult(matched={}, important={}, redirect={}, exception={}, filter={}, error={})", 130 "BlockerResult(matched={}, important={}, redirect={}, rewritten_url={}, exception={}, filter={})",
152 self.matched.diy_python_repr(), 131 self.matched.diy_python_repr(),
153 self.important.diy_python_repr(), 132 self.important.diy_python_repr(),
154 self.redirect.diy_python_repr(), 133 self.redirect.diy_python_repr(),
134 self.rewritten_url.diy_python_repr(),
155 self.exception.diy_python_repr(), 135 self.exception.diy_python_repr(),
156 self.filter.diy_python_repr(), 136 self.filter.diy_python_repr(),
157 self.error.diy_python_repr(),
158 )) 137 ))
159 } 138 }
160} 139}
@@ -214,17 +193,6 @@ impl From<BlockerError> for PyErr {
214 } 193 }
215} 194}
216 195
217impl From<RustBlockerError> for BlockerError {
218 fn from(err: RustBlockerError) -> Self {
219 match err {
220 RustBlockerError::SerializationError => Self::SerializationError,
221 RustBlockerError::DeserializationError => Self::DeserializationError,
222 RustBlockerError::OptimizedFilterExistence => Self::OptimizedFilterExistence,
223 RustBlockerError::BadFilterAddUnsupported => Self::BadFilterAddUnsupported,
224 RustBlockerError::FilterExists => Self::FilterExists,
225 }
226 }
227}
228 196
229fn filter_format_from_string(filter_format: &str) -> PyResult<FilterFormat> { 197fn filter_format_from_string(filter_format: &str) -> PyResult<FilterFormat> {
230 match filter_format { 198 match filter_format {
@@ -252,7 +220,6 @@ fn rule_types_from_string(rule_types: &str) -> PyResult<RuleTypes> {
252/// created. FilterSet allows assembling a compound list from multiple 220/// created. FilterSet allows assembling a compound list from multiple
253/// different sources before compiling the rules into an Engine. 221/// different sources before compiling the rules into an Engine.
254#[pyclass] 222#[pyclass]
255#[pyo3(text_signature = "($self, debug)")]
256#[derive(Clone)] 223#[derive(Clone)]
257pub struct FilterSet { 224pub struct FilterSet {
258 filter_set: RustFilterSet, 225 filter_set: RustFilterSet,
@@ -266,7 +233,7 @@ impl FilterSet {
266 /// the more compact internal representation. If enabled, this information 233 /// the more compact internal representation. If enabled, this information
267 /// will be passed to the corresponding Engine. 234 /// will be passed to the corresponding Engine.
268 #[new] 235 #[new]
269 #[args(debug = false)] 236 #[pyo3(signature = (debug = false))]
270 pub fn new(debug: bool) -> Self { 237 pub fn new(debug: bool) -> Self {
271 Self { 238 Self {
272 filter_set: RustFilterSet::new(debug), 239 filter_set: RustFilterSet::new(debug),
@@ -279,18 +246,11 @@ impl FilterSet {
279 /// 246 ///
280 /// The format is a string containing either "standard" (ABP/uBO-style) 247 /// The format is a string containing either "standard" (ABP/uBO-style)
281 /// or "hosts". 248 /// or "hosts".
282 #[pyo3(text_signature = "($self, filter_list, format, include_redirect_urls, rule_types)")] 249 #[pyo3(signature = (filter_list, format = "standard", rule_types = "all"))]
283 #[args(
284 filter_list,
285 format = "\"standard\"",
286 include_redirect_urls = "false",
287 rule_types = "\"all\""
288 )]
289 pub fn add_filter_list( 250 pub fn add_filter_list(
290 &mut self, 251 &mut self,
291 filter_list: &str, 252 filter_list: &str,
292 format: &str, 253 format: &str,
293 include_redirect_urls: bool,
294 rule_types: &str, 254 rule_types: &str,
295 ) -> PyResult<()> { 255 ) -> PyResult<()> {
296 let filter_format = filter_format_from_string(format)?; 256 let filter_format = filter_format_from_string(format)?;
@@ -299,8 +259,8 @@ impl FilterSet {
299 filter_list, 259 filter_list,
300 ParseOptions { 260 ParseOptions {
301 format: filter_format, 261 format: filter_format,
302 include_redirect_urls,
303 rule_types, 262 rule_types,
263 permissions: PermissionMask::default(),
304 }, 264 },
305 ); 265 );
306 Ok(()) 266 Ok(())
@@ -311,18 +271,11 @@ impl FilterSet {
311 /// 271 ///
312 /// The format is a string containing either "standard" (ABP/uBO-style) 272 /// The format is a string containing either "standard" (ABP/uBO-style)
313 /// or "hosts". 273 /// or "hosts".
314 #[pyo3(text_signature = "($self, filters, format, include_redirect_urls, rule_types)")] 274 #[pyo3(signature = (filters, format = "standard", rule_types = "all"))]
315 #[args(
316 filters,
317 format = "\"standard\"",
318 include_redirect_urls = "false",
319 rule_types = "\"all\""
320 )]
321 pub fn add_filters( 275 pub fn add_filters(
322 &mut self, 276 &mut self,
323 filters: Vec<String>, 277 filters: Vec<String>,
324 format: &str, 278 format: &str,
325 include_redirect_urls: bool,
326 rule_types: &str, 279 rule_types: &str,
327 ) -> PyResult<()> { 280 ) -> PyResult<()> {
328 let filter_format = filter_format_from_string(format)?; 281 let filter_format = filter_format_from_string(format)?;
@@ -331,8 +284,8 @@ impl FilterSet {
331 &filters, 284 &filters,
332 ParseOptions { 285 ParseOptions {
333 format: filter_format, 286 format: filter_format,
334 include_redirect_urls,
335 rule_types, 287 rule_types,
288 permissions: PermissionMask::default(),
336 }, 289 },
337 ); 290 );
338 Ok(()) 291 Ok(())
@@ -351,10 +304,9 @@ pub struct UrlSpecificResources {
351 /// styled as `{ display: none !important; }`. 304 /// styled as `{ display: none !important; }`.
352 #[pyo3(get)] 305 #[pyo3(get)]
353 pub hide_selectors: HashSet<String>, 306 pub hide_selectors: HashSet<String>,
354 /// A map of CSS selectors on the page to respective non-hide style rules, 307 /// Set of JSON-encoded procedural filters or filters with an action.
355 /// i.e. any required styles other than `display: none`.
356 #[pyo3(get)] 308 #[pyo3(get)]
357 pub style_selectors: HashMap<String, Vec<String>>, 309 pub procedural_actions: HashSet<String>,
358 /// A set of any class or id CSS selectors that should not have generic 310 /// A set of any class or id CSS selectors that should not have generic
359 /// rules applied. 311 /// rules applied.
360 // In practice, these should be passed to `class_id_stylesheet` and not 312 // In practice, these should be passed to `class_id_stylesheet` and not
@@ -376,7 +328,7 @@ impl From<RustUrlSpecificResources> for UrlSpecificResources {
376 fn from(r: RustUrlSpecificResources) -> Self { 328 fn from(r: RustUrlSpecificResources) -> Self {
377 Self { 329 Self {
378 hide_selectors: r.hide_selectors, 330 hide_selectors: r.hide_selectors,
379 style_selectors: r.style_selectors, 331 procedural_actions: r.procedural_actions,
380 exceptions: r.exceptions, 332 exceptions: r.exceptions,
381 injected_script: r.injected_script, 333 injected_script: r.injected_script,
382 generichide: r.generichide, 334 generichide: r.generichide,
@@ -388,9 +340,9 @@ impl From<RustUrlSpecificResources> for UrlSpecificResources {
388impl UrlSpecificResources { 340impl UrlSpecificResources {
389 fn __repr__(&self) -> PyResult<String> { 341 fn __repr__(&self) -> PyResult<String> {
390 Ok(format!( 342 Ok(format!(
391 "UrlSpecificResources<{} hide selectors, {} style selectors, {} exceptions, injected_javascript={}, generichide={}>", 343 "UrlSpecificResources<{} hide selectors, {} procedural actions, {} exceptions, injected_javascript={}, generichide={}>",
392 self.hide_selectors.len(), 344 self.hide_selectors.len(),
393 self.style_selectors.len(), 345 self.procedural_actions.len(),
394 self.exceptions.len(), 346 self.exceptions.len(),
395 self.injected_script.diy_python_repr(), 347 self.injected_script.diy_python_repr(),
396 self.generichide.diy_python_repr(), 348 self.generichide.diy_python_repr(),
@@ -418,7 +370,6 @@ impl UrlSpecificResources {
418/// 370///
419/// [1]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/ResourceType 371/// [1]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/ResourceType
420#[pyclass] 372#[pyclass]
421#[pyo3(text_signature = "($self, filter_set, optimize)")]
422pub struct Engine { 373pub struct Engine {
423 engine: RustEngine, 374 engine: RustEngine,
424 optimize: bool, 375 optimize: bool,
@@ -428,7 +379,7 @@ pub struct Engine {
428impl Engine { 379impl Engine {
429 /// Create a new adblocking engine 380 /// Create a new adblocking engine
430 #[new] 381 #[new]
431 #[args(filter_set, optimize = true)] 382 #[pyo3(signature = (filter_set, optimize = true))]
432 pub fn new(filter_set: FilterSet, optimize: bool) -> Self { 383 pub fn new(filter_set: FilterSet, optimize: bool) -> Self {
433 let engine = RustEngine::from_filter_set(filter_set.filter_set, optimize); 384 let engine = RustEngine::from_filter_set(filter_set.filter_set, optimize);
434 Self { engine, optimize } 385 Self { engine, optimize }
@@ -442,17 +393,26 @@ impl Engine {
442 /// * `url` - The URL of the request to check 393 /// * `url` - The URL of the request to check
443 /// * `source_url` - The URL from where the request is made 394 /// * `source_url` - The URL from where the request is made
444 /// * `request_type` - The resource type that the request points to 395 /// * `request_type` - The resource type that the request points to
445 #[pyo3(text_signature = "($self, url, source_url, request_type)")]
446 pub fn check_network_urls( 396 pub fn check_network_urls(
447 &self, 397 &self,
448 url: &str, 398 url: &str,
449 source_url: &str, 399 source_url: &str,
450 request_type: &str, 400 request_type: &str,
451 ) -> BlockerResult { 401 ) -> BlockerResult {
452 let blocker_result = self 402 match Request::new(url, source_url, request_type) {
453 .engine 403 Ok(request) => {
454 .check_network_urls(url, source_url, request_type); 404 let blocker_result = self.engine.check_network_request(&request);
455 blocker_result.into() 405 blocker_result.into()
406 }
407 Err(_) => BlockerResult {
408 matched: false,
409 important: false,
410 redirect: None,
411 rewritten_url: None,
412 exception: None,
413 filter: None,
414 }
415 }
456 } 416 }
457 417
458 /// Check if a request should be blocked based on the given parameters. 418 /// Check if a request should be blocked based on the given parameters.
@@ -465,9 +425,7 @@ impl Engine {
465 /// * `third_party_request` - Is the given request to a third-party? Here, 425 /// * `third_party_request` - Is the given request to a third-party? Here,
466 /// `None` can be given and the engine will figure it out based on the 426 /// `None` can be given and the engine will figure it out based on the
467 /// `hostname` and `source_hostname`. 427 /// `hostname` and `source_hostname`.
468 #[pyo3( 428 #[pyo3(signature = (url, hostname, source_hostname, request_type, third_party_request = None))]
469 text_signature = "($self, url, hostname, source_hostname, requsest_type, third_party_request)"
470 )]
471 pub fn check_network_urls_with_hostnames( 429 pub fn check_network_urls_with_hostnames(
472 &self, 430 &self,
473 url: &str, 431 url: &str,
@@ -476,13 +434,11 @@ impl Engine {
476 request_type: &str, 434 request_type: &str,
477 third_party_request: Option<bool>, 435 third_party_request: Option<bool>,
478 ) -> BlockerResult { 436 ) -> BlockerResult {
479 let blocker_result = self.engine.check_network_urls_with_hostnames( 437 let third_party = third_party_request.unwrap_or_else(|| {
480 url, 438 hostname != source_hostname
481 hostname, 439 });
482 source_hostname, 440 let request = Request::preparsed(url, hostname, source_hostname, request_type, third_party);
483 request_type, 441 let blocker_result = self.engine.check_network_request(&request);
484 third_party_request,
485 );
486 blocker_result.into() 442 blocker_result.into()
487 } 443 }
488 444
@@ -499,10 +455,7 @@ impl Engine {
499 /// * `previously_matched_rule` - Return a match as long as there are no 455 /// * `previously_matched_rule` - Return a match as long as there are no
500 /// exceptions 456 /// exceptions
501 /// * `force_check_exceptions` - Check exceptions even if no other rule matches 457 /// * `force_check_exceptions` - Check exceptions even if no other rule matches
502 #[pyo3( 458 #[pyo3(signature = (url, hostname, source_hostname, request_type, third_party_request = None, previously_matched_rule = false, force_check_exceptions = false))]
503 text_signature = "($self, url, hostname, source_hostname, request_type, \
504 third_party_request, previously_matched_rule, force_check_exceptions)"
505 )]
506 #[allow(clippy::too_many_arguments)] 459 #[allow(clippy::too_many_arguments)]
507 pub fn check_network_urls_with_hostnames_subset( 460 pub fn check_network_urls_with_hostnames_subset(
508 &self, 461 &self,
@@ -514,12 +467,12 @@ impl Engine {
514 previously_matched_rule: bool, 467 previously_matched_rule: bool,
515 force_check_exceptions: bool, 468 force_check_exceptions: bool,
516 ) -> BlockerResult { 469 ) -> BlockerResult {
517 let blocker_result = self.engine.check_network_urls_with_hostnames_subset( 470 let third_party = third_party_request.unwrap_or_else(|| {
518 url, 471 hostname != source_hostname
519 hostname, 472 });
520 source_hostname, 473 let request = Request::preparsed(url, hostname, source_hostname, request_type, third_party);
521 request_type, 474 let blocker_result = self.engine.check_network_request_subset(
522 third_party_request, 475 &request,
523 previously_matched_rule, 476 previously_matched_rule,
524 force_check_exceptions, 477 force_check_exceptions,
525 ); 478 );
@@ -534,7 +487,7 @@ impl Engine {
534 /// Use `"template"` if wanting to specify a template resource type. 487 /// Use `"template"` if wanting to specify a template resource type.
535 /// * `content`: The resource data, encoded using standard base64 configuration 488 /// * `content`: The resource data, encoded using standard base64 configuration
536 /// * `aliases`: List of aliases for the resource 489 /// * `aliases`: List of aliases for the resource
537 #[pyo3(text_signature = "($self, name, content_type, content, aliases)")] 490 #[pyo3(signature = (name, content_type, content, aliases = None))]
538 pub fn add_resource( 491 pub fn add_resource(
539 &mut self, 492 &mut self,
540 name: &str, 493 name: &str,
@@ -542,7 +495,7 @@ impl Engine {
542 content: &str, 495 content: &str,
543 aliases: Option<Vec<String>>, 496 aliases: Option<Vec<String>>,
544 ) -> PyResult<()> { 497 ) -> PyResult<()> {
545 let result = self.engine.add_resource(Resource { 498 let resource = Resource {
546 name: name.to_string(), 499 name: name.to_string(),
547 aliases: aliases.unwrap_or_default(), 500 aliases: aliases.unwrap_or_default(),
548 kind: match content_type { 501 kind: match content_type {
@@ -552,47 +505,27 @@ impl Engine {
552 ))), 505 ))),
553 }, 506 },
554 content: content.to_string(), 507 content: content.to_string(),
555 }); 508 dependencies: Vec::new(),
509 permission: PermissionMask::default(),
510 };
556 511
557 match result { 512 self.engine.use_resources(std::iter::once(resource));
558 Ok(_) => Ok(()), 513 Ok(())
559 Err(err) => match err {
560 RustAddResourceError::InvalidBase64Content => Err(
561 InvalidBase64ContentError::new_err("invalid base64 content".to_string()),
562 ),
563 RustAddResourceError::InvalidUtf8Content => Err(InvalidUtf8ContentError::new_err(
564 "invalid utf content".to_string(),
565 )),
566 },
567 }
568 } 514 }
569 515
570 /// Serialize this blocking engine to bytes. They can then be deserialized 516 /// Serialize this blocking engine to bytes. They can then be deserialized
571 /// using `deserialize()` to get the same engine again. 517 /// using `deserialize()` to get the same engine again.
572 #[pyo3(text_signature = "($self)")] 518 pub fn serialize<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyBytes>> {
573 pub fn serialize<'p>(&mut self, py: Python<'p>) -> PyResult<&'p PyBytes> { 519 let bytes = self.engine.serialize();
574 let bytes = self.serialize_inner()?; 520 let py_bytes = PyBytes::new_bound(py, &bytes);
575 let py_bytes = PyBytes::new(py, &bytes);
576 Ok(py_bytes) 521 Ok(py_bytes)
577 } 522 }
578 523
579 fn serialize_inner(&mut self) -> PyResult<Vec<u8>> {
580 let result = self.engine.serialize_raw();
581 match result {
582 Ok(x) => Ok(x),
583 Err(error) => {
584 let my_blocker_error: BlockerError = error.into();
585 Err(my_blocker_error.into())
586 }
587 }
588 }
589
590 /// Serialize this blocking engine to a file. The file can then be 524 /// Serialize this blocking engine to a file. The file can then be
591 /// deserialized using `deserialize_from_file()` to get the same engine 525 /// deserialized using `deserialize_from_file()` to get the same engine
592 /// again. 526 /// again.
593 #[pyo3(text_signature = "($self, file)")] 527 pub fn serialize_to_file(&self, file: &str) -> PyResult<()> {
594 pub fn serialize_to_file(&mut self, file: &str) -> PyResult<()> { 528 let data = self.engine.serialize();
595 let data = self.serialize_inner()?;
596 let mut fd = fs::OpenOptions::new() 529 let mut fd = fs::OpenOptions::new()
597 .create(true) 530 .create(true)
598 .truncate(true) 531 .truncate(true)
@@ -603,21 +536,14 @@ impl Engine {
603 } 536 }
604 537
605 /// Deserialize a blocking engine from bytes produced with `serialize()`. 538 /// Deserialize a blocking engine from bytes produced with `serialize()`.
606 #[pyo3(text_signature = "($self, serialized)")]
607 pub fn deserialize(&mut self, serialized: &[u8]) -> PyResult<()> { 539 pub fn deserialize(&mut self, serialized: &[u8]) -> PyResult<()> {
608 let result = self.engine.deserialize(serialized); 540 self.engine.deserialize(serialized).map_err(|_| {
609 match result { 541 DeserializationError::new_err("Failed to deserialize engine data")
610 Ok(_) => Ok(()), 542 })
611 Err(error) => {
612 let my_blocker_error: BlockerError = error.into();
613 Err(my_blocker_error.into())
614 }
615 }
616 } 543 }
617 544
618 /// Deserialize a blocking engine from file produced with 545 /// Deserialize a blocking engine from file produced with
619 /// `serialize_to_file()`. 546 /// `serialize_to_file()`.
620 #[pyo3(text_signature = "($self, file)")]
621 pub fn deserialize_from_file(&mut self, file: &str) -> PyResult<()> { 547 pub fn deserialize_from_file(&mut self, file: &str) -> PyResult<()> {
622 let mut fd = fs::File::open(file)?; 548 let mut fd = fs::File::open(file)?;
623 let mut data: Vec<u8> = Vec::new(); 549 let mut data: Vec<u8> = Vec::new();
@@ -626,18 +552,20 @@ impl Engine {
626 } 552 }
627 553
628 /// Checks if the given filter exists in the blocking engine. 554 /// Checks if the given filter exists in the blocking engine.
629 #[pyo3(text_signature = "($self, filter)")] 555 /// Note: This method has been removed in the latest version of adblock-rust.
630 pub fn filter_exists(&self, filter: &str) -> bool { 556 /// It will always return false.
631 self.engine.filter_exists(filter) 557 pub fn filter_exists(&self, _filter: &str) -> bool {
558 // This method no longer exists in the adblock-rust API
559 false
632 } 560 }
633 561
634 /// Sets this engine's tags to be _only_ the ones provided in tags. 562 /// Sets this engine's tags to be _only_ the ones provided in tags.
635 /// 563 ///
636 /// Tags can be used to cheaply enable or disable network rules with a 564 /// Tags can be used to cheaply enable or disable network rules with a
637 /// corresponding $tag option. 565 /// corresponding $tag option.
638 #[pyo3(text_signature = "($self, tags)")] 566 pub fn use_tags(&mut self, tags: Vec<String>) {
639 pub fn use_tags(&mut self, tags: Vec<&str>) { 567 let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect();
640 self.engine.use_tags(&tags); 568 self.engine.use_tags(&tag_refs);
641 } 569 }
642 570
643 /// Sets this engine's tags to additionally include the ones provided in 571 /// Sets this engine's tags to additionally include the ones provided in
@@ -645,9 +573,9 @@ impl Engine {
645 /// 573 ///
646 /// Tags can be used to cheaply enable or disable network rules with a 574 /// Tags can be used to cheaply enable or disable network rules with a
647 /// corresponding $tag option. 575 /// corresponding $tag option.
648 #[pyo3(text_signature = "($self, tags)")] 576 pub fn enable_tags(&mut self, tags: Vec<String>) {
649 pub fn enable_tags(&mut self, tags: Vec<&str>) { 577 let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect();
650 self.engine.enable_tags(&tags); 578 self.engine.enable_tags(&tag_refs);
651 } 579 }
652 580
653 /// Sets this engine's tags to no longer include the ones provided in 581 /// Sets this engine's tags to no longer include the ones provided in
@@ -655,16 +583,15 @@ impl Engine {
655 /// 583 ///
656 /// Tags can be used to cheaply enable or disable network rules with a 584 /// Tags can be used to cheaply enable or disable network rules with a
657 /// corresponding $tag option. 585 /// corresponding $tag option.
658 #[pyo3(text_signature = "($self, tags)")] 586 pub fn disable_tags(&mut self, tags: Vec<String>) {
659 pub fn disable_tags(&mut self, tags: Vec<&str>) { 587 let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect();
660 self.engine.disable_tags(&tags); 588 self.engine.disable_tags(&tag_refs);
661 } 589 }
662 590
663 /// Checks if a given tag exists in this engine. 591 /// Checks if a given tag exists in this engine.
664 /// 592 ///
665 /// Tags can be used to cheaply enable or disable network rules with a 593 /// Tags can be used to cheaply enable or disable network rules with a
666 /// corresponding $tag option. 594 /// corresponding $tag option.
667 #[pyo3(text_signature = "($self, tag)")]
668 pub fn tag_exists(&self, tag: &str) -> bool { 595 pub fn tag_exists(&self, tag: &str) -> bool {
669 self.engine.tag_exists(tag) 596 self.engine.tag_exists(tag)
670 } 597 }
@@ -673,7 +600,6 @@ impl Engine {
673 /// url. Once this has been called, all CSS ids and classes on a 600 /// url. Once this has been called, all CSS ids and classes on a
674 /// page should be passed to hidden_class_id_selectors to obtain any 601 /// page should be passed to hidden_class_id_selectors to obtain any
675 /// stylesheets consisting of generic rules. 602 /// stylesheets consisting of generic rules.
676 #[pyo3(text_signature = "($self, url)")]
677 pub fn url_cosmetic_resources(&self, url: &str) -> UrlSpecificResources { 603 pub fn url_cosmetic_resources(&self, url: &str) -> UrlSpecificResources {
678 self.engine.url_cosmetic_resources(url).into() 604 self.engine.url_cosmetic_resources(url).into()
679 } 605 }
@@ -685,7 +611,6 @@ impl Engine {
685 /// are not excepted. 611 /// are not excepted.
686 /// 612 ///
687 /// Exceptions should be passed directly from UrlSpecificResources. 613 /// Exceptions should be passed directly from UrlSpecificResources.
688 #[pyo3(text_signature = "($self, classes, ids, exceptions)")]
689 pub fn hidden_class_id_selectors( 614 pub fn hidden_class_id_selectors(
690 &self, 615 &self,
691 classes: Vec<String>, 616 classes: Vec<String>,