bbolt-rs 1.3.10

A Rust port of the Bolt database
Documentation
use crate::common::page::CoerciblePage;
use crate::common::self_owned::SelfOwned;
use crate::tx::check::{TxCheck, UnsealRwTx, UnsealTx};
use crate::{
  Bolt, BoltOptions, BucketApi, BucketRwApi, CursorApi, DbApi, Error, TxApi, TxRwApi, TxRwRefApi,
};
use aligners::{alignment, AlignedBytes};
use fake::faker::lorem::en::Sentence;
use fake::locales::EN;
use fake::Faker;
use fake::{Dummy, Fake};
use itertools::Itertools;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use tempfile::{Builder, NamedTempFile};

pub(crate) fn mapped_page<T: CoerciblePage + Sized>(
  bytes: usize,
) -> SelfOwned<AlignedBytes<alignment::Page>, T> {
  SelfOwned::new_with_map(
    AlignedBytes::<alignment::Page>::new_zeroed(bytes),
    |aligned_bytes| T::own(aligned_bytes.as_mut_ptr()),
  )
}

pub(crate) fn temp_file() -> crate::Result<NamedTempFile> {
  let temp_file = Builder::new()
    .prefix("bbolt-rs-")
    .suffix(".db")
    .tempfile()?;

  Ok(temp_file)
}

pub(crate) struct TestDb {
  pub(crate) tmp_file: Option<NamedTempFile>,
  pub(crate) db: Option<Bolt>,
  options: BoltOptions,
}

impl Deref for TestDb {
  type Target = Bolt;

  fn deref(&self) -> &Self::Target {
    self.db.as_ref().unwrap()
  }
}

impl DerefMut for TestDb {
  fn deref_mut(&mut self) -> &mut Self::Target {
    self.db.as_mut().unwrap()
  }
}

impl TestDb {
  pub(crate) fn new() -> crate::Result<TestDb> {
    Self::with_options(BoltOptions::default())
  }

  pub(crate) fn with_options(options: BoltOptions) -> crate::Result<TestDb> {
    if cfg!(any(miri, feature = "test-mem-backend")) {
      Self::new_mem(options)
    } else {
      Self::new_tmp(options)
    }
  }

  pub(crate) fn new_tmp(options: BoltOptions) -> crate::Result<TestDb> {
    let tmp_file = temp_file()?;
    let db = options.clone().open(tmp_file.path())?;

    Ok(TestDb {
      tmp_file: Some(tmp_file),
      db: Some(db),
      options,
    })
  }

  pub(crate) fn new_mem(options: BoltOptions) -> crate::Result<TestDb> {
    let db = options.clone().open_mem()?;
    Ok(TestDb {
      tmp_file: None,
      db: Some(db),
      options,
    })
  }

  pub(crate) fn must_check(&mut self) {
    if let Some(Ok(tx)) = self.db.as_ref().map(|db| db.begin()) {
      let errors = tx.check();
      if !errors.is_empty() {
        for error in errors {
          eprintln!("{}", error);
        }
        panic!()
      }
    }
  }

  #[cfg(not(any(miri, feature = "test-mem-backend")))]
  pub(crate) fn must_close(&mut self) {
    let db = self.db.take().unwrap();
    db.close();
  }

  #[cfg(not(any(miri, feature = "test-mem-backend")))]
  pub(crate) fn reopen(&mut self) -> crate::Result<()> {
    assert!(
      self.tmp_file.is_some(),
      "Reopen only supported on file based databases"
    );
    assert!(self.db.is_none(), "Please call close before must_reopen");
    let options = self.options.clone();
    match options.open(self.tmp_file.as_ref().unwrap().path()) {
      Ok(db) => self.db = Some(db),
      Err(err) => return Err(err),
    }
    Ok(())
  }

  #[cfg(not(any(miri, feature = "test-mem-backend")))]
  pub(crate) fn must_reopen(&mut self) {
    self.reopen().expect("Unable to reopen db")
  }

  pub(crate) fn clone_db(&self) -> Bolt {
    self.db.as_ref().unwrap().clone()
  }

  pub(crate) fn begin_unseal(&self) -> crate::Result<impl TxApi + UnsealTx> {
    self.db.as_ref().unwrap().begin_tx()
  }

  pub(crate) fn begin_rw_unseal(&mut self) -> crate::Result<impl TxRwRefApi + UnsealRwTx> {
    self.db.as_mut().unwrap().begin_rw_tx()
  }
}

impl Drop for TestDb {
  fn drop(&mut self) {
    self.must_check()
  }
}

#[derive(Debug, Dummy)]
pub struct DummyEntry {
  #[dummy(faker = "(Faker, 1..1024)")]
  pub key: Vec<u8>,
  #[dummy(faker = "(Faker, 1..1024)")]
  pub value: Vec<u8>,
}

#[derive(Debug, Dummy)]
pub struct DummyVec {
  #[dummy(faker = "(Faker, 1..1000)")]
  pub values: Vec<DummyEntry>,
}

pub(crate) fn quick_check<D, F>(count: u64, mut f: F)
where
  D: Dummy<Faker> + Debug,
  F: FnMut(&mut D) -> bool,
{
  for i in 0..count {
    let mut d = Faker.fake();
    let r = f(&mut d);
    if !r {
      panic!("Iteration {} failed. {:?}", i + 1, d);
    }
  }
}