orderwal 0.5.1

A generic-purpose, atomic, ordered, zero-copy read, zero-cost (in-place) write, Write-Ahead Log implementation for Rust.
Documentation
use core::cmp;
#[cfg(feature = "std")]
use std::thread::spawn;

use std::{
  string::{String, ToString},
  vec,
  vec::Vec,
};

use base::{AlternativeTable, OrderWal, OrderWalReader};
use dbutils::{
  equivalent::{Comparable, Equivalent},
  leb128::{decode_u64_varint, encode_u64_varint, encoded_u64_varint_len},
  types::{KeyRef, Type, TypeRef},
};

use super::*;

const MB: u32 = 1024 * 1024;

macro_rules! expand_unit_tests {
  ($prefix:literal: $wal:ty [$memtable_opts:expr]: $table:ty { $($name:ident $({ $($tt:tt)* })?), +$(,)? }) => {
    $(
      paste::paste! {
        #[test]
        fn [< test_ $prefix _ $name _inmemory >]() {
          $name(&mut $crate::Builder::<$table>::new()
            .with_capacity(MB)
            .with_memtable_options($memtable_opts)
            .alloc::<$wal>()
            .unwrap()
          );
        }

        #[test]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        fn [< test_ $prefix _ $name _map_anon >]() {
          $name(&mut $crate::Builder::<$table>::new()
            .with_capacity(MB)
            .with_memtable_options($memtable_opts)
            .map_anon::<$wal>().unwrap()
          );
        }

        #[test]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        #[cfg_attr(miri, ignore)]
        fn [< test_ $prefix _ $name _map_file >]() {
          let dir = ::tempfile::tempdir().unwrap();
          $name(
            &mut unsafe {
              $crate::Builder::<$table>::new()
                .with_create_new(true)
                .with_read(true)
                .with_write(true)
                .with_capacity(MB as u32)
                .with_memtable_options($memtable_opts)
                .map_mut::<$wal, _>(
                  dir.path().join(concat!("test_", $prefix, "_", stringify!($name), "_map_file")
                ),
            )
            .unwrap() },
          );
        }
      }
    )*
  };
  (move $prefix:literal: $wal:ty [$memtable_opts:expr]: $table:ty { $($name:ident $($block:expr)?), +$(,)? }) => {
    $(
      paste::paste! {
        #[test]
        fn [< test_ $prefix _ $name _inmemory >]() {
          $name($crate::Builder::<$table>::new().with_memtable_options($memtable_opts).with_capacity(MB).alloc::<$wal>().unwrap());
        }

        #[test]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        fn [< test_ $prefix _ $name _map_anon >]() {
          $name($crate::Builder::<$table>::new().with_memtable_options($memtable_opts).with_capacity(MB).map_anon::<$wal>().unwrap());
        }

        #[test]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        #[cfg_attr(miri, ignore)]
        fn [< test_ $prefix _ $name _map_file >]() {
          let dir = ::tempfile::tempdir().unwrap();
          let p = dir.path().join(concat!("test_", $prefix, "_", stringify!($name), "_map_file"));
          let wal = unsafe {
            $crate::Builder::<$table>::new()
              .with_memtable_options($memtable_opts)
              .with_create_new(true)
                .with_read(true)
                .with_write(true)
                .with_capacity(MB as u32)
                .map_mut::<$wal, _>(
              &p,
            )
            .unwrap()
          };

          let res = $name(wal);

          $(
            {
              let f = |p, res| { $block(p, res) };
              f(p, res);
            }
          )?
        }
      }
    )*
  };
  ($prefix:literal: $wal:ty [$memtable_opts:expr]: $table:ty { $($name:ident($builder:expr) $({ $($tt:tt)* })?), +$(,)? }) => {
    $(
      paste::paste! {
        #[test]
        fn [< test_ $prefix _ $name _inmemory >]() {
          $name(&mut $builder.alloc::<$wal>().unwrap());
        }

        #[test]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        fn [< test_ $prefix _ $name _map_anon >]() {
          $name(&mut $builder
            .map_anon::<$wal>().unwrap()
          );
        }

        #[test]
        #[cfg_attr(miri, ignore)]
        #[cfg(all(feature = "memmap", not(target_family = "wasm")))]
        fn [< test_ $prefix _ $name _map_file >]() {
          let dir = ::tempfile::tempdir().unwrap();
          $name(
            &mut unsafe {
              $builder
                .with_create_new(true)
                .with_read(true)
                .with_write(true)
                .with_capacity(MB as u32)
                .map_mut::<$wal, _>(
                  dir.path().join(concat!("test_", $prefix, "_", stringify!($name), "_map_file")
                ),
            )
            .unwrap() },
          );
        }
      }
    )*
  };
}

type OrderWalAlternativeTable<K, V> = OrderWal<K, V, AlternativeTable<K, V>>;
type OrderWalReaderAlternativeTable<K, V> = OrderWalReader<K, V, AlternativeTable<K, V>>;

type MultipleVersionOrderWalAlternativeTable<K, V> =
  multiple_version::OrderWal<K, V, multiple_version::AlternativeTable<K, V>>;
type MultipleVersionOrderWalReaderAlternativeTable<K, V> =
  multiple_version::OrderWalReader<K, V, multiple_version::AlternativeTable<K, V>>;

#[doc(hidden)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Person {
  #[doc(hidden)]
  pub id: u64,
  #[doc(hidden)]
  pub name: String,
}

