nostrdb-rs

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

note.rs (5128B)


      1 use crate::bindings;
      2 use crate::tags::Tags;
      3 use crate::transaction::Transaction;
      4 use std::hash::Hash;
      5 
      6 #[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash)]
      7 pub struct NoteKey(u64);
      8 
      9 impl NoteKey {
     10     pub fn as_u64(&self) -> u64 {
     11         self.0
     12     }
     13 
     14     pub fn new(key: u64) -> Self {
     15         NoteKey(key)
     16     }
     17 }
     18 
     19 #[derive(Debug, Clone)]
     20 pub enum Note<'a> {
     21     /// A note in-memory outside of nostrdb. This note is a pointer to a note in
     22     /// memory and will be free'd when [Drop]ped. Method such as [Note::from_json]
     23     /// will create owned notes in memory.
     24     ///
     25     /// [Drop]: std::ops::Drop
     26     Owned {
     27         ptr: *mut bindings::ndb_note,
     28         size: usize,
     29     },
     30 
     31     /// A note inside of nostrdb. Tied to the lifetime of a
     32     /// [Transaction] to ensure no reading of data outside
     33     /// of a transaction.
     34     Transactional {
     35         ptr: *mut bindings::ndb_note,
     36         size: usize,
     37         key: NoteKey,
     38         transaction: &'a Transaction,
     39     },
     40 }
     41 
     42 impl<'a> Note<'a> {
     43     /// Constructs an owned `Note`. This note is a pointer to a note in
     44     /// memory and will be free'd when [Drop]ped. You normally wouldn't
     45     /// use this method directly, public consumer would use from_json instead.
     46     ///
     47     /// [Drop]: std::ops::Drop
     48     #[allow(dead_code)]
     49     pub(crate) fn new_owned(ptr: *mut bindings::ndb_note, size: usize) -> Note<'static> {
     50         Note::Owned { ptr, size }
     51     }
     52 
     53     /// Constructs a `Note` in a transactional context.
     54     /// Use [Note::new_transactional] to create a new transactional note.
     55     /// You normally wouldn't use this method directly, it is used by
     56     /// functions that get notes from the database like
     57     /// [ndb_get_note_by_id]
     58     pub(crate) fn new_transactional(
     59         ptr: *mut bindings::ndb_note,
     60         size: usize,
     61         key: NoteKey,
     62         transaction: &'a Transaction,
     63     ) -> Note<'a> {
     64         Note::Transactional {
     65             ptr,
     66             size,
     67             key,
     68             transaction,
     69         }
     70     }
     71 
     72     pub fn txn(&'a self) -> Option<&'a Transaction> {
     73         match self {
     74             Note::Transactional { transaction, .. } => Some(transaction),
     75             _ => None,
     76         }
     77     }
     78 
     79     pub fn key(&self) -> Option<NoteKey> {
     80         match self {
     81             Note::Transactional { key, .. } => Some(NoteKey::new(key.as_u64())),
     82             _ => None,
     83         }
     84     }
     85 
     86     pub fn size(&self) -> usize {
     87         match self {
     88             Note::Owned { size, .. } => *size,
     89             Note::Transactional { size, .. } => *size,
     90         }
     91     }
     92 
     93     pub fn as_ptr(&self) -> *mut bindings::ndb_note {
     94         match self {
     95             Note::Owned { ptr, .. } => *ptr,
     96             Note::Transactional { ptr, .. } => *ptr,
     97         }
     98     }
     99 
    100     fn content_size(&self) -> usize {
    101         unsafe { bindings::ndb_note_content_length(self.as_ptr()) as usize }
    102     }
    103 
    104     pub fn created_at(&self) -> u64 {
    105         unsafe { bindings::ndb_note_created_at(self.as_ptr()).into() }
    106     }
    107 
    108     pub fn content_ptr(&self) -> *const ::std::os::raw::c_char {
    109         unsafe { bindings::ndb_note_content(self.as_ptr()) }
    110     }
    111 
    112     /// Get the [`Note`] contents.
    113     pub fn content(&self) -> &'a str {
    114         unsafe {
    115             let content = self.content_ptr();
    116             let byte_slice = std::slice::from_raw_parts(content as *const u8, self.content_size());
    117             std::str::from_utf8_unchecked(byte_slice)
    118         }
    119     }
    120 
    121     /// Get the note pubkey
    122     pub fn pubkey(&self) -> &'a [u8; 32] {
    123         unsafe {
    124             let ptr = bindings::ndb_note_pubkey(self.as_ptr());
    125             &*(ptr as *const [u8; 32])
    126         }
    127     }
    128 
    129     pub fn id(&self) -> &'a [u8; 32] {
    130         unsafe {
    131             let ptr = bindings::ndb_note_id(self.as_ptr());
    132             &*(ptr as *const [u8; 32])
    133         }
    134     }
    135 
    136     pub fn kind(&self) -> u32 {
    137         unsafe { bindings::ndb_note_kind(self.as_ptr()) }
    138     }
    139 
    140     pub fn tags(&'a self) -> Tags<'a> {
    141         let tags = unsafe { bindings::ndb_note_tags(self.as_ptr()) };
    142         Tags::new(tags, self)
    143     }
    144 
    145     pub fn sig(&self) -> &'a [u8; 32] {
    146         unsafe {
    147             let ptr = bindings::ndb_note_sig(self.as_ptr());
    148             &*(ptr as *const [u8; 32])
    149         }
    150     }
    151 }
    152 
    153 impl<'a> Drop for Note<'a> {
    154     fn drop(&mut self) {
    155         match self {
    156             Note::Owned { ptr, .. } => unsafe { libc::free((*ptr) as *mut libc::c_void) },
    157             _ => (),
    158         }
    159     }
    160 }
    161 
    162 #[cfg(test)]
    163 mod tests {
    164     use super::*;
    165 
    166     #[test]
    167     fn note_query_works() {
    168         use crate::config::Config;
    169         use crate::error::Error;
    170         use crate::ndb::Ndb;
    171         use crate::test_util;
    172 
    173         let db = "target/testdbs/note_query_works";
    174 
    175         // Initialize ndb
    176         {
    177             let cfg = Config::new();
    178             let ndb = Ndb::new(&db, &cfg).expect("db open");
    179             let mut txn = Transaction::new(&ndb).expect("new txn");
    180 
    181             let err = ndb
    182                 .get_note_by_id(&mut txn, &[0; 32])
    183                 .expect_err("not found");
    184             assert!(err == Error::NotFound);
    185         }
    186 
    187         test_util::cleanup_db(db);
    188     }
    189 }