use notify_types::event::EventKindMask;
use std::{
path::{Path, PathBuf},
time::Duration,
};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum RecursiveMode {
Recursive,
NonRecursive,
}
impl RecursiveMode {
pub(crate) fn is_recursive(&self) -> bool {
match *self {
RecursiveMode::Recursive => true,
RecursiveMode::NonRecursive => false,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
pub enum WindowsPathSeparatorStyle {
#[default]
Auto,
Slash,
Backslash,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Config {
poll_interval: Option<Duration>,
compare_contents: bool,
follow_symlinks: bool,
event_kinds: EventKindMask,
windows_path_separator_style: WindowsPathSeparatorStyle,
}
impl Config {
#[must_use]
pub fn with_poll_interval(mut self, dur: Duration) -> Self {
self.poll_interval = Some(dur);
self
}
#[must_use]
pub fn poll_interval(&self) -> Option<Duration> {
self.poll_interval
}
#[must_use]
pub fn with_manual_polling(mut self) -> Self {
self.poll_interval = None;
self
}
#[must_use]
pub fn with_compare_contents(mut self, compare_contents: bool) -> Self {
self.compare_contents = compare_contents;
self
}
#[must_use]
pub fn compare_contents(&self) -> bool {
self.compare_contents
}
#[must_use]
pub fn with_follow_symlinks(mut self, follow_symlinks: bool) -> Self {
self.follow_symlinks = follow_symlinks;
self
}
#[must_use]
pub fn follow_symlinks(&self) -> bool {
self.follow_symlinks
}
#[must_use]
pub fn with_event_kinds(mut self, event_kinds: EventKindMask) -> Self {
self.event_kinds = event_kinds;
self
}
#[must_use]
pub fn event_kinds(&self) -> EventKindMask {
self.event_kinds
}
#[must_use]
pub fn with_windows_path_separator_style(mut self, style: WindowsPathSeparatorStyle) -> Self {
self.windows_path_separator_style = style;
self
}
#[must_use]
pub fn windows_path_separator_style(&self) -> WindowsPathSeparatorStyle {
self.windows_path_separator_style
}
}
impl Default for Config {
fn default() -> Self {
Self {
poll_interval: Some(Duration::from_secs(30)),
compare_contents: false,
follow_symlinks: true,
event_kinds: EventKindMask::ALL,
windows_path_separator_style: WindowsPathSeparatorStyle::Auto,
}
}
}
#[derive(Debug)]
pub struct WatchPathConfig {
recursive_mode: RecursiveMode,
}
impl WatchPathConfig {
#[must_use]
pub fn new(recursive_mode: RecursiveMode) -> Self {
Self { recursive_mode }
}
#[must_use]
pub fn with_recursive_mode(mut self, recursive_mode: RecursiveMode) -> Self {
self.recursive_mode = recursive_mode;
self
}
#[must_use]
pub fn recursive_mode(&self) -> RecursiveMode {
self.recursive_mode
}
}
#[derive(Debug)]
pub enum PathOp {
Watch(PathBuf, WatchPathConfig),
Unwatch(PathBuf),
}
impl PathOp {
#[must_use]
pub fn watch_recursive<P: Into<PathBuf>>(path: P) -> Self {
Self::Watch(path.into(), WatchPathConfig::new(RecursiveMode::Recursive))
}
#[must_use]
pub fn watch_non_recursive<P: Into<PathBuf>>(path: P) -> Self {
Self::Watch(
path.into(),
WatchPathConfig::new(RecursiveMode::NonRecursive),
)
}
#[must_use]
pub fn unwatch<P: Into<PathBuf>>(path: P) -> Self {
Self::Unwatch(path.into())
}
#[must_use]
pub fn as_path(&self) -> &Path {
match self {
PathOp::Watch(p, _) => p,
PathOp::Unwatch(p) => p,
}
}
#[must_use]
pub fn into_path(self) -> PathBuf {
match self {
PathOp::Watch(p, _) => p,
PathOp::Unwatch(p) => p,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use notify_types::event::EventKindMask;
#[test]
fn config_default_event_kinds_is_all() {
let config = Config::default();
assert_eq!(config.event_kinds(), EventKindMask::ALL);
}
#[test]
fn config_with_event_kinds() {
let mask = EventKindMask::CREATE | EventKindMask::REMOVE;
let config = Config::default().with_event_kinds(mask);
assert_eq!(config.event_kinds(), mask);
}
#[test]
fn config_with_all_events_includes_access() {
let config = Config::default().with_event_kinds(EventKindMask::ALL);
assert!(config.event_kinds().intersects(EventKindMask::ALL_ACCESS));
}
#[test]
fn config_with_empty_mask() {
let config = Config::default().with_event_kinds(EventKindMask::empty());
assert!(config.event_kinds().is_empty());
}
#[test]
fn event_kind_mask_default_matches_config_default() {
assert_eq!(EventKindMask::default(), Config::default().event_kinds());
assert_eq!(EventKindMask::default(), EventKindMask::ALL);
}
#[test]
fn config_default_windows_separator_style_is_auto() {
let config = Config::default();
assert_eq!(
config.windows_path_separator_style(),
WindowsPathSeparatorStyle::Auto
);
}
#[test]
fn config_with_windows_separator_style() {
let config =
Config::default().with_windows_path_separator_style(WindowsPathSeparatorStyle::Slash);
assert_eq!(
config.windows_path_separator_style(),
WindowsPathSeparatorStyle::Slash
);
}
}