diff --git a/build.rs b/build.rs index 2c88cfd..b186505 100644 --- a/build.rs +++ b/build.rs @@ -119,9 +119,9 @@ fn main() { println!("cargo:rustc-link-lib=static=nostrdb"); // Link Security framework on macOS - //if cfg!(target_os = "macos") { - //println!("cargo:rustc-link-lib=framework=Security"); - //} + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-lib=framework=Security"); + } // // We only need bindgen when we update the bindings. diff --git a/nostrdb b/nostrdb index cd9ba0e..7365c20 160000 --- a/nostrdb +++ b/nostrdb @@ -1 +1 @@ -Subproject commit cd9ba0ea7dfd021f2a3e98aefef87990d161aab3 +Subproject commit 7365c20e5277431632d43f730ae48e79750373c4 diff --git a/src/bindings.rs b/src/bindings.rs index 839ffb5..0eb89f0 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -279,6 +279,7 @@ pub const __MAC_14_3: u32 = 140300; pub const __MAC_14_4: u32 = 140400; pub const __MAC_14_5: u32 = 140500; pub const __MAC_15_0: u32 = 150000; +pub const __MAC_15_1: u32 = 150100; pub const __IPHONE_2_0: u32 = 20000; pub const __IPHONE_2_1: u32 = 20100; pub const __IPHONE_2_2: u32 = 20200; @@ -359,6 +360,7 @@ pub const __IPHONE_17_3: u32 = 170300; pub const __IPHONE_17_4: u32 = 170400; pub const __IPHONE_17_5: u32 = 170500; pub const __IPHONE_18_0: u32 = 180000; +pub const __IPHONE_18_1: u32 = 180100; pub const __WATCHOS_1_0: u32 = 10000; pub const __WATCHOS_2_0: u32 = 20000; pub const __WATCHOS_2_1: u32 = 20100; @@ -407,6 +409,7 @@ pub const __WATCHOS_10_3: u32 = 100300; pub const __WATCHOS_10_4: u32 = 100400; pub const __WATCHOS_10_5: u32 = 100500; pub const __WATCHOS_11_0: u32 = 110000; +pub const __WATCHOS_11_1: u32 = 110100; pub const __TVOS_9_0: u32 = 90000; pub const __TVOS_9_1: u32 = 90100; pub const __TVOS_9_2: u32 = 90200; @@ -456,6 +459,7 @@ pub const __TVOS_17_3: u32 = 170300; pub const __TVOS_17_4: u32 = 170400; pub const __TVOS_17_5: u32 = 170500; pub const __TVOS_18_0: u32 = 180000; +pub const __TVOS_18_1: u32 = 180100; pub const __BRIDGEOS_2_0: u32 = 20000; pub const __BRIDGEOS_3_0: u32 = 30000; pub const __BRIDGEOS_3_1: u32 = 30100; @@ -483,6 +487,7 @@ pub const __BRIDGEOS_8_3: u32 = 80300; pub const __BRIDGEOS_8_4: u32 = 80400; pub const __BRIDGEOS_8_5: u32 = 80500; pub const __BRIDGEOS_9_0: u32 = 90000; +pub const __BRIDGEOS_9_1: u32 = 90100; pub const __DRIVERKIT_19_0: u32 = 190000; pub const __DRIVERKIT_20_0: u32 = 200000; pub const __DRIVERKIT_21_0: u32 = 210000; @@ -497,10 +502,12 @@ pub const __DRIVERKIT_23_3: u32 = 230300; pub const __DRIVERKIT_23_4: u32 = 230400; pub const __DRIVERKIT_23_5: u32 = 230500; pub const __DRIVERKIT_24_0: u32 = 240000; +pub const __DRIVERKIT_24_1: u32 = 240100; pub const __VISIONOS_1_0: u32 = 10000; pub const __VISIONOS_1_1: u32 = 10100; pub const __VISIONOS_1_2: u32 = 10200; pub const __VISIONOS_2_0: u32 = 20000; +pub const __VISIONOS_2_1: u32 = 20100; pub const MAC_OS_X_VERSION_10_0: u32 = 1000; pub const MAC_OS_X_VERSION_10_1: u32 = 1010; pub const MAC_OS_X_VERSION_10_2: u32 = 1020; @@ -563,8 +570,10 @@ pub const MAC_OS_VERSION_14_3: u32 = 140300; pub const MAC_OS_VERSION_14_4: u32 = 140400; pub const MAC_OS_VERSION_14_5: u32 = 140500; pub const MAC_OS_VERSION_15_0: u32 = 150000; -pub const __MAC_OS_X_VERSION_MAX_ALLOWED: u32 = 150000; +pub const MAC_OS_VERSION_15_1: u32 = 150100; +pub const __MAC_OS_X_VERSION_MAX_ALLOWED: u32 = 150100; pub const __ENABLE_LEGACY_MAC_AVAILABILITY: u32 = 1; +pub const USE_CLANG_TYPES: u32 = 0; pub const __PTHREAD_SIZE__: u32 = 8176; pub const __PTHREAD_ATTR_SIZE__: u32 = 56; pub const __PTHREAD_MUTEXATTR_SIZE__: u32 = 8; @@ -576,6 +585,7 @@ pub const __PTHREAD_RWLOCK_SIZE__: u32 = 192; pub const __PTHREAD_RWLOCKATTR_SIZE__: u32 = 16; pub const __DARWIN_WCHAR_MIN: i32 = -2147483648; pub const _FORTIFY_SOURCE: u32 = 2; +pub const USE_CLANG_STDDEF: u32 = 0; pub const __WORDSIZE: u32 = 64; pub const INT8_MAX: u32 = 127; pub const INT16_MAX: u32 = 32767; @@ -635,6 +645,7 @@ pub const HAVE_LITTLE_ENDIAN: u32 = 1; pub const __bool_true_false_are_defined: u32 = 1; pub const true_: u32 = 1; pub const false_: u32 = 0; +pub const USE_CLANG_STDARG: u32 = 0; pub const RENAME_SECLUDE: u32 = 1; pub const RENAME_SWAP: u32 = 2; pub const RENAME_EXCL: u32 = 4; @@ -5760,6 +5771,17 @@ extern "C" { str_: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; } +extern "C" { + pub fn ndb_filter_eq(arg1: *const ndb_filter, arg2: *const ndb_filter) + -> ::std::os::raw::c_int; +} +extern "C" { + #[doc = " is `a` a subset of `b`"] + pub fn ndb_filter_is_subset_of( + a: *const ndb_filter, + b: *const ndb_filter, + ) -> ::std::os::raw::c_int; +} extern "C" { pub fn ndb_filter_from_json( arg1: *const ::std::os::raw::c_char, @@ -5867,6 +5889,13 @@ extern "C" { extern "C" { pub fn ndb_num_subscriptions(arg1: *mut ndb) -> ::std::os::raw::c_int; } +extern "C" { + pub fn ndb_subscription_filters( + arg1: *mut ndb, + subid: u64, + filters: *mut ::std::os::raw::c_int, + ) -> *mut ndb_filter; +} extern "C" { pub fn ndb_text_search( txn: *mut ndb_txn, diff --git a/src/filter.rs b/src/filter.rs index 6022881..bb3f212 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -14,6 +14,14 @@ pub struct Filter { pub data: bindings::ndb_filter, } +impl PartialEq for Filter { + fn eq(&self, other: &Filter) -> bool { + unsafe { + bindings::ndb_filter_eq(self.as_ptr(), other.as_ptr()) == 1 + } + } +} + impl Clone for Filter { fn clone(&self) -> Self { let mut new_filter: bindings::ndb_filter = Default::default(); @@ -112,6 +120,40 @@ impl Filter { } } + /// Given a set of filters, filter redundant ones. This is done by + /// finding all the filters that are subsets of every other filter. If + /// a filter is known to be a subset of another, it is removed. + pub fn optimize(filters: &[Filter]) -> Vec { + let mut is_subset: Vec = vec![false; filters.len()]; + + for (i1, f1) in filters.iter().enumerate() { + for (i2, f2) in filters.iter().enumerate() { + // we don't want to count ourselves + if i1 == i2 { + continue; + } + + if f2.is_subset_of(f1) { + is_subset[i2] = true; + } + } + } + + filters + .iter() + .enumerate() + .filter(|(i, _f)| !is_subset[*i]) + .map(|(_i, f)| f.clone()) + .collect() + } + + /// Is this filter a subset of another + pub fn is_subset_of(&self, b: &Filter) -> bool { + unsafe { + bindings::ndb_filter_is_subset_of(self.as_ptr(), b.as_ptr()) == 1 + } + } + pub fn copy_from<'a, I>(filter: I) -> FilterBuilder where I: IntoIterator>, @@ -1078,6 +1120,29 @@ impl<'a> FilterElemIter<'a> { mod tests { use super::*; + #[test] + fn filter_test_subset_optimize() { + let id: [u8; 32] = [ + 0xfb, 0x16, 0x5b, 0xe2, 0x2c, 0x7b, 0x25, 0x18, 0xb7, 0x49, 0xaa, 0xbb, 0x71, 0x40, + 0xc7, 0x3f, 0x08, 0x87, 0xfe, 0x84, 0x47, 0x5c, 0x82, 0x78, 0x57, 0x00, 0x66, 0x3b, + 0xe8, 0x5b, 0xa8, 0x59, + ]; + let expected = [ + Filter::new().kinds(vec![1]).build(), + Filter::new().kinds(vec![2]).build(), + ]; + + let filters = [ + Filter::new().kinds(vec![1]).build(), + Filter::new().kinds(vec![2]).build(), + Filter::new().kinds(vec![1]).authors(vec![&id]).build(), + Filter::new().kinds(vec![2]).authors(vec![&id]).build(), + ]; + + let output = Filter::optimize(&filters); + assert_eq!(output, expected); + } + #[test] fn filter_limit_iter_works() { let filter = Filter::new().limit(42).build();