diff --git a/src/freedesktop.rs b/src/freedesktop.rs index 9db12fa..625c8e4 100644 --- a/src/freedesktop.rs +++ b/src/freedesktop.rs @@ -197,6 +197,32 @@ pub fn list() -> Result, Error> { Ok(result) } +pub fn is_empty() -> Result { + let trash_folders = trash_folders()?; + + if trash_folders.is_empty() { + return Ok(true); + } + + for folder in trash_folders { + // We're only concerned if the trash contains any files + // Therefore, we only need to check if the bin itself is empty + let bin = folder.join("files"); + match bin.read_dir() { + Ok(mut entries) => { + if let Some(Ok(_)) = entries.next() { + return Ok(false); + } + } + Err(e) => { + warn!("The trash files folder {:?} could not be read. Error was {:?}", bin, e); + } + } + } + + Ok(true) +} + pub fn trash_folders() -> Result, Error> { let EvaluatedTrashFolders { trash_folders, home_error, .. } = eval_trash_folders()?; diff --git a/src/lib.rs b/src/lib.rs index cf624cc..0fd60b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -374,6 +374,24 @@ pub mod os_limited { platform::list() } + /// Returns whether the trash is empty or has at least one item. + /// + /// Unlike calling [`list`], this function short circuits without evaluating every item. + /// + /// # Example + /// + /// ``` + /// use trash::os_limited::is_empty; + /// if is_empty().unwrap_or(true) { + /// println!("Trash is empty"); + /// } else { + /// println!("Trash contains at least one item"); + /// } + /// ``` + pub fn is_empty() -> Result { + platform::is_empty() + } + /// Returns all valid trash bins on supported Unix platforms. /// /// Valid trash folders include the user's personal "home trash" as well as designated trash diff --git a/src/tests.rs b/src/tests.rs index 72e72ea..993bad1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -287,4 +287,14 @@ mod os_limited { _ => panic!("restore_all was expected to return `trash::ErrorKind::RestoreTwins` but did not."), } } + + #[test] + #[serial] + fn is_empty_matches_list() { + init_logging(); + + let is_empty_list = trash::os_limited::list().unwrap().is_empty(); + let is_empty = trash::os_limited::is_empty().unwrap(); + assert_eq!(is_empty, is_empty_list, "is_empty() should match empty status from list()"); + } } diff --git a/src/windows.rs b/src/windows.rs index 52aebaf..8727706 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -126,6 +126,21 @@ pub fn list() -> Result, Error> { } } +pub fn is_empty() -> Result { + ensure_com_initialized(); + unsafe { + let recycle_bin: IShellItem = + SHGetKnownFolderItem(&FOLDERID_RecycleBinFolder, KF_FLAG_DEFAULT, HANDLE::default())?; + let pesi: IEnumShellItems = recycle_bin.BindToHandler(None, &BHID_EnumItems)?; + + let mut count = 0u32; + let mut items = [None]; + pesi.Next(&mut items, Some(&mut count as *mut u32))?; + + Ok(count == 0) + } +} + pub fn metadata(item: &TrashItem) -> Result { ensure_com_initialized(); let id_as_wide = to_wide_path(&item.id);