use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use crate::metadata::FileSystemCapability;
use crate::metadata::FileSystemCapabilitySupport;
const CAPABILITY_DEPENDENCIES: &[(FileSystemCapability, FileSystemCapability)] = &[
(FileSystemCapability::RangeRead, FileSystemCapability::Read),
(FileSystemCapability::ConditionalRead, FileSystemCapability::Read),
(FileSystemCapability::ChecksumValidation, FileSystemCapability::Read),
(FileSystemCapability::Append, FileSystemCapability::Write),
(FileSystemCapability::ConditionalWrite, FileSystemCapability::Write),
(FileSystemCapability::AtomicReplace, FileSystemCapability::Write),
(FileSystemCapability::DurableWrite, FileSystemCapability::Write),
(FileSystemCapability::RecursiveDelete, FileSystemCapability::Delete),
(FileSystemCapability::ConditionalDelete, FileSystemCapability::Delete),
(FileSystemCapability::AtomicRename, FileSystemCapability::Rename),
(FileSystemCapability::ServerSideCopy, FileSystemCapability::Copy),
(FileSystemCapability::AtomicFileCopy, FileSystemCapability::Copy),
(FileSystemCapability::AtomicTreeCopy, FileSystemCapability::Copy),
(FileSystemCapability::DurableFileCopy, FileSystemCapability::Copy),
(FileSystemCapability::DurableTreeCopy, FileSystemCapability::Copy),
(FileSystemCapability::DurableRename, FileSystemCapability::Rename),
];
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct FileSystemCapabilities {
conditional: u128,
guaranteed: u128,
}
impl FileSystemCapabilities {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self {
conditional: 0,
guaranteed: 0,
}
}
#[inline]
#[must_use]
pub const fn with_conditional(self, capability: FileSystemCapability) -> Self {
self.set_support(capability, FileSystemCapabilitySupport::Conditional)
}
#[inline]
#[must_use]
pub const fn with_guaranteed(self, capability: FileSystemCapability) -> Self {
self.set_support(capability, FileSystemCapabilitySupport::Guaranteed)
}
#[inline]
#[must_use]
pub const fn set_support(mut self, capability: FileSystemCapability, support: FileSystemCapabilitySupport) -> Self {
let bit = capability.bit();
self.conditional &= !bit;
self.guaranteed &= !bit;
match support {
FileSystemCapabilitySupport::Unsupported => {}
FileSystemCapabilitySupport::Conditional => {
self.conditional |= bit;
}
FileSystemCapabilitySupport::Guaranteed => {
self.guaranteed |= bit;
}
}
self
}
#[inline]
pub const fn support(&self, capability: FileSystemCapability) -> FileSystemCapabilitySupport {
let bit = capability.bit();
if self.guaranteed & bit != 0 {
FileSystemCapabilitySupport::Guaranteed
} else if self.conditional & bit != 0 {
FileSystemCapabilitySupport::Conditional
} else {
FileSystemCapabilitySupport::Unsupported
}
}
#[inline]
#[must_use]
pub const fn supports(&self, capability: FileSystemCapability) -> bool {
!matches!(self.support(capability), FileSystemCapabilitySupport::Unsupported)
}
#[inline]
#[must_use]
pub const fn guarantees(&self, capability: FileSystemCapability) -> bool {
matches!(self.support(capability), FileSystemCapabilitySupport::Guaranteed)
}
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
(self.conditional | self.guaranteed).count_ones() as usize
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.conditional == 0 && self.guaranteed == 0
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = FileSystemCapability> + '_ {
FileSystemCapability::ALL
.iter()
.copied()
.filter(|capability| self.supports(*capability))
}
#[inline]
pub fn iter_with_support(&self) -> impl Iterator<Item = (FileSystemCapability, FileSystemCapabilitySupport)> + '_ {
self.iter().map(|capability| (capability, self.support(capability)))
}
#[inline]
#[must_use]
pub fn missing_dependency(&self) -> Option<(FileSystemCapability, FileSystemCapability)> {
CAPABILITY_DEPENDENCIES
.iter()
.copied()
.find(|(capability, dependency)| {
let capability_support = self.support(*capability);
let dependency_support = self.support(*dependency);
matches!(capability_support, FileSystemCapabilitySupport::Conditional)
&& matches!(dependency_support, FileSystemCapabilitySupport::Unsupported)
|| matches!(capability_support, FileSystemCapabilitySupport::Guaranteed)
&& !matches!(dependency_support, FileSystemCapabilitySupport::Guaranteed)
})
}
}
impl Default for FileSystemCapabilities {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Debug for FileSystemCapabilities {
#[inline]
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
formatter.debug_map().entries(self.iter_with_support()).finish()
}
}