impl Person {
  #[doc(hidden)]
  #[cfg(test)]
  pub fn random() -> Self {
    Self {
      id: rand::random(),
      name: names::Generator::default().next().unwrap(),
    }
  }

  #[doc(hidden)]
  pub fn as_ref(&self) -> PersonRef<'_> {
    PersonRef {
      id: self.id,
      name: &self.name,
    }
  }

  #[doc(hidden)]
  #[cfg(test)]
  #[allow(dead_code)]
  fn to_vec(&self) -> Vec<u8> {
    let mut buf = vec![0; self.encoded_len()];
    self.encode(&mut buf).unwrap();
    buf
  }
}

#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub struct PersonRef<'a> {
  id: u64,
  name: &'a str,
}

impl PartialEq for PersonRef<'_> {
  fn eq(&self, other: &Self) -> bool {
    self.id == other.id && self.name == other.name
  }
}

impl Eq for PersonRef<'_> {}

impl PartialOrd for PersonRef<'_> {
  fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
    Some(self.cmp(other))
  }
}

impl Ord for PersonRef<'_> {
  fn cmp(&self, other: &Self) -> cmp::Ordering {
    self
      .id
      .cmp(&other.id)
      .then_with(|| self.name.cmp(other.name))
  }
}

impl Equivalent<Person> for PersonRef<'_> {
  fn equivalent(&self, key: &Person) -> bool {
    self.id == key.id && self.name == key.name
  }
}

impl Comparable<Person> for PersonRef<'_> {
  fn compare(&self, key: &Person) -> core::cmp::Ordering {
    self.id.cmp(&key.id).then_with(|| self.name.cmp(&key.name))
  }
}

impl Equivalent<PersonRef<'_>> for Person {
  fn equivalent(&self, key: &PersonRef<'_>) -> bool {
    self.id == key.id && self.name == key.name
  }
}

impl Comparable<PersonRef<'_>> for Person {
  fn compare(&self, key: &PersonRef<'_>) -> core::cmp::Ordering {
    self
      .id
      .cmp(&key.id)
      .then_with(|| self.name.as_str().cmp(key.name))
  }
}

impl KeyRef<'_, Person> for PersonRef<'_> {
  fn compare<Q>(&self, a: &Q) -> cmp::Ordering
  where
    Q: ?Sized + Comparable<Self>,
  {
    Comparable::compare(a, self).reverse()
  }

  unsafe fn compare_binary(this: &[u8], other: &[u8]) -> cmp::Ordering {
    let (this_id_size, this_id) = decode_u64_varint(this).unwrap();
    let (other_id_size, other_id) = decode_u64_varint(other).unwrap();
    PersonRef {
      id: this_id,
      name: std::str::from_utf8(&this[this_id_size..]).unwrap(),
    }
    .cmp(&PersonRef {
      id: other_id,
      name: std::str::from_utf8(&other[other_id_size..]).unwrap(),
    })
  }
}

impl Type for Person {
  type Ref<'a> = PersonRef<'a>;
  type Error = dbutils::error::InsufficientBuffer;

  fn encoded_len(&self) -> usize {
    encoded_u64_varint_len(self.id) + self.name.len()
  }

  fn encode(&self, buf: &mut [u8]) -> Result<usize, Self::Error> {
    let id_size = encode_u64_varint(self.id, buf)?;
    buf[id_size..].copy_from_slice(self.name.as_bytes());
    Ok(id_size + self.name.len())
  }

  #[inline]
  fn encode_to_buffer(
    &self,
    buf: &mut dbutils::buffer::VacantBuffer<'_>,
  ) -> Result<usize, Self::Error> {
    let id_size = buf.put_u64_varint(self.id)?;
    buf.put_slice_unchecked(self.name.as_bytes());
    Ok(id_size + self.name.len())
  }
}

impl<'a> TypeRef<'a> for PersonRef<'a> {
  unsafe fn from_slice(src: &'a [u8]) -> Self {
    let (id_size, id) = decode_u64_varint(src).unwrap();
    let name = std::str::from_utf8(&src[id_size..]).unwrap();
    PersonRef { id, name }
  }
}

impl PersonRef<'_> {
  #[cfg(test)]
  #[allow(dead_code)]
  fn encode_into_vec(&self) -> Result<Vec<u8>, dbutils::error::InsufficientBuffer> {
    let mut buf = vec![0; encoded_u64_varint_len(self.id) + self.name.len()];
    let id_size = encode_u64_varint(self.id, &mut buf)?;
    buf[id_size..].copy_from_slice(self.name.as_bytes());
    Ok(buf)
  }
}

#[cfg(all(test, any(test_swmr_constructor, all_orderwal_tests)))]
mod constructor;

#[cfg(all(test, any(test_swmr_insert, all_orderwal_tests)))]
mod insert;

#[cfg(all(test, any(test_swmr_iters, all_orderwal_tests)))]
mod iters;

#[cfg(all(test, any(test_swmr_get, all_orderwal_tests)))]
mod get;

#[cfg(all(test, any(test_swmr_multiple_version_constructor, all_orderwal_tests)))]
mod multiple_version_constructor;

#[cfg(all(test, any(test_swmr_multiple_version_get, all_orderwal_tests)))]
mod multiple_version_get;

#[cfg(all(test, any(test_swmr_multiple_version_insert, all_orderwal_tests)))]
mod multiple_version_insert;

#[cfg(all(test, any(test_swmr_multiple_version_iters, all_orderwal_tests)))]
mod multiple_version_iters;