use std::{
ffi::{CStr, CString},
ptr::NonNull,
sync::{Arc, Mutex},
};
use crate::notmuch::{ffi, DbPointer, NotmuchError, NotmuchLibrary};
pub struct NotmuchDirectory {
pub lib: Arc<NotmuchLibrary>,
pub path: CString,
pub db: Arc<Mutex<DbPointer>>,
pub inner: NonNull<ffi::notmuch_directory_t>,
}
impl std::fmt::Debug for NotmuchDirectory {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("NotmuchDirectory")
.field("path", &self.path)
.finish_non_exhaustive()
}
}
impl Drop for NotmuchDirectory {
fn drop(&mut self) {
unsafe { call!(self.lib, ffi::notmuch_directory_destroy)(self.inner.as_mut()) };
}
}
impl NotmuchDirectory {
#[inline]
pub fn child_files_paths(&mut self) -> NotmuchFilenames {
NotmuchFilenames {
path: Some(self.path.clone()),
inner: NonNull::new(unsafe {
call!(self.lib, ffi::notmuch_directory_get_child_files)(self.inner.as_mut())
})
.unwrap(),
lib: self.lib.clone(),
db: self.db.clone(),
}
}
#[inline]
pub fn child_files_filenames(&mut self) -> NotmuchFilenames {
NotmuchFilenames {
path: None,
inner: NonNull::new(unsafe {
call!(self.lib, ffi::notmuch_directory_get_child_files)(self.inner.as_mut())
})
.unwrap(),
lib: self.lib.clone(),
db: self.db.clone(),
}
}
#[inline]
pub fn child_directories_paths(&mut self) -> NotmuchFilenames {
NotmuchFilenames {
path: Some(self.path.clone()),
inner: NonNull::new(unsafe {
call!(self.lib, ffi::notmuch_directory_get_child_directories)(self.inner.as_mut())
})
.unwrap(),
lib: self.lib.clone(),
db: self.db.clone(),
}
}
#[inline]
pub fn child_directories_filenames(&mut self) -> NotmuchFilenames {
NotmuchFilenames {
path: None,
inner: NonNull::new(unsafe {
call!(self.lib, ffi::notmuch_directory_get_child_directories)(self.inner.as_mut())
})
.unwrap(),
lib: self.lib.clone(),
db: self.db.clone(),
}
}
pub fn child_directories(&mut self) -> NotmuchDirectories {
NotmuchDirectories {
filenames: self.child_directories_filenames(),
path: self.path.clone(),
lib: self.lib.clone(),
db: self.db.clone(),
}
}
pub fn mtime(&mut self) -> libc::time_t {
unsafe { call!(self.lib, ffi::notmuch_directory_get_mtime)(self.inner.as_mut()) }
}
pub fn set_mtime(&mut self, value: libc::time_t) -> Result<(), NotmuchError> {
unsafe {
try_call!(
self.lib,
call!(self.lib, ffi::notmuch_directory_set_mtime)(self.inner.as_mut(), value)
)
}
}
}
pub struct NotmuchFilenames {
pub path: Option<CString>,
pub lib: Arc<NotmuchLibrary>,
pub db: Arc<Mutex<DbPointer>>,
pub inner: NonNull<ffi::notmuch_filenames_t>,
}
impl std::fmt::Debug for NotmuchFilenames {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("NotmuchFilenames")
.field("path", &self.path)
.finish_non_exhaustive()
}
}
impl Drop for NotmuchFilenames {
fn drop(&mut self) {
unsafe { call!(self.lib, ffi::notmuch_filenames_destroy)(self.inner.as_mut()) };
}
}
impl Iterator for NotmuchFilenames {
type Item = CString;
fn next(&mut self) -> Option<Self::Item> {
if unsafe { call!(self.lib, ffi::notmuch_filenames_valid)(self.inner.as_mut()) } == 0 {
return None;
}
let next_ptr = unsafe { call!(self.lib, ffi::notmuch_filenames_get)(self.inner.as_mut()) };
if next_ptr.is_null() {
return None;
}
let next_basename = unsafe { CStr::from_ptr(next_ptr) };
let ret = if let Some(path) = self.path.as_ref() {
let mut path = path.clone().into_bytes();
path.extend_from_slice(std::path::MAIN_SEPARATOR_STR.as_bytes());
path.extend_from_slice(next_basename.to_bytes());
unsafe { CString::from_vec_unchecked(path) }
} else {
next_basename.into()
};
unsafe { call!(self.lib, ffi::notmuch_filenames_move_to_next)(self.inner.as_mut()) };
Some(ret)
}
}
pub struct NotmuchDirectories {
pub filenames: NotmuchFilenames,
pub lib: Arc<NotmuchLibrary>,
pub path: CString,
pub db: Arc<Mutex<DbPointer>>,
}
impl std::fmt::Debug for NotmuchDirectories {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("NotmuchDirectories")
.field("path", &self.path)
.finish_non_exhaustive()
}
}
impl Iterator for NotmuchDirectories {
type Item = NotmuchDirectory;
fn next(&mut self) -> Option<Self::Item> {
let next_basename = self.filenames.next()?;
let mut path = self.path.clone().into_bytes();
path.extend_from_slice(std::path::MAIN_SEPARATOR_STR.as_bytes());
path.extend_from_slice(next_basename.as_bytes());
let path: CString = unsafe { CString::from_vec_unchecked(path) };
let mut directory_ptr = std::ptr::null_mut();
if unsafe {
call!(self.lib, ffi::notmuch_database_get_directory)(
self.db.lock().unwrap().as_mut(),
path.as_ptr(),
&raw mut directory_ptr,
)
} != ffi::NOTMUCH_STATUS_SUCCESS
{
return self.next();
}
Some(NotmuchDirectory {
path,
lib: self.lib.clone(),
db: self.db.clone(),
inner: NonNull::new(directory_ptr)?,
})
}
}