pub struct DirectoryEntryIterator<'a>
{
directory_file_descriptor: &'a DirectoryFileDescriptor,
buffer_offset: usize,
buffer_end: usize,
last_item: Option<NonNull<dirent>>,
buffer: [u8; BufferCapacity],
}
const BufferCapacity: usize = 2048;
impl<'a> StreamingIterator for DirectoryEntryIterator<'a>
{
type Item = DirectoryEntry<'a>;
#[inline(always)]
fn advance(&mut self)
{
if unlikely!(self.has_finished())
{
return
}
if unlikely!(self.buffer_offset >= self.buffer_end)
{
let result = unsafe { getdents(self.directory_file_descriptor.as_raw_fd(), self.buffer.as_mut_ptr() as *mut u8 as *mut dirent, BufferCapacity) };
if likely!(result > 0)
{
self.buffer_offset = 0;
self.buffer_end =
{
let length = result as usize;
debug_assert!(length <= BufferCapacity);
length
};
}
else if likely!(result == 0)
{
return self.finished()
}
else if likely!(result < 0)
{
let error_number = -result;
match error_number
{
ENOENT => return self.finished(),
EBADF => panic!("Invalid file descriptor fd"),
EFAULT => panic!("Argument points outside the calling process's address space"),
EINVAL => panic!("Result bufferfer is too small"),
ENOTDIR => panic!("File descriptor does not refer to a directory"),
_ => panic!("Unexpected error {} from from getdents()", error_number)
}
}
}
let current = unsafe { new_non_null(self.buffer.as_mut_ptr().add(self.buffer_offset) as *mut dirent) };
self.buffer_offset += unsafe { current.as_ref().d_reclen as usize };
self.last_item = Some(current);
}
#[inline(always)]
fn get(&self) -> Option<&Self::Item>
{
self.last_item.map(|dirent| unsafe { & * dirent.cast::<DirectoryEntry>().as_ptr() })
}
}
impl<'a> DirectoryEntryIterator<'a>
{
#[inline(always)]
pub fn rewind(&mut self) -> io::Result<()>
{
self.seek(0)
}
#[inline(always)]
pub fn rewind_to(&mut self, directory_entry_rewind_position: DirectoryEntryRewindPosition<'a>) -> io::Result<()>
{
self.seek(directory_entry_rewind_position.0)
}
#[inline(always)]
fn new(directory_file_descriptor: &'a DirectoryFileDescriptor) -> Self
{
Self
{
directory_file_descriptor,
buffer_offset: 0,
buffer_end: 0,
last_item: None,
buffer: unsafe_zeroed(),
}
}
#[inline(always)]
fn seek(&mut self, offset: off_t) -> io::Result<()>
{
let result = unsafe { lseek(self.directory_file_descriptor.as_raw_fd(), offset, SEEK_SET) };
if likely!(result == offset)
{
self.buffer_offset = 0;
self.buffer_end = 0;
self.last_item = None;
Ok(())
}
else if likely!(result == -1)
{
self.finished();
Err(io::Error::last_os_error())
}
else
{
unreachable_code(format_args!("Invalid result {} from lseek()", result))
}
}
#[inline(always)]
fn finished(&mut self)
{
self.buffer_end = BufferCapacity + 1;
self.last_item = None;
}
#[inline(always)]
fn has_finished(&self) -> bool
{
self.buffer_end == BufferCapacity + 1
}
}