filter.rs (43692B)
1 use crate::{bindings, Error, FilterError, Note, Result}; 2 use std::ffi::CString; 3 use std::fmt; 4 use std::os::raw::c_char; 5 use std::os::raw::c_void; 6 use std::ptr::null_mut; 7 use std::sync::Arc; 8 use tracing::debug; 9 10 pub struct FilterBuilder { 11 pub data: bindings::ndb_filter, 12 pub custom_ctx: Option<*mut c_void>, 13 } 14 15 pub struct Filter { 16 pub data: bindings::ndb_filter, 17 pub custom_ctx: Option<Arc<*mut c_void>>, 18 } 19 20 fn filter_fmt<'a, F>(filter: F, f: &mut fmt::Formatter<'_>) -> fmt::Result 21 where 22 F: IntoIterator<Item = FilterField<'a>>, 23 { 24 let mut dfmt = f.debug_struct("Filter"); 25 let mut fmt = &mut dfmt; 26 27 for field in filter { 28 fmt = match field { 29 FilterField::Search(ref search) => fmt.field("search", search), 30 FilterField::Ids(ref ids) => fmt.field("ids", ids), 31 FilterField::Authors(ref authors) => fmt.field("authors", authors), 32 FilterField::Kinds(ref kinds) => fmt.field("kinds", kinds), 33 FilterField::Tags(ref chr, _tags) => fmt.field("tags", chr), 34 FilterField::Since(ref n) => fmt.field("since", n), 35 FilterField::Until(ref n) => fmt.field("until", n), 36 FilterField::Limit(ref n) => fmt.field("limit", n), 37 FilterField::Relays(ref n) => fmt.field("relays", n), 38 FilterField::Custom(ref n) => fmt.field("custom", n), 39 } 40 } 41 42 fmt.finish() 43 } 44 45 impl fmt::Debug for Filter { 46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 47 filter_fmt(self, f) 48 } 49 } 50 51 impl fmt::Debug for FilterBuilder { 52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 53 filter_fmt(self, f) 54 } 55 } 56 57 impl Clone for Filter { 58 fn clone(&self) -> Self { 59 // Default inits... 60 //let mut new_filter: bindings::ndb_filter = Default::default(); 61 let null = null_mut(); 62 let mut new_filter = bindings::ndb_filter { 63 finalized: 0, 64 elem_buf: bindings::cursor { 65 start: null, 66 p: null, 67 end: null, 68 }, 69 data_buf: bindings::cursor { 70 start: null, 71 p: null, 72 end: null, 73 }, 74 num_elements: 0, 75 current: -1, 76 elements: [0; 10], 77 }; 78 79 debug!("cloning filter"); 80 unsafe { 81 bindings::ndb_filter_clone( 82 new_filter.as_mut_ptr(), 83 self.as_ptr() as *mut bindings::ndb_filter, 84 ); 85 }; 86 Filter { 87 data: new_filter, 88 custom_ctx: self.custom_ctx.clone(), 89 } 90 } 91 } 92 93 impl bindings::ndb_filter { 94 fn as_ptr(&self) -> *const bindings::ndb_filter { 95 self as *const bindings::ndb_filter 96 } 97 98 fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter { 99 self as *mut bindings::ndb_filter 100 } 101 102 fn as_ref(&self) -> &bindings::ndb_filter { 103 self 104 } 105 106 pub fn mut_iter(&self) -> MutFilterIter<'_> { 107 MutFilterIter::new(self.as_ref()) 108 } 109 110 pub fn field(&self, index: i32) -> Option<FilterField<'_>> { 111 let ptr = unsafe { bindings::ndb_filter_get_elements(self.as_ptr(), index) }; 112 113 if ptr.is_null() { 114 return None; 115 } 116 117 Some(FilterElements::new(self, ptr).field()) 118 } 119 120 pub fn field_mut(&self, index: i32) -> Option<MutFilterField<'_>> { 121 let ptr = unsafe { bindings::ndb_filter_get_elements(self.as_ptr(), index) }; 122 123 if ptr.is_null() { 124 return None; 125 } 126 127 FilterElements::new(self, ptr).field_mut() 128 } 129 130 pub fn elements(&self, index: i32) -> Option<FilterElements<'_>> { 131 let ptr = unsafe { bindings::ndb_filter_get_elements(self.as_ptr(), index) }; 132 133 if ptr.is_null() { 134 return None; 135 } 136 137 Some(FilterElements::new(self, ptr)) 138 } 139 } 140 141 impl bindings::ndb_filter { 142 fn new(pages: i32) -> Self { 143 let null = null_mut(); 144 let mut filter_data = bindings::ndb_filter { 145 finalized: 0, 146 elem_buf: bindings::cursor { 147 start: null, 148 p: null, 149 end: null, 150 }, 151 data_buf: bindings::cursor { 152 start: null, 153 p: null, 154 end: null, 155 }, 156 num_elements: 0, 157 current: -1, 158 elements: [0; 10], 159 }; 160 161 unsafe { 162 bindings::ndb_filter_init_with(filter_data.as_mut_ptr(), pages); 163 }; 164 165 filter_data 166 } 167 } 168 169 impl Filter { 170 pub fn new_with_capacity(pages: i32) -> FilterBuilder { 171 FilterBuilder { 172 data: bindings::ndb_filter::new(pages), 173 custom_ctx: None, 174 } 175 } 176 177 #[allow(clippy::new_ret_no_self)] 178 pub fn new() -> FilterBuilder { 179 Self::new_with_capacity(256) 180 } 181 182 pub fn copy_from<'a, I>(filter: I) -> FilterBuilder 183 where 184 I: IntoIterator<Item = FilterField<'a>>, 185 { 186 let mut builder = Filter::new(); 187 for field in filter { 188 match field { 189 FilterField::Custom(_n) => { 190 // TODO: copy custom filters 191 } 192 FilterField::Relays(relays) => builder = builder.relays(relays), 193 FilterField::Search(search) => { 194 builder = builder.search(search); 195 } 196 FilterField::Ids(ids) => { 197 builder = builder.ids(ids); 198 } 199 FilterField::Authors(authors) => builder = builder.authors(authors), 200 FilterField::Kinds(kinds) => builder = builder.kinds(kinds), 201 FilterField::Tags(chr, tags) => { 202 builder.start_tags_field(chr).unwrap(); 203 for field in tags { 204 match field { 205 FilterElement::Id(id) => builder.add_id_element(id).unwrap(), 206 FilterElement::Str(str_) => builder.add_str_element(str_).unwrap(), 207 FilterElement::Int(int) => builder.add_int_element(int).unwrap(), 208 FilterElement::Custom => { 209 todo!("copy filters with custom filters"); 210 } 211 } 212 } 213 builder.end_field(); 214 } 215 FilterField::Since(n) => builder = builder.since(n), 216 FilterField::Until(n) => builder = builder.until(n), 217 FilterField::Limit(n) => builder = builder.limit(n), 218 } 219 } 220 builder 221 } 222 223 pub fn from_json(json: &str) -> Result<Self> { 224 Self::from_json_with_bufsize(json, 1024usize * 1024usize) 225 } 226 227 pub fn from_json_with_bufsize(json: &str, bufsize: usize) -> Result<Self> { 228 let mut buf = Vec::with_capacity(bufsize); 229 let mut filter = Filter::new(); 230 unsafe { 231 let json_cstr = CString::new(json).expect("string to cstring conversion failed"); 232 let size = bindings::ndb_filter_from_json( 233 json_cstr.as_ptr(), 234 json.len() as i32, 235 filter.as_mut_ptr(), 236 buf.as_mut_ptr(), 237 bufsize as ::std::os::raw::c_int, 238 ) as usize; 239 240 // Step 4: Check the return value for success 241 if size == 0 { 242 return Err(Error::BufferOverflow); // Handle the error appropriately 243 } 244 245 Ok(Filter { 246 data: filter.data, 247 custom_ctx: None, 248 }) 249 } 250 } 251 252 pub fn to_ref(&self) -> &bindings::ndb_filter { 253 &self.data 254 } 255 256 pub fn mut_iter(&self) -> MutFilterIter<'_> { 257 self.data.mut_iter() 258 } 259 260 pub fn matches(&self, note: &Note) -> bool { 261 unsafe { 262 bindings::ndb_filter_matches(self.as_ptr() as *mut bindings::ndb_filter, note.as_ptr()) 263 != 0 264 } 265 } 266 267 pub fn num_elements(&self) -> i32 { 268 unsafe { &*(self.as_ptr()) }.num_elements 269 } 270 271 pub fn limit_mut(self, limit: u64) -> Self { 272 for field in self.mut_iter() { 273 if let MutFilterField::Limit(val) = field { 274 *val = limit; 275 return self; 276 } 277 } 278 279 Filter::copy_from(&self).limit(limit).build() 280 } 281 282 pub fn until_mut(self, until: u64) -> Self { 283 for field in self.mut_iter() { 284 if let MutFilterField::Until(val) = field { 285 *val = until; 286 return self; 287 } 288 } 289 290 Filter::copy_from(&self).until(until).build() 291 } 292 293 pub fn since(&self) -> Option<u64> { 294 for field in self { 295 if let FilterField::Since(since) = field { 296 return Some(since); 297 } 298 } 299 300 None 301 } 302 303 pub fn limit(&self) -> Option<u64> { 304 for field in self { 305 if let FilterField::Limit(limit) = field { 306 return Some(limit); 307 } 308 } 309 310 None 311 } 312 313 pub fn until(&self) -> Option<u64> { 314 for field in self { 315 if let FilterField::Until(until) = field { 316 return Some(until); 317 } 318 } 319 320 None 321 } 322 323 pub fn since_mut(self, since: u64) -> Self { 324 for field in self.mut_iter() { 325 if let MutFilterField::Since(val) = field { 326 *val = since; 327 return self; 328 } 329 } 330 331 Filter::copy_from(&self).since(since).build() 332 } 333 334 pub fn as_ptr(&self) -> *const bindings::ndb_filter { 335 self.data.as_ptr() 336 } 337 338 pub fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter { 339 self.data.as_mut_ptr() 340 } 341 342 pub fn json_with_bufsize(&self, bufsize: usize) -> Result<String> { 343 let mut buf = Vec::with_capacity(bufsize); 344 unsafe { 345 let size = bindings::ndb_filter_json( 346 self.as_ptr(), 347 buf.as_mut_ptr() as *mut ::std::os::raw::c_char, 348 bufsize as ::std::os::raw::c_int, 349 ) as usize; 350 351 // Step 4: Check the return value for success 352 if size == 0 { 353 return Err(Error::BufferOverflow); // Handle the error appropriately 354 } 355 356 buf.set_len(size); 357 358 Ok(std::str::from_utf8_unchecked(&buf[..size - 1]).to_string()) 359 } 360 } 361 362 pub fn json(&self) -> Result<String> { 363 // 1mb buffer 364 self.json_with_bufsize(1024usize * 1024usize) 365 } 366 } 367 368 impl Default for FilterBuilder { 369 fn default() -> Self { 370 FilterBuilder { 371 data: bindings::ndb_filter::new(256), 372 custom_ctx: None, 373 } 374 } 375 } 376 377 impl FilterBuilder { 378 pub fn new() -> FilterBuilder { 379 Self::default() 380 } 381 382 pub fn to_ref(&self) -> &bindings::ndb_filter { 383 &self.data 384 } 385 386 pub fn mut_iter(&self) -> MutFilterIter<'_> { 387 self.data.mut_iter() 388 } 389 390 pub fn as_ptr(&self) -> *const bindings::ndb_filter { 391 self.data.as_ptr() 392 } 393 394 pub fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter { 395 self.data.as_mut_ptr() 396 } 397 398 pub fn add_int_element(&mut self, i: u64) -> Result<()> { 399 let res = unsafe { bindings::ndb_filter_add_int_element(self.as_mut_ptr(), i) }; 400 if res == 0 { 401 return Err(FilterError::already_exists()); 402 } 403 404 Ok(()) 405 } 406 407 pub fn add_str_element(&mut self, s: &str) -> Result<()> { 408 let c_str = CString::new(s).expect("string to cstring conversion failed"); 409 let r = unsafe { bindings::ndb_filter_add_str_element(self.as_mut_ptr(), c_str.as_ptr()) }; 410 411 if r == 0 { 412 return Err(FilterError::already_exists()); 413 } 414 415 Ok(()) 416 } 417 418 /// Set a callback to add custom filtering logic to the query 419 pub fn add_custom_filter_element<F>(&mut self, closure: F) -> Result<()> 420 where 421 F: FnMut(Note<'_>) -> bool, 422 { 423 // Box the closure to ensure it has a stable address. 424 let boxed_closure: Box<dyn FnMut(Note<'_>) -> bool> = Box::new(closure); 425 426 // Convert it to a raw pointer to store in sub_cb_ctx. 427 // FIXME: THIS LEAKS! we need some way to clean this up after the filter 428 // is destroyed. 429 let ctx_ptr = Box::into_raw(Box::new(boxed_closure)) as *mut ::std::os::raw::c_void; 430 self.custom_ctx = Some(ctx_ptr); 431 432 let r = unsafe { 433 bindings::ndb_filter_add_custom_filter_element( 434 self.as_mut_ptr(), 435 Some(custom_filter_trampoline), 436 ctx_ptr, 437 ) 438 }; 439 440 if r == 0 { 441 return Err(FilterError::already_exists()); 442 } 443 444 Ok(()) 445 } 446 447 pub fn add_id_element(&mut self, id: &[u8; 32]) -> Result<()> { 448 let ptr: *const ::std::os::raw::c_uchar = id.as_ptr() as *const ::std::os::raw::c_uchar; 449 let r = unsafe { bindings::ndb_filter_add_id_element(self.as_mut_ptr(), ptr) }; 450 451 if r == 0 { 452 return Err(FilterError::already_exists()); 453 } 454 455 Ok(()) 456 } 457 458 pub fn start_field(&mut self, field: bindings::ndb_filter_fieldtype) -> Result<()> { 459 let r = unsafe { bindings::ndb_filter_start_field(self.as_mut_ptr(), field) }; 460 461 if r == 0 { 462 return Err(FilterError::already_started()); 463 } 464 465 Ok(()) 466 } 467 468 pub fn start_tags_field(&mut self, tag: char) -> Result<()> { 469 let r = 470 unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; 471 if r == 0 { 472 return Err(FilterError::already_started()); 473 } 474 Ok(()) 475 } 476 477 pub fn start_kinds_field(&mut self) -> Result<()> { 478 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_KINDS) 479 } 480 481 pub fn start_authors_field(&mut self) -> Result<()> { 482 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_AUTHORS) 483 } 484 485 pub fn start_since_field(&mut self) -> Result<()> { 486 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_SINCE) 487 } 488 489 pub fn start_custom_field(&mut self) -> Result<()> { 490 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_CUSTOM) 491 } 492 493 pub fn start_until_field(&mut self) -> Result<()> { 494 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_UNTIL) 495 } 496 497 pub fn start_limit_field(&mut self) -> Result<()> { 498 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_LIMIT) 499 } 500 501 pub fn start_ids_field(&mut self) -> Result<()> { 502 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_IDS) 503 } 504 505 pub fn start_search_field(&mut self) -> Result<()> { 506 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_SEARCH) 507 } 508 509 pub fn start_relays_field(&mut self) -> Result<()> { 510 self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_RELAYS) 511 } 512 513 #[allow(dead_code)] 514 pub fn start_events_field(&mut self) -> Result<()> { 515 self.start_tags_field('e') 516 } 517 518 pub fn start_pubkeys_field(&mut self) -> Result<()> { 519 self.start_tags_field('p') 520 } 521 522 pub fn start_tag_field(&mut self, tag: char) -> Result<()> { 523 let r = 524 unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; 525 if r == 0 { 526 return Err(FilterError::FieldAlreadyStarted.into()); 527 } 528 Ok(()) 529 } 530 531 pub fn end_field(&mut self) { 532 unsafe { 533 bindings::ndb_filter_end_field(self.as_mut_ptr()); 534 }; 535 } 536 537 pub fn events<'a, I>(mut self, events: I) -> Self 538 where 539 I: IntoIterator<Item = &'a [u8; 32]>, 540 { 541 self.start_tag_field('e').unwrap(); 542 for id in events { 543 self.add_id_element(id).unwrap(); 544 } 545 self.end_field(); 546 self 547 } 548 549 pub fn event(mut self, id: &[u8; 32]) -> Self { 550 self.start_tag_field('e').unwrap(); 551 self.add_id_element(id).unwrap(); 552 self.end_field(); 553 self 554 } 555 556 pub fn relays<'a, I>(mut self, relays: I) -> Self 557 where 558 I: IntoIterator<Item = &'a str>, 559 { 560 self.start_relays_field().unwrap(); 561 for relay in relays { 562 self.add_str_element(relay).unwrap(); 563 } 564 self.end_field(); 565 self 566 } 567 568 pub fn search(mut self, search: &str) -> Self { 569 self.start_search_field().unwrap(); 570 self.add_str_element(search).unwrap(); 571 self.end_field(); 572 self 573 } 574 575 pub fn ids<'a, I>(mut self, ids: I) -> Self 576 where 577 I: IntoIterator<Item = &'a [u8; 32]>, 578 { 579 self.start_ids_field().unwrap(); 580 for id in ids { 581 self.add_id_element(id).unwrap(); 582 } 583 self.end_field(); 584 self 585 } 586 587 pub fn pubkeys<'a, I>(mut self, pubkeys: I) -> Self 588 where 589 I: IntoIterator<Item = &'a [u8; 32]>, 590 { 591 self.start_tag_field('p').unwrap(); 592 for pk in pubkeys { 593 self.add_id_element(pk).unwrap(); 594 } 595 self.end_field(); 596 self 597 } 598 599 pub fn authors<'a, I>(mut self, authors: I) -> Self 600 where 601 I: IntoIterator<Item = &'a [u8; 32]>, 602 { 603 self.start_authors_field().unwrap(); 604 for author in authors { 605 self.add_id_element(author).unwrap(); 606 } 607 self.end_field(); 608 self 609 } 610 611 pub fn kinds<I>(mut self, kinds: I) -> Self 612 where 613 I: IntoIterator<Item = u64>, 614 { 615 self.start_kinds_field().unwrap(); 616 for kind in kinds { 617 self.add_int_element(kind).unwrap(); 618 } 619 self.end_field(); 620 self 621 } 622 623 pub fn pubkey<'a, I>(mut self, pubkeys: I) -> Self 624 where 625 I: IntoIterator<Item = &'a [u8; 32]>, 626 { 627 self.start_pubkeys_field().unwrap(); 628 for pubkey in pubkeys { 629 self.add_id_element(pubkey).unwrap(); 630 } 631 self.end_field(); 632 self 633 } 634 635 pub fn tags<'a, I>(mut self, tags: I, tag: char) -> Self 636 where 637 I: IntoIterator<Item = &'a str>, 638 { 639 self.start_tag_field(tag).unwrap(); 640 for tag in tags { 641 self.add_str_element(tag).unwrap(); 642 } 643 self.end_field(); 644 self 645 } 646 647 pub fn custom<F>(mut self, filter: F) -> Self 648 where 649 F: FnMut(Note<'_>) -> bool, 650 { 651 self.start_custom_field().unwrap(); 652 self.add_custom_filter_element(filter).unwrap(); 653 self.end_field(); 654 self 655 } 656 657 pub fn since(mut self, since: u64) -> Self { 658 for field in self.mut_iter() { 659 if let MutFilterField::Since(val) = field { 660 *val = since; 661 return self; 662 } 663 } 664 665 self.start_since_field().unwrap(); 666 self.add_int_element(since).unwrap(); 667 self.end_field(); 668 self 669 } 670 671 pub fn until(mut self, until: u64) -> Self { 672 for field in self.mut_iter() { 673 if let MutFilterField::Until(val) = field { 674 *val = until; 675 return self; 676 } 677 } 678 679 self.start_until_field().unwrap(); 680 self.add_int_element(until).unwrap(); 681 self.end_field(); 682 self 683 } 684 685 pub fn limit(mut self, limit: u64) -> Self { 686 for field in self.mut_iter() { 687 if let MutFilterField::Limit(val) = field { 688 *val = limit; 689 return self; 690 } 691 } 692 693 self.start_limit_field().unwrap(); 694 self.add_int_element(limit).unwrap(); 695 self.end_field(); 696 self 697 } 698 699 pub fn build(&mut self) -> Filter { 700 unsafe { 701 bindings::ndb_filter_end(self.as_mut_ptr()); 702 }; 703 704 let custom_ctx = self.custom_ctx.map(Arc::new); 705 706 Filter { 707 data: self.data, 708 custom_ctx, 709 } 710 } 711 } 712 713 impl Drop for Filter { 714 fn drop(&mut self) { 715 debug!("dropping filter {:?}", self); 716 unsafe { bindings::ndb_filter_destroy(self.as_mut_ptr()) }; 717 718 if let Some(ptr_arc) = &self.custom_ctx { 719 // Only drop the actual Box if this is the last Arc 720 let count = Arc::strong_count(ptr_arc); 721 if count == 1 { 722 let raw = **ptr_arc as *mut Box<dyn FnMut(Note) -> bool>; 723 tracing::trace!("dropping custom filter closure context"); 724 unsafe { 725 drop(Box::from_raw(raw)); 726 } 727 } else { 728 tracing::trace!("NOT dropping custom filter closure context, {count} instances"); 729 } 730 } 731 } 732 } 733 734 impl Drop for FilterBuilder { 735 fn drop(&mut self) { 736 debug!("dropping filter builder"); 737 } 738 } 739 740 #[derive(Debug, Copy, Clone)] 741 pub struct MutFilterIter<'a> { 742 filter: &'a bindings::ndb_filter, 743 index: i32, 744 } 745 746 impl<'a> MutFilterIter<'a> { 747 pub(crate) fn new(filter: &'a bindings::ndb_filter) -> Self { 748 let index = 0; 749 MutFilterIter { filter, index } 750 } 751 752 pub fn done(&self) -> bool { 753 self.index >= self.filter.num_elements 754 } 755 } 756 757 #[derive(Debug, Copy, Clone)] 758 pub struct FilterIter<'a> { 759 filter: &'a bindings::ndb_filter, 760 index: i32, 761 } 762 763 /// Filter element: `authors`, `limit`, etc 764 #[derive(Copy, Clone, Debug)] 765 pub struct FilterElements<'a> { 766 filter: &'a bindings::ndb_filter, 767 elements: *mut bindings::ndb_filter_elements, 768 } 769 770 #[derive(Copy, Clone, Debug)] 771 pub struct FilterIdElements<'a> { 772 filter: &'a bindings::ndb_filter, 773 elements: *mut bindings::ndb_filter_elements, 774 } 775 776 #[derive(Copy, Clone, Debug)] 777 pub struct FilterStrElements<'a> { 778 filter: &'a bindings::ndb_filter, 779 elements: *mut bindings::ndb_filter_elements, 780 } 781 782 #[derive(Copy, Clone, Debug)] 783 pub struct FilterIntElements<'a> { 784 _filter: &'a bindings::ndb_filter, 785 elements: *mut bindings::ndb_filter_elements, 786 } 787 788 pub struct FilterIdElemIter<'a> { 789 ids: FilterIdElements<'a>, 790 index: i32, 791 } 792 793 pub struct FilterStrElemIter<'a> { 794 strs: FilterStrElements<'a>, 795 index: i32, 796 } 797 798 pub struct FilterIntElemIter<'a> { 799 ints: FilterIntElements<'a>, 800 index: i32, 801 } 802 803 impl<'a> FilterIdElemIter<'a> { 804 pub(crate) fn new(ids: FilterIdElements<'a>) -> Self { 805 let index = 0; 806 Self { ids, index } 807 } 808 809 pub fn done(&self) -> bool { 810 self.index >= self.ids.count() 811 } 812 } 813 814 impl<'a> FilterStrElemIter<'a> { 815 pub(crate) fn new(strs: FilterStrElements<'a>) -> Self { 816 let index = 0; 817 Self { strs, index } 818 } 819 820 pub fn done(&self) -> bool { 821 self.index >= self.strs.count() 822 } 823 } 824 825 impl<'a> FilterIntElemIter<'a> { 826 pub(crate) fn new(ints: FilterIntElements<'a>) -> Self { 827 let index = 0; 828 Self { ints, index } 829 } 830 831 pub fn done(&self) -> bool { 832 self.index >= self.ints.count() 833 } 834 } 835 836 impl<'a> FilterIdElements<'a> { 837 pub(crate) fn new( 838 filter: &'a bindings::ndb_filter, 839 elements: *mut bindings::ndb_filter_elements, 840 ) -> Self { 841 Self { filter, elements } 842 } 843 844 pub fn count(&self) -> i32 { 845 unsafe { &*self.elements }.count 846 } 847 848 /// Field element type. In the case of ids, it would be FieldElemType::Id, etc 849 fn elemtype(&self) -> FieldElemType { 850 FieldElemType::new(unsafe { &*self.elements }.field.elem_type) 851 .expect("expected valid filter element type") 852 } 853 854 pub fn get(self, index: i32) -> Option<&'a [u8; 32]> { 855 assert!(self.elemtype() == FieldElemType::Id); 856 857 let id = unsafe { 858 bindings::ndb_filter_get_id_element(self.filter.as_ptr(), self.elements, index) 859 as *const [u8; 32] 860 }; 861 862 if id.is_null() { 863 return None; 864 } 865 866 Some(unsafe { &*id }) 867 } 868 } 869 870 impl<'a> FilterStrElements<'a> { 871 pub(crate) fn new( 872 filter: &'a bindings::ndb_filter, 873 elements: *mut bindings::ndb_filter_elements, 874 ) -> Self { 875 Self { filter, elements } 876 } 877 878 pub fn count(&self) -> i32 { 879 unsafe { &*self.elements }.count 880 } 881 882 /// Field element type. In the case of ids, it would be FieldElemType::Id, etc 883 fn elemtype(&self) -> FieldElemType { 884 FieldElemType::new(unsafe { &*self.elements }.field.elem_type) 885 .expect("expected valid filter element type") 886 } 887 888 pub fn get(self, index: i32) -> Option<&'a str> { 889 assert!(self.elemtype() == FieldElemType::Id); 890 891 let ptr = unsafe { 892 bindings::ndb_filter_get_string_element(self.filter.as_ptr(), self.elements, index) 893 }; 894 895 if ptr.is_null() { 896 return None; 897 } 898 899 let byte_slice = unsafe { std::slice::from_raw_parts(ptr as *mut u8, libc::strlen(ptr)) }; 900 Some(unsafe { std::str::from_utf8_unchecked(byte_slice) }) 901 } 902 } 903 904 impl<'a> FilterIntElements<'a> { 905 pub(crate) fn new( 906 filter: &'a bindings::ndb_filter, 907 elements: *mut bindings::ndb_filter_elements, 908 ) -> Self { 909 Self { 910 _filter: filter, 911 elements, 912 } 913 } 914 915 pub fn count(&self) -> i32 { 916 unsafe { &*self.elements }.count 917 } 918 919 /// Field element type. In the case of ids, it would be FieldElemType::Id, etc 920 fn elemtype(&self) -> FieldElemType { 921 FieldElemType::new(unsafe { &*self.elements }.field.elem_type) 922 .expect("expected valid filter element type") 923 } 924 925 pub fn get(self, index: i32) -> Option<u64> { 926 if index >= self.count() { 927 return None; 928 } 929 assert!(self.elemtype() == FieldElemType::Int); 930 Some(unsafe { bindings::ndb_filter_get_int_element(self.elements, index) }) 931 } 932 } 933 934 pub enum FilterField<'a> { 935 Ids(FilterIdElements<'a>), 936 Authors(FilterIdElements<'a>), 937 Kinds(FilterIntElements<'a>), 938 Tags(char, FilterElements<'a>), 939 Search(&'a str), 940 Since(u64), 941 Until(u64), 942 Limit(u64), 943 Relays(FilterStrElements<'a>), 944 Custom(u64), 945 } 946 947 pub enum MutFilterField<'a> { 948 Since(&'a mut u64), 949 Until(&'a mut u64), 950 Limit(&'a mut u64), 951 } 952 953 impl<'a> FilterField<'a> { 954 pub fn new(elements: FilterElements<'a>) -> Self { 955 match elements.fieldtype() { 956 FilterFieldType::Custom => FilterField::Custom(0), 957 958 FilterFieldType::Relays => { 959 FilterField::Relays(FilterStrElements::new(elements.filter(), elements.as_ptr())) 960 } 961 962 FilterFieldType::Search => { 963 for element in elements { 964 if let FilterElement::Str(s) = element { 965 return FilterField::Search(s); 966 } 967 } 968 969 panic!("something is very wrong"); 970 } 971 972 FilterFieldType::Ids => { 973 FilterField::Ids(FilterIdElements::new(elements.filter(), elements.as_ptr())) 974 } 975 976 FilterFieldType::Authors => { 977 FilterField::Authors(FilterIdElements::new(elements.filter(), elements.as_ptr())) 978 } 979 980 FilterFieldType::Kinds => { 981 FilterField::Kinds(FilterIntElements::new(elements.filter(), elements.as_ptr())) 982 } 983 984 FilterFieldType::Tags => FilterField::Tags(elements.tag(), elements), 985 986 FilterFieldType::Since => FilterField::Since( 987 FilterIntElements::new(elements.filter(), elements.as_ptr()) 988 .into_iter() 989 .next() 990 .expect("expected since in filter"), 991 ), 992 993 FilterFieldType::Until => FilterField::Until( 994 FilterIntElements::new(elements.filter(), elements.as_ptr()) 995 .into_iter() 996 .next() 997 .expect("expected until in filter"), 998 ), 999 1000 FilterFieldType::Limit => FilterField::Limit( 1001 FilterIntElements::new(elements.filter(), elements.as_ptr()) 1002 .into_iter() 1003 .next() 1004 .expect("expected limit in filter"), 1005 ), 1006 } 1007 } 1008 } 1009 1010 impl<'a> FilterElements<'a> { 1011 pub(crate) fn new( 1012 filter: &'a bindings::ndb_filter, 1013 elements: *mut bindings::ndb_filter_elements, 1014 ) -> Self { 1015 FilterElements { filter, elements } 1016 } 1017 1018 pub fn filter(self) -> &'a bindings::ndb_filter { 1019 self.filter 1020 } 1021 1022 pub fn as_ptr(self) -> *mut bindings::ndb_filter_elements { 1023 self.elements 1024 } 1025 1026 pub fn count(&self) -> i32 { 1027 unsafe { &*self.elements }.count 1028 } 1029 1030 pub fn field(self) -> FilterField<'a> { 1031 FilterField::new(self) 1032 } 1033 1034 /// Mutably access since, until, limit. We can probably do others in 1035 /// the future, but this is the most useful at the moment 1036 pub fn field_mut(self) -> Option<MutFilterField<'a>> { 1037 if self.count() != 1 { 1038 return None; 1039 } 1040 1041 if self.elemtype() != FieldElemType::Int { 1042 return None; 1043 } 1044 1045 match self.fieldtype() { 1046 FilterFieldType::Since => Some(MutFilterField::Since(self.get_mut_int(0))), 1047 FilterFieldType::Until => Some(MutFilterField::Until(self.get_mut_int(0))), 1048 FilterFieldType::Limit => Some(MutFilterField::Limit(self.get_mut_int(0))), 1049 _ => None, 1050 } 1051 } 1052 1053 pub fn get_mut_int(&self, index: i32) -> &'a mut u64 { 1054 unsafe { &mut *bindings::ndb_filter_get_int_element_ptr(self.elements, index) } 1055 } 1056 1057 pub fn get(self, index: i32) -> Option<FilterElement<'a>> { 1058 if index >= self.count() { 1059 return None; 1060 } 1061 1062 match self.elemtype() { 1063 FieldElemType::Id => { 1064 let id = unsafe { 1065 bindings::ndb_filter_get_id_element(self.filter.as_ptr(), self.elements, index) 1066 as *const [u8; 32] 1067 }; 1068 if id.is_null() { 1069 return None; 1070 } 1071 Some(FilterElement::Id(unsafe { &*id })) 1072 } 1073 1074 FieldElemType::Str => { 1075 let cstr = unsafe { 1076 bindings::ndb_filter_get_string_element( 1077 self.filter.as_ptr(), 1078 self.elements, 1079 index, 1080 ) 1081 }; 1082 if cstr.is_null() { 1083 return None; 1084 } 1085 let str = unsafe { 1086 let byte_slice = 1087 std::slice::from_raw_parts(cstr as *const u8, libc::strlen(cstr)); 1088 std::str::from_utf8_unchecked(byte_slice) 1089 }; 1090 Some(FilterElement::Str(str)) 1091 } 1092 1093 FieldElemType::Int => { 1094 let num = unsafe { bindings::ndb_filter_get_int_element(self.elements, index) }; 1095 Some(FilterElement::Int(num)) 1096 } 1097 1098 FieldElemType::Custom => { 1099 //let custom = unsafe { bindings::ndb_filter_get_custom_filter_element() } 1100 Some(FilterElement::Custom) 1101 } 1102 } 1103 } 1104 1105 /// Field element type. In the case of ids, it would be FieldElemType::Id, etc 1106 pub fn elemtype(&self) -> FieldElemType { 1107 FieldElemType::new(unsafe { &*self.elements }.field.elem_type) 1108 .expect("expected valid filter element type") 1109 } 1110 1111 /// Field element type. In the case of ids, it would be FieldElemType::Id, etc 1112 pub fn tag(&self) -> char { 1113 (unsafe { &*self.elements }.field.tag as u8) as char 1114 } 1115 1116 pub fn fieldtype(self) -> FilterFieldType { 1117 FilterFieldType::new(unsafe { &*self.elements }.field.type_) 1118 .expect("expected valid fieldtype") 1119 } 1120 } 1121 1122 impl<'a> FilterIter<'a> { 1123 pub fn new(filter: &'a bindings::ndb_filter) -> Self { 1124 let index = 0; 1125 FilterIter { filter, index } 1126 } 1127 1128 pub fn done(&self) -> bool { 1129 self.index >= self.filter.num_elements 1130 } 1131 } 1132 1133 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1134 pub enum FilterFieldType { 1135 Ids, 1136 Authors, 1137 Kinds, 1138 Tags, 1139 Since, 1140 Until, 1141 Limit, 1142 Search, 1143 Relays, 1144 Custom, 1145 } 1146 1147 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1148 pub enum FieldElemType { 1149 Str, 1150 Id, 1151 Int, 1152 Custom, 1153 } 1154 1155 impl FieldElemType { 1156 pub(crate) fn new(val: bindings::ndb_generic_element_type) -> Option<Self> { 1157 if val == bindings::ndb_generic_element_type_NDB_ELEMENT_UNKNOWN { 1158 None 1159 } else if val == bindings::ndb_generic_element_type_NDB_ELEMENT_STRING { 1160 Some(FieldElemType::Str) 1161 } else if val == bindings::ndb_generic_element_type_NDB_ELEMENT_ID { 1162 Some(FieldElemType::Id) 1163 } else if val == bindings::ndb_generic_element_type_NDB_ELEMENT_INT { 1164 Some(FieldElemType::Int) 1165 } else if val == bindings::ndb_generic_element_type_NDB_ELEMENT_CUSTOM { 1166 Some(FieldElemType::Custom) 1167 } else { 1168 None 1169 } 1170 } 1171 } 1172 1173 impl FilterFieldType { 1174 pub(crate) fn new(val: bindings::ndb_filter_fieldtype) -> Option<Self> { 1175 if val == bindings::ndb_filter_fieldtype_NDB_FILTER_IDS { 1176 Some(FilterFieldType::Ids) 1177 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_AUTHORS { 1178 Some(FilterFieldType::Authors) 1179 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_KINDS { 1180 Some(FilterFieldType::Kinds) 1181 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_TAGS { 1182 Some(FilterFieldType::Tags) 1183 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_SINCE { 1184 Some(FilterFieldType::Since) 1185 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_UNTIL { 1186 Some(FilterFieldType::Until) 1187 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_LIMIT { 1188 Some(FilterFieldType::Limit) 1189 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_SEARCH { 1190 Some(FilterFieldType::Search) 1191 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_RELAYS { 1192 Some(FilterFieldType::Relays) 1193 } else if val == bindings::ndb_filter_fieldtype_NDB_FILTER_CUSTOM { 1194 Some(FilterFieldType::Custom) 1195 } else { 1196 None 1197 } 1198 } 1199 } 1200 1201 impl<'a> IntoIterator for &'a Filter { 1202 type Item = FilterField<'a>; 1203 type IntoIter = FilterIter<'a>; 1204 1205 fn into_iter(self) -> Self::IntoIter { 1206 FilterIter::new(self.to_ref()) 1207 } 1208 } 1209 1210 impl<'a> IntoIterator for &'a FilterBuilder { 1211 type Item = FilterField<'a>; 1212 type IntoIter = FilterIter<'a>; 1213 1214 fn into_iter(self) -> Self::IntoIter { 1215 FilterIter::new(self.to_ref()) 1216 } 1217 } 1218 1219 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1220 pub enum FilterElement<'a> { 1221 Str(&'a str), 1222 Id(&'a [u8; 32]), 1223 Int(u64), 1224 Custom, 1225 } 1226 1227 impl<'a> Iterator for FilterIter<'a> { 1228 type Item = FilterField<'a>; 1229 1230 fn next(&mut self) -> Option<FilterField<'a>> { 1231 if self.done() { 1232 return None; 1233 } 1234 1235 let ind = self.index; 1236 self.index += 1; 1237 1238 self.filter.field(ind) 1239 } 1240 } 1241 1242 impl<'a> Iterator for MutFilterIter<'a> { 1243 type Item = MutFilterField<'a>; 1244 1245 fn next(&mut self) -> Option<MutFilterField<'a>> { 1246 if self.done() { 1247 return None; 1248 } 1249 1250 while !self.done() { 1251 let mnext = self.filter.field_mut(self.index); 1252 self.index += 1; 1253 1254 if mnext.is_some() { 1255 return mnext; 1256 } 1257 } 1258 1259 None 1260 } 1261 } 1262 1263 impl<'a> IntoIterator for FilterIdElements<'a> { 1264 type Item = &'a [u8; 32]; 1265 type IntoIter = FilterIdElemIter<'a>; 1266 1267 fn into_iter(self) -> Self::IntoIter { 1268 FilterIdElemIter::new(self) 1269 } 1270 } 1271 1272 impl<'a> IntoIterator for FilterStrElements<'a> { 1273 type Item = &'a str; 1274 type IntoIter = FilterStrElemIter<'a>; 1275 1276 fn into_iter(self) -> Self::IntoIter { 1277 FilterStrElemIter::new(self) 1278 } 1279 } 1280 1281 impl<'a> IntoIterator for FilterIntElements<'a> { 1282 type Item = u64; 1283 type IntoIter = FilterIntElemIter<'a>; 1284 1285 fn into_iter(self) -> Self::IntoIter { 1286 FilterIntElemIter::new(self) 1287 } 1288 } 1289 1290 impl Iterator for FilterIntElemIter<'_> { 1291 type Item = u64; 1292 1293 fn next(&mut self) -> Option<u64> { 1294 if self.done() { 1295 return None; 1296 } 1297 1298 let ind = self.index; 1299 self.index += 1; 1300 1301 self.ints.get(ind) 1302 } 1303 } 1304 1305 impl<'a> Iterator for FilterStrElemIter<'a> { 1306 type Item = &'a str; 1307 1308 fn next(&mut self) -> Option<&'a str> { 1309 if self.done() { 1310 return None; 1311 } 1312 1313 let ind = self.index; 1314 self.index += 1; 1315 1316 self.strs.get(ind) 1317 } 1318 } 1319 1320 impl<'a> Iterator for FilterIdElemIter<'a> { 1321 type Item = &'a [u8; 32]; 1322 1323 fn next(&mut self) -> Option<&'a [u8; 32]> { 1324 if self.done() { 1325 return None; 1326 } 1327 1328 let ind = self.index; 1329 self.index += 1; 1330 1331 self.ids.get(ind) 1332 } 1333 } 1334 1335 impl<'a> IntoIterator for FilterElements<'a> { 1336 type Item = FilterElement<'a>; 1337 type IntoIter = FilterElemIter<'a>; 1338 1339 fn into_iter(self) -> Self::IntoIter { 1340 FilterElemIter::new(self) 1341 } 1342 } 1343 1344 impl<'a> Iterator for FilterElemIter<'a> { 1345 type Item = FilterElement<'a>; 1346 1347 fn next(&mut self) -> Option<FilterElement<'a>> { 1348 let element = self.elements.get(self.index); 1349 if element.is_some() { 1350 self.index += 1; 1351 element 1352 } else { 1353 None 1354 } 1355 } 1356 } 1357 1358 #[derive(Copy, Clone, Debug)] 1359 pub struct FilterElemIter<'a> { 1360 elements: FilterElements<'a>, 1361 index: i32, 1362 } 1363 1364 impl<'a> FilterElemIter<'a> { 1365 pub(crate) fn new(elements: FilterElements<'a>) -> Self { 1366 let index = 0; 1367 FilterElemIter { elements, index } 1368 } 1369 } 1370 1371 extern "C" fn custom_filter_trampoline( 1372 ctx: *mut ::std::os::raw::c_void, 1373 note: *mut bindings::ndb_note, 1374 ) -> bool { 1375 unsafe { 1376 // Convert the raw pointer back into a reference to our closure. 1377 // We know this pointer was created by Box::into_raw in `set_sub_callback_rust`. 1378 let closure_ptr = ctx as *mut Box<dyn FnMut(Note<'_>) -> bool>; 1379 assert!(!closure_ptr.is_null()); 1380 let closure = &mut *closure_ptr; 1381 let note = Note::new_unowned(&*note); 1382 closure(note) 1383 } 1384 } 1385 1386 #[cfg(test)] 1387 mod tests { 1388 use super::*; 1389 1390 #[test] 1391 fn filter_limit_iter_works() { 1392 let filter = Filter::new().limit(42).build(); 1393 let mut hit = 0; 1394 for element in &filter { 1395 if let FilterField::Limit(42) = element { 1396 hit += 1; 1397 } 1398 } 1399 assert!(hit == 1); 1400 } 1401 1402 #[test] 1403 fn filter_quick_since_mut_works() { 1404 let id: [u8; 32] = [ 1405 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, 1406 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, 1407 0xe8, 0x5b, 0xa8, 0x59, 1408 ]; 1409 1410 let mut hit = 0; 1411 let mut filter = Filter::new().ids([&id, &id, &id]).build(); 1412 1413 // mutate 1414 filter = filter.since_mut(3); 1415 1416 for element in &filter { 1417 if let FilterField::Since(s) = element { 1418 hit += 1; 1419 assert_eq!(s, 3); 1420 } 1421 } 1422 assert!(hit == 1); 1423 } 1424 1425 #[test] 1426 fn filter_since_mut_works() { 1427 let id: [u8; 32] = [ 1428 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, 1429 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, 1430 0xe8, 0x5b, 0xa8, 0x59, 1431 ]; 1432 1433 let mut hit = 0; 1434 let filter = Filter::new().ids([&id, &id, &id]).since(1); 1435 1436 for element in filter.mut_iter() { 1437 if let MutFilterField::Since(since_ref) = element { 1438 hit += 1; 1439 assert_eq!(*since_ref, 1); 1440 *since_ref = 2; 1441 } 1442 } 1443 for element in &filter { 1444 if let FilterField::Since(s) = element { 1445 hit += 1; 1446 assert_eq!(s, 2); 1447 } 1448 } 1449 assert!(hit == 2); 1450 } 1451 1452 #[test] 1453 fn filter_id_iter_works() { 1454 let id: [u8; 32] = [ 1455 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, 1456 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, 1457 0xe8, 0x5b, 0xa8, 0x59, 1458 ]; 1459 1460 let filter = Filter::new().ids([&id, &id, &id]).build(); 1461 let mut hit = 0; 1462 for element in &filter { 1463 if let FilterField::Ids(ids) = element { 1464 for same_id in ids { 1465 hit += 1; 1466 assert!(same_id == &id); 1467 } 1468 } 1469 } 1470 assert!(hit == 3); 1471 } 1472 1473 #[test] 1474 fn filter_int_iter_works() { 1475 let filter = Filter::new().kinds(vec![1, 2, 3]).build(); 1476 let mut hit = 0; 1477 for element in &filter { 1478 if let FilterField::Kinds(ks) = element { 1479 hit += 1; 1480 assert!(vec![1, 2, 3] == ks.into_iter().collect::<Vec<u64>>()); 1481 } 1482 } 1483 assert!(hit == 1); 1484 } 1485 1486 #[test] 1487 fn filter_multiple_field_iter_works() { 1488 let id: [u8; 32] = [ 1489 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, 1490 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, 1491 0xe8, 0x5b, 0xa8, 0x59, 1492 ]; 1493 let filter = Filter::new().event(&id).kinds(vec![1, 2, 3]).build(); 1494 let mut hit = 0; 1495 for element in &filter { 1496 if let FilterField::Kinds(ks) = element { 1497 hit += 1; 1498 assert!(vec![1, 2, 3] == ks.into_iter().collect::<Vec<u64>>()); 1499 } else if let FilterField::Tags('e', ids) = element { 1500 for i in ids { 1501 hit += 1; 1502 assert!(i == FilterElement::Id(&id)); 1503 } 1504 } 1505 } 1506 assert!(hit == 2); 1507 } 1508 1509 #[test] 1510 fn custom_filter_works() { 1511 use crate::NoteBuilder; 1512 1513 let seckey: [u8; 32] = [ 1514 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, 1515 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, 1516 0xe8, 0x5b, 0xa8, 0x59, 1517 ]; 1518 1519 let note = NoteBuilder::new() 1520 .kind(1) 1521 .content("this is the content") 1522 .created_at(42) 1523 .start_tag() 1524 .tag_str("comment") 1525 .tag_str("this is a comment") 1526 .start_tag() 1527 .tag_str("blah") 1528 .tag_str("something") 1529 .sign(&seckey) 1530 .build() 1531 .expect("expected build to work"); 1532 1533 { 1534 let filter = Filter::new().custom(|n| n.created_at() == 43).build(); 1535 assert!(!filter.matches(¬e)); 1536 } 1537 1538 { 1539 let filter = Filter::new().custom(|n| n.created_at() == 42).build(); 1540 // test Arc 1541 let _filter2 = filter.clone(); 1542 assert!(filter.matches(¬e)); 1543 } 1544 1545 { 1546 let filter = Filter::new() 1547 .custom(|n| { 1548 n.tags() 1549 .into_iter() 1550 .next() 1551 .and_then(|t| t.get_str(1)) 1552 .map_or(false, |s| s == "this is a comment") 1553 }) 1554 .build(); 1555 assert!(filter.matches(¬e)); 1556 } 1557 } 1558 }