use std::mem::MaybeUninit;
use crate::core::errors::UTabDiffError;
use crate::core::errors::UTabDiffIterError;
use crate::core::iter::UTabDiffIter;
use crate::tables::GcItem;
use crate::tables::UTab;
#[derive(Debug)]
pub struct UTabDiff<'source, 'other> {
pub(crate) inner: *mut libmount::libmnt_tabdiff,
pub(crate) source: &'source UTab,
pub(crate) other: &'other UTab,
pub(crate) gc: Vec<GcItem>,
}
impl<'source, 'other> UTabDiff<'source, 'other> {
pub fn new(
source: &'source UTab,
other: &'other UTab,
) -> Result<UTabDiff<'source, 'other>, UTabDiffError> {
log::debug!("TableDiff::new creating a new `TableDiff` instance");
let mut inner = MaybeUninit::<*mut libmount::libmnt_tabdiff>::zeroed();
unsafe { inner.write(libmount::mnt_new_tabdiff()) };
match unsafe { inner.assume_init() } {
inner if inner.is_null() => {
let err_msg = "failed to create a new `UTabDiff` instance".to_owned();
log::debug!(
"UTabDiff::new {err_msg}. libmount::mnt_new_tabdiff returned a NULL pointer"
);
Err(UTabDiffError::Creation(err_msg))
}
inner => {
log::debug!("UTabDiff::new created a new `UTabDiff` instance");
let table_diff = Self {
inner,
source,
other,
gc: vec![],
};
Ok(table_diff)
}
}
}
pub fn diff(&self) -> Result<usize, UTabDiffError> {
log::debug!("UTabDiff::diff comparing tables, entry by entry");
let result =
unsafe { libmount::mnt_diff_tables(self.inner, self.source.inner, self.other.inner) };
match result {
code if code < 0 => {
let err_msg = "failed to compare tables, entry by entry".to_owned();
log::debug!(
"UTabDiff::diff {err_msg}. libmount::mnt_diff_tables returned error code: {code:?}"
);
Err(UTabDiffError::Diff(err_msg))
}
nb_changes => {
log::debug!(
"UTabDiff::diff compared tables. Found {:?} changes",
nb_changes
);
Ok(nb_changes as usize)
}
}
}
pub fn iter(&self) -> UTabDiffIter<'_, '_, '_> {
log::debug!("UTabDiff::iter creating a new `UTabDiffIter` instance");
UTabDiffIter::new(self).unwrap()
}
pub fn try_iter(&self) -> Result<UTabDiffIter<'_, '_, '_>, UTabDiffIterError> {
log::debug!("UTabDiff::try_iter creating a new `UTabDiffIter` instance");
UTabDiffIter::new(self)
}
}
impl<'source, 'other> AsRef<UTabDiff<'source, 'other>> for UTabDiff<'source, 'other> {
#[inline]
fn as_ref(&self) -> &UTabDiff<'source, 'other> {
self
}
}
impl<'source, 'other> Drop for UTabDiff<'source, 'other> {
fn drop(&mut self) {
log::debug!("UTabDiff::drop deallocating `UTabDiff` instance");
unsafe { libmount::mnt_free_tabdiff(self.inner) };
while let Some(gc_item) = self.gc.pop() {
gc_item.destroy();
}
}
}