use std::cmp::Ordering;
use std::collections::HashMap;
use std::ffi::c_void;
use std::fs::File;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
use std::panic::catch_unwind;
use std::path::{Path, PathBuf};
use std::process::abort;
use std::sync::{Arc, LazyLock, RwLock};
use std::time::Duration;
#[cfg(windows)]
use std::{
ffi::OsStr,
os::windows::io::{AsRawHandle as _, RawHandle},
};
use std::{fmt, io};
use heed_traits::{Comparator, LexicographicComparator};
use synchronoise::event::SignalEvent;
use crate::mdb::ffi;
#[allow(unused)] use crate::{Database, DatabaseFlags};
#[cfg(master3)]
mod encrypted_env;
mod env;
mod env_open_options;
#[cfg(master3)]
pub use encrypted_env::EncryptedEnv;
pub use env::Env;
pub(crate) use env::EnvInner;
pub use env_open_options::EnvOpenOptions;
static OPENED_ENV: LazyLock<RwLock<HashMap<PathBuf, Arc<SignalEvent>>>> =
LazyLock::new(RwLock::default);
pub fn env_closing_event<P: AsRef<Path>>(path: P) -> Option<EnvClosingEvent> {
let lock = OPENED_ENV.read().unwrap();
lock.get(path.as_ref()).map(|signal_event| EnvClosingEvent(signal_event.clone()))
}
#[derive(Debug, Clone, Copy)]
pub struct EnvInfo {
pub map_addr: *mut c_void,
pub map_size: usize,
pub last_page_number: usize,
pub last_txn_id: usize,
pub maximum_number_of_readers: u32,
pub number_of_readers: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct EnvStat {
pub page_size: u32,
pub depth: u32,
pub branch_pages: usize,
pub leaf_pages: usize,
pub overflow_pages: usize,
pub entries: usize,
}
#[derive(Clone)]
pub struct EnvClosingEvent(Arc<SignalEvent>);
impl EnvClosingEvent {
pub fn wait(&self) {
self.0.wait()
}
pub fn wait_timeout(&self, timeout: Duration) -> bool {
self.0.wait_timeout(timeout)
}
}
impl fmt::Debug for EnvClosingEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("EnvClosingEvent").finish()
}
}
#[cfg(not(windows))]
fn canonicalize_path(path: &Path) -> io::Result<PathBuf> {
path.canonicalize()
}
#[cfg(windows)]
fn canonicalize_path(path: &Path) -> io::Result<PathBuf> {
let canonical = path.canonicalize()?;
let url = url::Url::from_file_path(&canonical)
.map_err(|_e| io::Error::new(io::ErrorKind::Other, "URL passing error"))?;
url.to_file_path()
.map_err(|_e| io::Error::new(io::ErrorKind::Other, "path canonicalization error"))
}
#[cfg(windows)]
trait OsStrExtLmdb {
fn as_bytes(&self) -> &[u8];
}
#[cfg(windows)]
impl OsStrExtLmdb for OsStr {
fn as_bytes(&self) -> &[u8] {
&self.to_str().unwrap().as_bytes()
}
}
#[cfg(unix)]
fn get_file_fd(file: &File) -> RawFd {
file.as_raw_fd()
}
#[cfg(windows)]
fn get_file_fd(file: &File) -> RawHandle {
file.as_raw_handle()
}
unsafe extern "C" fn custom_key_cmp_wrapper<C: Comparator>(
a: *const ffi::MDB_val,
b: *const ffi::MDB_val,
) -> i32 {
let a = unsafe { ffi::from_val(*a) };
let b = unsafe { ffi::from_val(*b) };
match catch_unwind(|| C::compare(a, b)) {
Ok(Ordering::Less) => -1,
Ok(Ordering::Equal) => 0,
Ok(Ordering::Greater) => 1,
Err(_) => abort(),
}
}
#[derive(Debug)]
pub enum DefaultComparator {}
impl LexicographicComparator for DefaultComparator {
#[inline]
fn compare_elem(a: u8, b: u8) -> Ordering {
a.cmp(&b)
}
#[inline]
fn successor(elem: u8) -> Option<u8> {
match elem {
u8::MAX => None,
elem => Some(elem + 1),
}
}
#[inline]
fn predecessor(elem: u8) -> Option<u8> {
match elem {
u8::MIN => None,
elem => Some(elem - 1),
}
}
#[inline]
fn max_elem() -> u8 {
u8::MAX
}
#[inline]
fn min_elem() -> u8 {
u8::MIN
}
}
#[derive(Debug)]
pub enum IntegerComparator {}
impl Comparator for IntegerComparator {
fn compare(a: &[u8], b: &[u8]) -> Ordering {
#[cfg(target_endian = "big")]
return a.cmp(b);
#[cfg(target_endian = "little")]
{
let len = a.len();
for i in (0..len).rev() {
match a[i].cmp(&b[i]) {
Ordering::Equal => continue,
other => return other,
}
}
Ordering::Equal
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum CompactionOption {
Enabled,
Disabled,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum FlagSetMode {
Enable,
Disable,
}
impl FlagSetMode {
fn as_mdb_env_set_flags_input(self) -> i32 {
match self {
Self::Enable => 1,
Self::Disable => 0,
}
}
}