use std::path::Path;
use wtf_string::{Wtf16Str, Wtf16String};
use crate::entry::FileIdentityMode;
use crate::error::{RequestError, RequestFailure};
use crate::path;
use crate::predicate::EntryPredicate;
pub const DEFAULT_BUFFER_CAPACITY: usize = 64 * 1024;
pub const MINIMUM_BUFFER_CAPACITY: usize = 1024;
pub(crate) const RECORD_ALIGNMENT: usize = 8;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EnumerationRequest {
path: Wtf16String,
predicate: EntryPredicate,
file_identity_mode: FileIdentityMode,
buffer_capacity: usize,
}
impl EnumerationRequest {
pub fn new(path: &Wtf16Str) -> Result<Self, RequestError> {
Ok(Self {
path: path::prepare(path)?,
predicate: EntryPredicate::default(),
file_identity_mode: FileIdentityMode::default(),
buffer_capacity: DEFAULT_BUFFER_CAPACITY,
})
}
pub fn for_path(path: &Path) -> Result<Self, RequestError> {
Self::new(&Wtf16String::from_os_str(path.as_os_str()))
}
#[must_use]
pub fn with_predicate(mut self, predicate: impl Into<EntryPredicate>) -> Self {
self.predicate = predicate.into();
self
}
#[must_use]
pub fn with_file_identity(mut self, mode: FileIdentityMode) -> Self {
self.file_identity_mode = mode;
self
}
pub fn with_buffer_capacity(mut self, bytes: usize) -> Result<Self, RequestError> {
self.buffer_capacity = effective_buffer_capacity(bytes)?;
Ok(self)
}
#[must_use]
pub fn path(&self) -> &Wtf16Str {
&self.path
}
#[must_use]
pub fn predicate(&self) -> &EntryPredicate {
&self.predicate
}
#[must_use]
pub fn file_identity_mode(&self) -> FileIdentityMode {
self.file_identity_mode
}
#[must_use]
pub fn buffer_capacity(&self) -> usize {
self.buffer_capacity
}
}
fn effective_buffer_capacity(bytes: usize) -> Result<usize, RequestError> {
let clamped = bytes.max(MINIMUM_BUFFER_CAPACITY);
let aligned = clamped
.checked_next_multiple_of(RECORD_ALIGNMENT)
.ok_or_else(|| RequestError::new(RequestFailure::BufferCapacityUnrepresentable))?;
u32::try_from(aligned)
.map_err(|_| RequestError::new(RequestFailure::BufferCapacityUnrepresentable))?;
Ok(aligned)
}
#[cfg(test)]
mod tests;