use std::{fmt::Debug, ops::Range, path::PathBuf};
use widestring::U16CStr;
use windows::Win32::Storage::CloudFilters::{
self, CF_CALLBACK_CANCEL_FLAGS, CF_CALLBACK_DEHYDRATION_REASON, CF_CALLBACK_PARAMETERS_0_0,
CF_CALLBACK_PARAMETERS_0_1, CF_CALLBACK_PARAMETERS_0_10, CF_CALLBACK_PARAMETERS_0_11,
CF_CALLBACK_PARAMETERS_0_2, CF_CALLBACK_PARAMETERS_0_3, CF_CALLBACK_PARAMETERS_0_4,
CF_CALLBACK_PARAMETERS_0_5, CF_CALLBACK_PARAMETERS_0_6, CF_CALLBACK_PARAMETERS_0_7,
CF_CALLBACK_PARAMETERS_0_8, CF_CALLBACK_PARAMETERS_0_9,
};
#[derive(Debug, Clone, Copy)]
pub struct FetchData(pub(crate) CF_CALLBACK_PARAMETERS_0_1);
impl FetchData {
pub fn interrupted_hydration(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_FETCH_DATA_FLAG_RECOVERY).0 != 0
}
pub fn explicit_hydration(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_FETCH_DATA_FLAG_EXPLICIT_HYDRATION).0 != 0
}
pub fn required_file_range(&self) -> Range<u64> {
let offset = self.0.RequiredFileOffset as u64;
let length = self.0.RequiredLength as u64;
offset..(offset + length)
}
pub fn optional_file_range(&self) -> Range<u64> {
let offset = self.0.OptionalFileOffset as u64;
let length = self.0.OptionalLength as u64;
offset..(offset + length)
}
pub fn last_dehydration_time(&self) -> u64 {
self.0.LastDehydrationTime as u64
}
pub fn last_dehydration_reason(&self) -> Option<DehydrationReason> {
DehydrationReason::from_win32(self.0.LastDehydrationReason)
}
}
#[derive(Clone, Copy)]
pub struct CancelFetchData(pub(crate) CF_CALLBACK_PARAMETERS_0_0);
impl CancelFetchData {
pub fn timeout(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_CANCEL_FLAG_IO_TIMEOUT).0 != 0
}
pub fn user_cancelled(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_CANCEL_FLAG_IO_ABORTED).0 != 0
}
pub fn file_range(&self) -> Range<u64> {
let range = unsafe { self.0.Anonymous.FetchData };
let offset = range.FileOffset as u64;
let length = range.Length as u64;
offset..(offset + length)
}
}
impl Debug for CancelFetchData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("CancelFetchData")
.field(unsafe {
&CancelFetchDataDebug {
Flags: self.0.Flags,
FileOffset: self.0.Anonymous.FetchData.FileOffset,
Length: self.0.Anonymous.FetchData.Length,
}
})
.finish()
}
}
#[allow(dead_code, non_snake_case)]
#[derive(Debug)]
struct CancelFetchDataDebug {
Flags: CF_CALLBACK_CANCEL_FLAGS,
FileOffset: i64,
Length: i64,
}
#[derive(Debug, Clone, Copy)]
pub struct ValidateData(pub(crate) CF_CALLBACK_PARAMETERS_0_2);
impl ValidateData {
pub fn explicit_hydration(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_VALIDATE_DATA_FLAG_EXPLICIT_HYDRATION).0 != 0
}
pub fn file_range(&self) -> Range<u64> {
let offset = self.0.RequiredFileOffset as u64;
let length = self.0.RequiredLength as u64;
offset..(offset + length)
}
}
#[derive(Debug)]
pub struct FetchPlaceholders(pub(crate) CF_CALLBACK_PARAMETERS_0_3);
impl FetchPlaceholders {
#[cfg(feature = "globs")]
pub fn pattern(&self) -> Result<globset::Glob, globset::Error> {
let pattern = unsafe { U16CStr::from_ptr_str(self.0.Pattern.0) }.to_string_lossy();
globset::Glob::new(&pattern)
}
#[cfg(not(feature = "globs"))]
pub fn pattern(&self) -> &U16CStr {
unsafe { U16CStr::from_ptr_str(self.0.Pattern.0) }
}
}
#[derive(Clone, Copy)]
pub struct CancelFetchPlaceholders(pub(crate) CF_CALLBACK_PARAMETERS_0_0);
impl CancelFetchPlaceholders {
pub fn timeout(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_CANCEL_FLAG_IO_TIMEOUT).0 != 0
}
pub fn user_cancelled(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_CANCEL_FLAG_IO_ABORTED).0 != 0
}
}
impl Debug for CancelFetchPlaceholders {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("CancelFetchPlaceholders")
.field(&CancelFetchPlaceholdersDebug {
Flags: self.0.Flags,
})
.finish()
}
}
#[allow(dead_code, non_snake_case)]
#[derive(Debug)]
struct CancelFetchPlaceholdersDebug {
Flags: CF_CALLBACK_CANCEL_FLAGS,
}
#[derive(Debug, Clone, Copy)]
pub struct Opened(pub(crate) CF_CALLBACK_PARAMETERS_0_4);
impl Opened {
pub fn metadata_corrupt(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_OPEN_COMPLETION_FLAG_PLACEHOLDER_UNKNOWN).0 != 0
}
pub fn metadata_unsupported(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_OPEN_COMPLETION_FLAG_PLACEHOLDER_UNSUPPORTED).0
!= 0
}
}
#[derive(Debug, Clone, Copy)]
pub struct Closed(pub(crate) CF_CALLBACK_PARAMETERS_0_5);
impl Closed {
pub fn deleted(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_CLOSE_COMPLETION_FLAG_DELETED).0 != 0
}
}
#[derive(Debug, Clone, Copy)]
pub struct Dehydrate(pub(crate) CF_CALLBACK_PARAMETERS_0_6);
impl Dehydrate {
pub fn background(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_DEHYDRATE_FLAG_BACKGROUND).0 != 0
}
pub fn reason(&self) -> Option<DehydrationReason> {
DehydrationReason::from_win32(self.0.Reason)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Dehydrated(pub(crate) CF_CALLBACK_PARAMETERS_0_7);
impl Dehydrated {
pub fn background(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_DEHYDRATE_COMPLETION_FLAG_BACKGROUND).0 != 0
}
pub fn already_hydrated(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_DEHYDRATE_COMPLETION_FLAG_DEHYDRATED).0 != 0
}
pub fn reason(&self) -> Option<DehydrationReason> {
DehydrationReason::from_win32(self.0.Reason)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Delete(pub(crate) CF_CALLBACK_PARAMETERS_0_8);
impl Delete {
pub fn is_directory(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_DELETE_FLAG_IS_DIRECTORY).0 != 0
}
pub fn is_undelete(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_DELETE_FLAG_IS_UNDELETE).0 != 0
}
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct Deleted(pub(crate) CF_CALLBACK_PARAMETERS_0_9);
#[derive(Debug)]
pub struct Rename(pub(crate) CF_CALLBACK_PARAMETERS_0_10);
impl Rename {
pub fn is_directory(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_RENAME_FLAG_IS_DIRECTORY).0 != 0
}
pub fn source_in_scope(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_RENAME_FLAG_SOURCE_IN_SCOPE).0 != 0
}
pub fn target_in_scope(&self) -> bool {
(self.0.Flags & CloudFilters::CF_CALLBACK_RENAME_FLAG_TARGET_IN_SCOPE).0 != 0
}
pub fn target_path(&self) -> PathBuf {
unsafe {
U16CStr::from_ptr_str(self.0.TargetPath.0)
.to_os_string()
.into()
}
}
}
#[derive(Debug)]
pub struct Renamed(pub(crate) CF_CALLBACK_PARAMETERS_0_11);
impl Renamed {
pub fn source_path(&self) -> PathBuf {
unsafe {
U16CStr::from_ptr_str(self.0.SourcePath.0)
.to_os_string()
.into()
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DehydrationReason {
UserManually,
LowSpace,
Inactive,
OsUpgrade,
}
impl DehydrationReason {
fn from_win32(reason: CF_CALLBACK_DEHYDRATION_REASON) -> Option<DehydrationReason> {
match reason {
CloudFilters::CF_CALLBACK_DEHYDRATION_REASON_USER_MANUAL => Some(Self::UserManually),
CloudFilters::CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_LOW_SPACE => Some(Self::LowSpace),
CloudFilters::CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_INACTIVITY => Some(Self::Inactive),
CloudFilters::CF_CALLBACK_DEHYDRATION_REASON_SYSTEM_OS_UPGRADE => Some(Self::OsUpgrade),
_ => None,
}
}
}