#[cfg(feature = "native")]
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use async_trait::async_trait;
#[derive(Debug, thiserror::Error)]
pub enum TrashError {
#[error("{0}")]
Backend(String),
#[error("task join failed: {0}")]
Join(String),
}
pub struct TrashId(pub(crate) TrashIdInner);
pub(crate) enum TrashIdInner {
#[cfg(feature = "native")]
System(OsString),
#[cfg(not(feature = "native"))]
_Unavailable,
}
impl TrashId {
#[cfg(feature = "native")]
pub(crate) fn system(id: OsString) -> Self {
Self(TrashIdInner::System(id))
}
}
impl std::fmt::Debug for TrashId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.0 {
#[cfg(feature = "native")]
TrashIdInner::System(_) => f.write_str("TrashId::System(..)"),
#[cfg(not(feature = "native"))]
TrashIdInner::_Unavailable => f.write_str("TrashId::Unavailable"),
}
}
}
#[derive(Debug)]
pub struct TrashEntry {
pub id: TrashId,
pub name: String,
pub original_path: PathBuf,
pub deleted_at: i64,
}
pub fn find_restore_match<T>(items: Vec<(String, T)>, target: &str) -> Result<Vec<T>, String> {
let mut exact = Vec::new();
let mut substring = Vec::new();
let mut substring_names = Vec::new();
for (name, item) in items {
if name == target {
exact.push(item);
} else if name.contains(target) {
substring_names.push(name);
substring.push(item);
}
}
if exact.len() == 1 {
return Ok(exact);
}
let mut all_names: Vec<String> = Vec::new();
if !exact.is_empty() {
all_names.extend(std::iter::repeat_n(target.to_string(), exact.len()));
}
all_names.extend(substring_names);
let mut all: Vec<T> = exact;
all.extend(substring);
if all.is_empty() {
return Err(format!("'{}' not found in trash", target));
}
if all.len() > 1 {
return Err(format!(
"multiple matches for '{}': {}. Be more specific.",
target,
all_names.join(", ")
));
}
Ok(all)
}
#[async_trait]
pub trait TrashBackend: Send + Sync {
async fn trash(&self, path: &Path) -> Result<(), TrashError>;
async fn list(&self, filter: Option<&str>) -> Result<Vec<TrashEntry>, TrashError>;
async fn find_by_name(&self, name: &str) -> Result<Vec<TrashEntry>, TrashError>;
async fn restore(&self, entries: Vec<TrashEntry>) -> Result<(), TrashError>;
async fn purge_all(&self) -> Result<usize, TrashError>;
}