nostrdb-rs

nostrdb in rust!
git clone git://jb55.com/nostrdb-rs
Log | Files | Refs | Submodules | README | LICENSE

commit dfc4c27bf631b5b1d304562d9a26656836a573ae
parent 356cbe0fc11ee4dc1f93908dcc1e858c5291e20c
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 19 Aug 2024 15:31:14 -0700

filter: expose more builder options

to do this, we need to make filterbuilder handle errors better

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/error.rs | 54+++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/filter.rs | 201+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/lib.rs | 2+-
3 files changed, 163 insertions(+), 94 deletions(-)

diff --git a/src/error.rs b/src/error.rs @@ -10,21 +10,53 @@ pub enum Error { TransactionFailed, SubscriptionError, BufferOverflow, + Filter(FilterError), +} + +impl Error { + pub fn filter(ferr: FilterError) -> Self { + Error::Filter(ferr) + } +} + +#[derive(Debug, Eq, PartialEq)] +pub enum FilterError { + FieldAlreadyExists, + FieldAlreadyStarted, +} + +impl FilterError { + pub fn already_exists() -> Error { + Error::Filter(FilterError::FieldAlreadyExists) + } + + pub fn already_started() -> Error { + Error::Filter(FilterError::FieldAlreadyStarted) + } +} + +impl fmt::Display for FilterError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FilterError::FieldAlreadyExists => write!(f, "field already exists"), + FilterError::FieldAlreadyStarted => write!(f, "field already started"), + } + } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Error::DbOpenFailed => "Open failed", - Error::NotFound => "Not found", - Error::QueryError => "Query failed", - Error::DecodeError => "Decode error", - Error::NoteProcessFailed => "Note process failed", - Error::TransactionFailed => "Transaction failed", - Error::SubscriptionError => "Subscription failed", - Error::BufferOverflow => "Buffer overflow", - }; - write!(f, "{}", s) + match self { + Error::DbOpenFailed => write!(f, "Open failed"), + Error::NotFound => write!(f, "Not found"), + Error::QueryError => write!(f, "Query failed"), + Error::DecodeError => write!(f, "Decode error"), + Error::NoteProcessFailed => write!(f, "Note process failed"), + Error::TransactionFailed => write!(f, "Transaction failed"), + Error::SubscriptionError => write!(f, "Subscription failed"), + Error::BufferOverflow => write!(f, "Buffer overflow"), + Error::Filter(filter_err) => write!(f, "Filter: {filter_err}"), + } } } diff --git a/src/filter.rs b/src/filter.rs @@ -1,4 +1,4 @@ -use crate::{bindings, Error, Note}; +use crate::{bindings, Error, FilterError, Note, Result}; use std::ffi::CString; use std::os::raw::c_char; use std::ptr::null_mut; @@ -112,7 +112,7 @@ impl Filter { self.data.as_mut_ptr() } - pub fn json_with_bufsize(&self, bufsize: usize) -> Result<String, Error> { + pub fn json_with_bufsize(&self, bufsize: usize) -> Result<String> { let mut buf = Vec::with_capacity(bufsize); unsafe { let size = bindings::ndb_filter_json( @@ -132,7 +132,7 @@ impl Filter { } } - pub fn json(&self) -> Result<String, Error> { + pub fn json(&self) -> Result<String> { // 1mb buffer self.json_with_bufsize(1024usize * 1024usize) } @@ -159,162 +159,199 @@ impl FilterBuilder { self.data.as_mut_ptr() } - fn add_int_element(&mut self, i: u64) { - unsafe { bindings::ndb_filter_add_int_element(self.as_mut_ptr(), i) }; + pub fn add_int_element(&mut self, i: u64) -> Result<()> { + let res = unsafe { bindings::ndb_filter_add_int_element(self.as_mut_ptr(), i) }; + if res == 0 { + return Err(FilterError::already_exists()); + } + + Ok(()) } - fn add_str_element(&mut self, s: &str) { + pub fn add_str_element(&mut self, s: &str) -> Result<()> { let c_str = CString::new(s).expect("string to cstring conversion failed"); - unsafe { - bindings::ndb_filter_add_str_element(self.as_mut_ptr(), c_str.as_ptr()); - }; + let r = unsafe { bindings::ndb_filter_add_str_element(self.as_mut_ptr(), c_str.as_ptr()) }; + + if r == 0 { + return Err(FilterError::already_exists()); + } + + Ok(()) } - fn add_id_element(&mut self, id: &[u8; 32]) { + pub fn add_id_element(&mut self, id: &[u8; 32]) -> Result<()> { let ptr: *const ::std::os::raw::c_uchar = id.as_ptr() as *const ::std::os::raw::c_uchar; - unsafe { - bindings::ndb_filter_add_id_element(self.as_mut_ptr(), ptr); - }; + let r = unsafe { bindings::ndb_filter_add_id_element(self.as_mut_ptr(), ptr) }; + + if r == 0 { + return Err(FilterError::already_exists()); + } + + Ok(()) } - fn start_field(&mut self, field: bindings::ndb_filter_fieldtype) { - unsafe { bindings::ndb_filter_start_field(self.as_mut_ptr(), field) }; + pub fn start_field(&mut self, field: bindings::ndb_filter_fieldtype) -> Result<()> { + let r = unsafe { bindings::ndb_filter_start_field(self.as_mut_ptr(), field) }; + + if r == 0 { + return Err(FilterError::already_started()); + } + + Ok(()) } - fn start_tags_field(&mut self, tag: char) { - unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; + pub fn start_tags_field(&mut self, tag: char) -> Result<()> { + let r = + unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; + if r == 0 { + return Err(FilterError::already_started()); + } + Ok(()) } - fn start_kinds_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_KINDS); + pub fn start_kinds_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_KINDS) } - fn start_authors_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_AUTHORS); + pub fn start_authors_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_AUTHORS) } - fn start_since_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_SINCE); + pub fn start_since_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_SINCE) } - fn start_until_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_UNTIL); + pub fn start_until_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_UNTIL) } - fn start_limit_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_LIMIT); + pub fn start_limit_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_LIMIT) } - fn start_ids_field(&mut self) { - self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_IDS); + pub fn start_ids_field(&mut self) -> Result<()> { + self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_IDS) } #[allow(dead_code)] - fn start_events_field(&mut self) { - self.start_tags_field('e'); + pub fn start_events_field(&mut self) -> Result<()> { + self.start_tags_field('e') } - fn start_pubkeys_field(&mut self) { - self.start_tags_field('p'); + pub fn start_pubkeys_field(&mut self) -> Result<()> { + self.start_tags_field('p') } - fn start_tag_field(&mut self, tag: char) { - unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; + pub fn start_tag_field(&mut self, tag: char) -> Result<()> { + let r = + unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) }; + if r == 0 { + return Err(Error::filter(FilterError::FieldAlreadyStarted)); + } + Ok(()) } - fn end_field(&mut self) { - unsafe { bindings::ndb_filter_end_field(self.as_mut_ptr()) } + pub fn end_field(&mut self) { + unsafe { + bindings::ndb_filter_end_field(self.as_mut_ptr()); + }; } - pub fn events(mut self, events: Vec<[u8; 32]>) -> Self { - self.start_tag_field('e'); + pub fn events(mut self, events: Vec<[u8; 32]>) -> Result<Self> { + self.start_tag_field('e')?; for ref id in events { - self.add_id_element(id); + self.add_id_element(id)?; } self.end_field(); - self + Ok(self) } - pub fn event(mut self, id: &[u8; 32]) -> Self { - self.start_tag_field('e'); - self.add_id_element(id); + pub fn event(mut self, id: &[u8; 32]) -> Result<Self> { + self.start_tag_field('e')?; + self.add_id_element(id)?; self.end_field(); - self + Ok(self) } - pub fn ids(mut self, ids: Vec<[u8; 32]>) -> Self { - self.start_ids_field(); - for ref id in ids { - self.add_id_element(id); + pub fn ids<'a, I>(mut self, ids: I) -> Result<Self> + where + I: Iterator<Item = &'a [u8; 32]>, + { + self.start_ids_field()?; + for id in ids { + self.add_id_element(id)?; } self.end_field(); - self + Ok(self) } - pub fn pubkeys(mut self, pubkeys: Vec<[u8; 32]>) -> Self { - self.start_tag_field('p'); + pub fn pubkeys(mut self, pubkeys: Vec<[u8; 32]>) -> Result<Self> { + self.start_tag_field('p')?; for ref pk in pubkeys { - self.add_id_element(pk); + self.add_id_element(pk)?; } self.end_field(); - self + Ok(self) } - pub fn authors(mut self, authors: Vec<[u8; 32]>) -> Self { - self.start_authors_field(); + pub fn authors<'a, I>(mut self, authors: I) -> Result<Self> + where + I: Iterator<Item = &'a [u8; 32]>, + { + self.start_authors_field()?; for author in authors { - self.add_id_element(&author); + self.add_id_element(author)?; } self.end_field(); - self + Ok(self) } - pub fn kinds(mut self, kinds: Vec<u64>) -> Self { - self.start_kinds_field(); + pub fn kinds(mut self, kinds: Vec<u64>) -> Result<Self> { + self.start_kinds_field()?; for kind in kinds { - self.add_int_element(kind); + self.add_int_element(kind)?; } self.end_field(); - self + Ok(self) } - pub fn pubkey(mut self, pubkeys: Vec<[u8; 32]>) -> Self { - self.start_pubkeys_field(); + pub fn pubkey(mut self, pubkeys: Vec<[u8; 32]>) -> Result<Self> { + self.start_pubkeys_field()?; for ref pubkey in pubkeys { - self.add_id_element(pubkey); + self.add_id_element(pubkey)?; } self.end_field(); - self + Ok(self) } - pub fn tags(mut self, tags: Vec<String>, tag: char) -> Self { - self.start_tag_field(tag); + pub fn tags(mut self, tags: Vec<String>, tag: char) -> Result<Self> { + self.start_tag_field(tag)?; for tag in tags { - self.add_str_element(&tag); + self.add_str_element(&tag)?; } self.end_field(); - self + Ok(self) } - pub fn since(mut self, since: u64) -> Self { - self.start_since_field(); - self.add_int_element(since); + pub fn since(mut self, since: u64) -> Result<Self> { + self.start_since_field()?; + self.add_int_element(since)?; self.end_field(); - self + Ok(self) } - pub fn until(mut self, until: u64) -> Self { - self.start_until_field(); - self.add_int_element(until); + pub fn until(mut self, until: u64) -> Result<Self> { + self.start_until_field()?; + self.add_int_element(until)?; self.end_field(); - self + Ok(self) } - pub fn limit(mut self, limit: u64) -> Self { - self.start_limit_field(); - self.add_int_element(limit); + pub fn limit(mut self, limit: u64) -> Result<Self> { + self.start_limit_field()?; + self.add_int_element(limit)?; self.end_field(); - self + Ok(self) } pub fn build(&mut self) -> Filter { diff --git a/src/lib.rs b/src/lib.rs @@ -28,7 +28,7 @@ mod util; pub use block::{Block, BlockType, Blocks, Mention}; pub use config::Config; -pub use error::Error; +pub use error::{Error, FilterError}; pub use filter::{Filter, FilterBuilder}; pub use ndb::Ndb; pub use ndb_profile::{NdbProfile, NdbProfileRecord};