use std::mem::MaybeUninit;
use crate::core::entries::UTabEntryDiff;
use crate::core::errors::UTabDiffIterError;
use crate::core::iter::Direction;
use crate::core::iter::GenIterator;
use crate::tables::UTabDiff;
#[derive(Debug)]
pub struct UTabDiffIter<'diff, 's, 'o> {
table_diff: &'diff UTabDiff<'s, 'o>,
fwd_iter: GenIterator,
bwd_iter: GenIterator,
first_fwd_cursor: *mut libmount::libmnt_fs,
second_fwd_cursor: *mut libmount::libmnt_fs,
first_bwd_cursor: *mut libmount::libmnt_fs,
second_bwd_cursor: *mut libmount::libmnt_fs,
have_iterators_met: bool,
}
impl<'diff, 's, 'o> UTabDiffIter<'diff, 's, 'o> {
#[doc(hidden)]
#[allow(dead_code)]
pub(crate) fn new(
table_diff: &'diff UTabDiff<'s, 'o>,
) -> Result<UTabDiffIter<'diff, 's, 'o>, UTabDiffIterError> {
let fwd_iter = GenIterator::new(Direction::Forward)?;
let bwd_iter = GenIterator::new(Direction::Backward)?;
let first_fwd_cursor = std::ptr::null_mut();
let second_fwd_cursor = std::ptr::null_mut();
let first_bwd_cursor = std::ptr::null_mut();
let second_bwd_cursor = std::ptr::null_mut();
let have_iterators_met = false;
let iterator = Self {
table_diff,
fwd_iter,
bwd_iter,
first_fwd_cursor,
second_fwd_cursor,
first_bwd_cursor,
second_bwd_cursor,
have_iterators_met,
};
Ok(iterator)
}
}
impl<'diff, 's, 'o> Iterator for UTabDiffIter<'diff, 's, 'o> {
type Item = UTabEntryDiff<'diff, 's, 'o>;
fn next(&mut self) -> Option<Self::Item> {
log::debug!("UTabDiffIter::next getting next table changes");
let mut source_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut other_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut flags = MaybeUninit::<libc::c_int>::zeroed();
let result = unsafe {
libmount::mnt_tabdiff_next_change(
self.table_diff.inner,
self.fwd_iter.inner,
source_entry_inner.as_mut_ptr(),
other_entry_inner.as_mut_ptr(),
flags.as_mut_ptr(),
)
};
match result {
0 => {
let source_entry_inner = unsafe { source_entry_inner.assume_init() };
let other_entry_inner = unsafe { other_entry_inner.assume_init() };
let flags = unsafe { flags.assume_init() };
if self.have_iterators_met
|| ((self.first_fwd_cursor != self.first_bwd_cursor)
&& (self.second_fwd_cursor != self.second_bwd_cursor)
&& (source_entry_inner == self.first_bwd_cursor
&& other_entry_inner == self.second_bwd_cursor))
{
log::debug!(
"UTabDiffIter::next forward and backward iterators have met in the middle"
);
self.have_iterators_met = true;
None
} else {
log::debug!("UTabDiffIter::next got next table changes");
self.first_fwd_cursor = source_entry_inner;
self.second_fwd_cursor = other_entry_inner;
let diff_entry = UTabEntryDiff::new(
self.table_diff,
source_entry_inner,
other_entry_inner,
flags,
);
Some(diff_entry)
}
}
1 => {
log::debug!("UTabDiffIter::next reached the end of `UTabDiffIter`");
None
}
code => {
let err_msg = "failed to get next changes".to_owned();
log::debug!( "UTabDiffIter::next {err_msg}. libmount::mnt_tabdiff_next_change returned error code: {code:?}");
None
}
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
log::debug!("UTabDiffIter::nth getting {n:?}th table diff item");
let mut result;
let mut flags = MaybeUninit::<libc::c_int>::zeroed();
for i in 0..n {
let mut source_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut other_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
result = unsafe {
libmount::mnt_tabdiff_next_change(
self.table_diff.inner,
self.fwd_iter.inner,
source_entry_inner.as_mut_ptr(),
other_entry_inner.as_mut_ptr(),
flags.as_mut_ptr(),
)
};
match result {
0 => {
let source_entry_inner = unsafe { source_entry_inner.assume_init() };
let other_entry_inner = unsafe { other_entry_inner.assume_init() };
if self.have_iterators_met
|| ((self.first_fwd_cursor != self.first_bwd_cursor)
&& (self.second_fwd_cursor != self.second_bwd_cursor)
&& (source_entry_inner == self.first_bwd_cursor
&& other_entry_inner == self.second_bwd_cursor))
{
log::debug!( "UTabDiffIter::next forward and backward iterators have met in the middle");
self.have_iterators_met = true;
return None;
} else {
log::debug!("UTabDiffIter::nth got {i:?}th table diff item");
self.first_fwd_cursor = source_entry_inner;
self.second_fwd_cursor = other_entry_inner;
}
}
1 => {
log::debug!("UTabDiffIter::nth reached the end of `UTabDiffIter`");
return None;
}
code => {
let err_msg = format!("failed to get {:?}th table diff item", n);
log::debug!( "UTabDiffIter::nth {err_msg}. libmount::mnt_tabdiff_next_change returned error code: {code:?}");
return None;
}
}
}
self.next()
}
}
impl<'diff, 's, 'o> DoubleEndedIterator for UTabDiffIter<'diff, 's, 'o> {
fn next_back(&mut self) -> Option<Self::Item> {
log::debug!("UTabDiffIter::next_back getting next table diff item from the back");
let mut source_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut other_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut flags = MaybeUninit::<libc::c_int>::zeroed();
let result = unsafe {
libmount::mnt_tabdiff_next_change(
self.table_diff.inner,
self.bwd_iter.inner,
source_entry_inner.as_mut_ptr(),
other_entry_inner.as_mut_ptr(),
flags.as_mut_ptr(),
)
};
match result {
0 => {
let source_entry_inner = unsafe { source_entry_inner.assume_init() };
let other_entry_inner = unsafe { other_entry_inner.assume_init() };
let flags = unsafe { flags.assume_init() };
if self.have_iterators_met
|| ((self.first_fwd_cursor != self.first_bwd_cursor)
&& (self.second_fwd_cursor != self.second_bwd_cursor)
&& (source_entry_inner == self.first_fwd_cursor
&& other_entry_inner == self.second_fwd_cursor))
{
log::debug!( "UTabDiffIter::next_back forward and backward iterators have met in the middle");
self.have_iterators_met = true;
None
} else {
log::debug!(
"UTabDiffIter::next_back got next table changes iterating backward"
);
self.first_bwd_cursor = source_entry_inner;
self.second_bwd_cursor = other_entry_inner;
let diff_entry = UTabEntryDiff::new(
self.table_diff,
source_entry_inner,
other_entry_inner,
flags,
);
Some(diff_entry)
}
}
1 => {
log::debug!("UTabDiffIter::next_back reached the end of `UTabDiffIter`");
None
}
code => {
let err_msg = "failed to get next changes iterating backward".to_owned();
log::debug!( "UTabDiffIter::next_back {err_msg}. libmount::mnt_tabdiff_next_change returned error code: {code:?}");
None
}
}
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
log::debug!("UTabDiffIter::nth_back getting {n:?}th table diff item from the back");
let mut result;
let mut flags = MaybeUninit::<libc::c_int>::zeroed();
for i in 0..n {
let mut source_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
let mut other_entry_inner = MaybeUninit::<*mut libmount::libmnt_fs>::zeroed();
result = unsafe {
libmount::mnt_tabdiff_next_change(
self.table_diff.inner,
self.bwd_iter.inner,
source_entry_inner.as_mut_ptr(),
other_entry_inner.as_mut_ptr(),
flags.as_mut_ptr(),
)
};
match result {
0 => {
let source_entry_inner = unsafe { source_entry_inner.assume_init() };
let other_entry_inner = unsafe { other_entry_inner.assume_init() };
if self.have_iterators_met
|| ((self.first_fwd_cursor != self.first_bwd_cursor)
&& (self.second_fwd_cursor != self.second_bwd_cursor)
&& (source_entry_inner == self.first_fwd_cursor
&& other_entry_inner == self.second_fwd_cursor))
{
log::debug!( "UTabDiffIter::nth_back forward and backward iterators have met in the middle");
self.have_iterators_met = true;
return None;
} else {
log::debug!("UTabDiffIter::nth got {i:?}th table diff item from the back");
self.first_bwd_cursor = source_entry_inner;
self.second_bwd_cursor = other_entry_inner;
}
}
1 => {
log::debug!("UTabDiffIter::nth_back reached the beginning of `UTabDiffIter`");
return None;
}
code => {
let err_msg = format!("failed to get {:?}th table diff item from the back", n);
log::debug!( "UTabDiffIter::nth_back {err_msg}. libmount::mnt_tabdiff_next_change returned error code: {code:?}");
return None;
}
}
}
self.next_back()
}
}