use super::*;
use std::path::PathBuf;
pub const DEFAULT_READ_MAX_BYTES: usize = 16 * 1024 * 1024;
pub const DEFAULT_READ_STREAM_CHUNK_BYTES: usize = 1024 * 1024;
pub const DEFAULT_READ_ALLV_MAX_TOTAL_BYTES: usize = DEFAULT_READ_MAX_BYTES;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StreamOptions {
chunk_size: usize,
}
impl StreamOptions {
pub const fn new() -> Self {
Self {
chunk_size: DEFAULT_READ_STREAM_CHUNK_BYTES,
}
}
pub const fn chunk_size(mut self, bytes: usize) -> Self {
self.chunk_size = bytes;
self
}
pub const fn chunk_size_bytes(self) -> usize {
self.chunk_size
}
}
impl Default for StreamOptions {
fn default() -> Self {
Self::new()
}
}
pub const DEFAULT_DIRECTORY_MAX_ENTRIES: usize = 100_000;
pub const DEFAULT_DIRECTORY_MAX_PATH_BYTES: usize = 16 * 1024 * 1024;
pub const DEFAULT_WALK_MAX_DEPTH: usize = 128;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ReadDirOptions {
max_entries: usize,
max_path_bytes: usize,
}
impl ReadDirOptions {
pub const fn new() -> Self {
Self {
max_entries: DEFAULT_DIRECTORY_MAX_ENTRIES,
max_path_bytes: DEFAULT_DIRECTORY_MAX_PATH_BYTES,
}
}
pub const fn unlimited() -> Self {
Self {
max_entries: usize::MAX,
max_path_bytes: usize::MAX,
}
}
pub const fn max_entries(mut self, entries: usize) -> Self {
self.max_entries = entries;
self
}
pub const fn max_path_bytes(mut self, bytes: usize) -> Self {
self.max_path_bytes = bytes;
self
}
pub const fn entry_limit(self) -> usize {
self.max_entries
}
pub const fn path_byte_limit(self) -> usize {
self.max_path_bytes
}
}
impl Default for ReadDirOptions {
fn default() -> Self {
Self::new()
}
}
#[bitfields::bitfield(u8)]
#[derive(PartialEq, Eq)]
struct WalkFlags {
truncate: bool,
#[bits(7)]
_reserved: u8,
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DepthLimit(std::num::NonZeroU8);
impl DepthLimit {
pub const fn new(depth: usize) -> Self {
let encoded = if depth <= 200 { (depth + 1) as u8 } else { 202 };
Self(std::num::NonZeroU8::new(encoded).expect("depth encoding is nonzero"))
}
pub const fn unlimited() -> Self {
Self::new(usize::MAX)
}
pub const fn get(self) -> usize {
if self.is_unlimited() {
usize::MAX
} else {
self.0.get() as usize - 1
}
}
pub const fn is_unlimited(self) -> bool {
self.0.get() == 202
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WalkOptions {
directory: ReadDirOptions,
max_depth: DepthLimit,
flags: WalkFlags,
}
impl WalkOptions {
pub const fn new() -> Self {
Self {
directory: ReadDirOptions::new(),
max_depth: DepthLimit::new(DEFAULT_WALK_MAX_DEPTH),
flags: WalkFlags::new(),
}
}
pub const fn unlimited() -> Self {
Self {
directory: ReadDirOptions::unlimited(),
max_depth: DepthLimit::unlimited(),
flags: WalkFlags::new(),
}
}
pub const fn max_entries(mut self, entries: usize) -> Self {
self.directory = self.directory.max_entries(entries);
self
}
pub const fn max_path_bytes(mut self, bytes: usize) -> Self {
self.directory = self.directory.max_path_bytes(bytes);
self
}
pub const fn max_depth(mut self, depth: usize) -> Self {
self.max_depth = DepthLimit::new(depth);
self
}
pub const fn truncate_at_max_depth(mut self, truncate: bool) -> Self {
self.flags.set_truncate(truncate);
self
}
pub const fn entry_limit(self) -> usize {
self.directory.entry_limit()
}
pub const fn path_byte_limit(self) -> usize {
self.directory.path_byte_limit()
}
pub const fn depth_limit(self) -> usize {
self.max_depth.get()
}
pub const fn truncates_at_depth_limit(self) -> bool {
self.flags.truncate()
}
}
impl Default for WalkOptions {
fn default() -> Self {
Self::new()
}
}
pub const DEFAULT_READV_MAX_TOTAL_BYTES: usize = DEFAULT_READ_MAX_BYTES;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FsReadResult {
pub offset: u64,
pub data: Vec<u8>,
pub eof: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReadIntoResult {
pub offset: u64,
pub read: usize,
pub eof: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WriteResult {
pub offset: u64,
pub written: usize,
pub stable: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StreamCompletion {
Complete,
Stopped { next_offset: u64 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TraversalCompletion {
Complete,
Stopped,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResourceLimits {
pub max_read_bytes: usize,
pub stream_chunk_bytes: usize,
pub max_directory_entries: usize,
pub max_directory_path_bytes: usize,
pub max_walk_depth: usize,
}
impl Default for ResourceLimits {
fn default() -> Self {
Self {
max_read_bytes: DEFAULT_READ_MAX_BYTES,
stream_chunk_bytes: crate::api::DEFAULT_READ_STREAM_CHUNK_BYTES,
max_directory_entries: crate::api::DEFAULT_DIRECTORY_MAX_ENTRIES,
max_directory_path_bytes: crate::api::DEFAULT_DIRECTORY_MAX_PATH_BYTES,
max_walk_depth: crate::api::DEFAULT_WALK_MAX_DEPTH,
}
}
}
impl ResourceLimits {
pub fn directory_options(self) -> ReadDirOptions {
ReadDirOptions::new()
.max_entries(self.max_directory_entries)
.max_path_bytes(self.max_directory_path_bytes)
}
pub fn walk_options(self) -> crate::api::WalkOptions {
crate::api::WalkOptions::new()
.max_entries(self.max_directory_entries)
.max_path_bytes(self.max_directory_path_bytes)
.max_depth(self.max_walk_depth)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DirectoryListing {
pub path: PathBuf,
pub entries: Vec<DirEntry>,
}