mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
feat: support VFS for join(), starts_with(), and ends_with() of Url (#3094)
This commit is contained in:
parent
0054cf0b87
commit
c27ef58116
36 changed files with 699 additions and 449 deletions
|
|
@ -38,3 +38,6 @@ windows-sys = { version = "0.60.2", features = [ "Win32_Storage_FileSystem" ] }
|
|||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation-sys = { workspace = true }
|
||||
objc = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
trash = "5.2.3"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{ffi::OsStr, fs::{FileType, Metadata}, hash::{BuildHasher, Hash, Hasher}, ops::Deref};
|
||||
use std::{ffi::OsStr, fs::{FileType, Metadata}, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_shared::url::{Uri, UrlBuf, UrlCow, Urn, UrnBuf};
|
||||
|
|
@ -9,7 +9,7 @@ use crate::{cha::Cha, provider};
|
|||
pub struct File {
|
||||
pub url: UrlBuf,
|
||||
pub cha: Cha,
|
||||
pub link_to: Option<UrlBuf>,
|
||||
pub link_to: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Deref for File {
|
||||
|
|
|
|||
|
|
@ -31,59 +31,6 @@ pub fn ok_or_not_found<T: Default>(result: io::Result<T>) -> io::Result<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn paths_to_same_file(a: impl AsRef<Path>, b: impl AsRef<Path>) -> bool {
|
||||
_paths_to_same_file(a.as_ref(), b.as_ref()).await.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn _paths_to_same_file(a: &Path, b: &Path) -> io::Result<bool> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
let (a_, b_) = (fs::symlink_metadata(a).await?, fs::symlink_metadata(b).await?);
|
||||
Ok(
|
||||
a_.ino() == b_.ino()
|
||||
&& a_.dev() == b_.dev()
|
||||
&& fs::canonicalize(a).await? == fs::canonicalize(b).await?,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn _paths_to_same_file(a: &Path, b: &Path) -> std::io::Result<bool> {
|
||||
use std::os::windows::{ffi::OsStringExt, io::AsRawHandle};
|
||||
|
||||
use windows_sys::Win32::{Foundation::{HANDLE, MAX_PATH}, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, GetFinalPathNameByHandleW, VOLUME_NAME_DOS}};
|
||||
|
||||
async fn final_name(p: &Path) -> std::io::Result<PathBuf> {
|
||||
let file = fs::OpenOptions::new()
|
||||
.access_mode(0)
|
||||
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
|
||||
.open(p)
|
||||
.await?;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut buf = [0u16; MAX_PATH as usize];
|
||||
let len = unsafe {
|
||||
GetFinalPathNameByHandleW(
|
||||
file.as_raw_handle() as HANDLE,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as u32,
|
||||
VOLUME_NAME_DOS,
|
||||
)
|
||||
};
|
||||
|
||||
if len == 0 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(PathBuf::from(OsString::from_wide(&buf[0..len as usize])))
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
Ok(final_name(a).await? == final_name(b).await?)
|
||||
}
|
||||
|
||||
pub async fn realname(u: &UrlBuf) -> Option<OsString> {
|
||||
let name = u.file_name()?;
|
||||
if *u == provider::canonicalize(u).await.ok()? {
|
||||
|
|
@ -170,7 +117,7 @@ pub fn copy_with_progress(
|
|||
tokio::spawn({
|
||||
let (from, to) = (from.clone(), to.clone());
|
||||
async move {
|
||||
tick_tx.send(_copy_with_progress(from, to, cha).await).ok();
|
||||
tick_tx.send(provider::copy(&from, &to, cha).await).ok();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -213,54 +160,6 @@ pub fn copy_with_progress(
|
|||
rx
|
||||
}
|
||||
|
||||
async fn _copy_with_progress(from: UrlBuf, to: UrlBuf, cha: Cha) -> io::Result<u64> {
|
||||
let mut ft = std::fs::FileTimes::new();
|
||||
cha.atime.map(|t| ft = ft.set_accessed(t));
|
||||
cha.mtime.map(|t| ft = ft.set_modified(t));
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use std::os::macos::fs::FileTimesExt;
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::FileTimesExt;
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
{
|
||||
use std::os::{fd::AsRawFd, unix::fs::OpenOptionsExt};
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut reader = std::fs::File::open(from)?;
|
||||
let mut writer = std::fs::OpenOptions::new()
|
||||
.mode(cha.mode as u32) // Do not remove `as u32`, https://github.com/termux/termux-packages/pull/22481
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(to)?;
|
||||
|
||||
let written = std::io::copy(&mut reader, &mut writer)?;
|
||||
unsafe { libc::fchmod(writer.as_raw_fd(), cha.mode) };
|
||||
writer.set_times(ft).ok();
|
||||
|
||||
Ok(written)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
{
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let written = std::fs::copy(from, &to)?;
|
||||
std::fs::File::options().write(true).open(to).and_then(|f| f.set_times(ft)).ok();
|
||||
Ok(written)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove_dir_clean(dir: &UrlBuf) {
|
||||
let Ok(mut it) = provider::read_dir(dir).await else { return };
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(clean expand path);
|
||||
yazi_macro::mod_flat!(clean expand path relative);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{borrow::Cow, ffi::{OsStr, OsString}, future::Future, io, path::PathBuf};
|
||||
use std::{borrow::Cow, ffi::{OsStr, OsString}, future::Future, io};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use yazi_shared::{loc::LocBuf, url::{UrlBuf, UrlCow}};
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use crate::provider;
|
||||
|
||||
|
|
@ -63,50 +62,6 @@ async fn _unique_name(mut url: UrlBuf, append: bool) -> io::Result<UrlBuf> {
|
|||
Ok(url)
|
||||
}
|
||||
|
||||
pub fn url_relative_to<'a>(
|
||||
from: impl Into<UrlCow<'a>>,
|
||||
to: impl Into<UrlCow<'a>>,
|
||||
) -> Result<UrlCow<'a>> {
|
||||
url_relative_to_impl(from.into(), to.into())
|
||||
}
|
||||
|
||||
pub fn url_relative_to_impl<'a>(from: UrlCow<'a>, to: UrlCow<'a>) -> Result<UrlCow<'a>> {
|
||||
use yazi_shared::url::Component::*;
|
||||
|
||||
if from.is_absolute() != to.is_absolute() {
|
||||
return if to.is_absolute() {
|
||||
Ok(to)
|
||||
} else {
|
||||
bail!("Urls must be both absolute or both relative: {from:?} and {to:?}");
|
||||
};
|
||||
}
|
||||
|
||||
if from.covariant(&to) {
|
||||
return Ok(UrlBuf { loc: LocBuf::zeroed("."), scheme: to.scheme().clone() }.into());
|
||||
}
|
||||
|
||||
let (mut f_it, mut t_it) = (from.components(), to.components());
|
||||
let (f_head, t_head) = loop {
|
||||
match (f_it.next(), t_it.next()) {
|
||||
(Some(Scheme(a)), Some(Scheme(b))) if a.covariant(b) => {}
|
||||
(Some(RootDir), Some(RootDir)) => {}
|
||||
(Some(Prefix(a)), Some(Prefix(b))) if a == b => {}
|
||||
(Some(Scheme(_) | Prefix(_) | RootDir), _) | (_, Some(Scheme(_) | Prefix(_) | RootDir)) => {
|
||||
return Ok(to);
|
||||
}
|
||||
(None, None) => break (None, None),
|
||||
(a, b) if a != b => break (a, b),
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
|
||||
let dots = f_head.into_iter().chain(f_it).map(|_| ParentDir);
|
||||
let rest = t_head.into_iter().chain(t_it);
|
||||
|
||||
let buf: PathBuf = dots.chain(rest).collect();
|
||||
Ok(UrlBuf { loc: LocBuf::zeroed(buf), scheme: to.scheme().clone() }.into())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn backslash_to_slash(p: &std::path::Path) -> Cow<'_, std::path::Path> {
|
||||
let bytes = p.as_os_str().as_encoded_bytes();
|
||||
|
|
@ -125,63 +80,61 @@ pub fn backslash_to_slash(p: &std::path::Path) -> Cow<'_, std::path::Path> {
|
|||
for &b in rest {
|
||||
out.push(if b == b'\\' { b'/' } else { b });
|
||||
}
|
||||
Cow::Owned(PathBuf::from(unsafe { OsString::from_encoded_bytes_unchecked(out) }))
|
||||
Cow::Owned(std::path::PathBuf::from(unsafe { OsString::from_encoded_bytes_unchecked(out) }))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::url_relative_to;
|
||||
use yazi_shared::url::UrlCow;
|
||||
|
||||
use crate::path::url_relative_to;
|
||||
|
||||
#[test]
|
||||
fn test_path_relative_to() {
|
||||
fn test_url_relative_to() {
|
||||
yazi_shared::init_tests();
|
||||
|
||||
fn assert(from: &str, to: &str, ret: &str) {
|
||||
assert_eq!(
|
||||
url_relative_to(&from.parse().unwrap(), &to.parse().unwrap()).unwrap(),
|
||||
ret.parse().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let cases = [
|
||||
// Same urls
|
||||
assert("", "", ".");
|
||||
assert(".", ".", ".");
|
||||
assert("/a", "/a", ".");
|
||||
assert("regular:///", "/", ".");
|
||||
assert("regular://", "regular://", ".");
|
||||
assert("regular://", "search://kw/", "search://kw/.");
|
||||
assert("regular:///b", "search://kw//b", "search://kw/.");
|
||||
|
||||
("", "", "."),
|
||||
(".", ".", "."),
|
||||
("/a", "/a", "."),
|
||||
("regular:///", "/", "."),
|
||||
("regular://", "regular://", "."),
|
||||
("regular://", "search://kw/", "search://kw/."),
|
||||
("regular:///b", "search://kw//b", "search://kw/."),
|
||||
// Relative urls
|
||||
assert("foo", "bar", "../bar");
|
||||
|
||||
("foo", "bar", "../bar"),
|
||||
// Absolute urls
|
||||
assert("/a/b/c", "/a/b", "../");
|
||||
assert("/a/b", "/a/b/c", "c");
|
||||
assert("/a/b/d", "/a/b/c", "../c");
|
||||
assert("/a/b/c", "/a", "../../");
|
||||
assert("/a/b/b", "/a/a/b", "../../a/b");
|
||||
|
||||
assert("regular:///a/b", "regular:///a/b/c", "c");
|
||||
assert("/a/b/c/", "search://kw//a/d/", "search://kw/../../d");
|
||||
assert("search://kw//a/b/c", "search://kw//a/b", "search://kw/../");
|
||||
|
||||
("/a/b/c", "/a/b", ".."),
|
||||
("/a/b", "/a/b/c", "c"),
|
||||
("/a/b/d", "/a/b/c", "../c"),
|
||||
("/a/b/c", "/a", "../.."),
|
||||
("/a/b/b", "/a/a/b", "../../a/b"),
|
||||
("regular:///a/b", "regular:///a/b/c", "c"),
|
||||
("/a/b/c/", "search://kw//a/d/", "search://kw/../../d"),
|
||||
("search://kw//a/b/c", "search://kw//a/b", "search://kw/.."),
|
||||
// Different schemes
|
||||
assert("", "sftp://test/", "sftp://test/");
|
||||
assert("a", "sftp://test/", "sftp://test/");
|
||||
assert("a", "sftp://test/b", "sftp://test/b");
|
||||
assert("/a", "sftp://test//b", "sftp://test//b");
|
||||
assert("sftp://test//a/b", "sftp://test//a/d", "sftp://test/../d");
|
||||
}
|
||||
("", "sftp://test/", "sftp://test/"),
|
||||
("a", "sftp://test/", "sftp://test/"),
|
||||
("a", "sftp://test/b", "sftp://test/b"),
|
||||
("/a", "sftp://test//b", "sftp://test//b"),
|
||||
("sftp://test//a/b", "sftp://test//a/d", "sftp://test:0:0/../d"),
|
||||
];
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
assert(r"C:\a\b\c", r"C:\a\b", r"..\");
|
||||
assert(r"C:\a\b", r"C:\a\b\c", "c");
|
||||
assert(r"C:\a\b\d", r"C:\a\b\c", r"..\c");
|
||||
assert(r"C:\a\b\c", r"C:\a", r"..\..\");
|
||||
assert(r"C:\a\b\b", r"C:\a\a\b", r"..\..\a\b");
|
||||
let cases = [
|
||||
(r"C:\a\b\c", r"C:\a\b", r".."),
|
||||
(r"C:\a\b", r"C:\a\b\c", "c"),
|
||||
(r"C:\a\b\d", r"C:\a\b\c", r"..\c"),
|
||||
(r"C:\a\b\c", r"C:\a", r"..\.."),
|
||||
(r"C:\a\b\b", r"C:\a\a\b", r"..\..\a\b"),
|
||||
];
|
||||
|
||||
for (from, to, expected) in cases {
|
||||
let from: UrlCow = from.try_into().unwrap();
|
||||
let to: UrlCow = to.try_into().unwrap();
|
||||
assert_eq!(format!("{:?}", url_relative_to(from, to).unwrap().as_url()), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
51
yazi-fs/src/path/relative.rs
Normal file
51
yazi-fs/src/path/relative.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use std::{borrow::Cow, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use yazi_shared::{loc::LocBuf, url::{Url, UrlBuf, UrlCow}};
|
||||
|
||||
pub fn path_relative_to<'a>(
|
||||
from: impl AsRef<Path>,
|
||||
to: &'a impl AsRef<Path>,
|
||||
) -> Result<Cow<'a, Path>> {
|
||||
Ok(match url_relative_to(Url::regular(&from).into(), Url::regular(to).into())? {
|
||||
UrlCow::Borrowed(url) => Cow::Borrowed(url.loc.as_path()),
|
||||
UrlCow::Owned(url) => Cow::Owned(url.loc.into_path()),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn url_relative_to<'a>(from: UrlCow<'_>, to: UrlCow<'a>) -> Result<UrlCow<'a>> {
|
||||
use yazi_shared::url::Component::*;
|
||||
|
||||
if from.is_absolute() != to.is_absolute() {
|
||||
return if to.is_absolute() {
|
||||
Ok(to)
|
||||
} else {
|
||||
bail!("Urls must be both absolute or both relative: {from:?} and {to:?}");
|
||||
};
|
||||
}
|
||||
|
||||
if from.covariant(&to) {
|
||||
return Ok(UrlBuf { loc: LocBuf::zeroed("."), scheme: to.scheme().clone() }.into());
|
||||
}
|
||||
|
||||
let (mut f_it, mut t_it) = (from.components(), to.components());
|
||||
let (f_head, t_head) = loop {
|
||||
match (f_it.next(), t_it.next()) {
|
||||
(Some(Scheme(a)), Some(Scheme(b))) if a.covariant(b) => {}
|
||||
(Some(RootDir), Some(RootDir)) => {}
|
||||
(Some(Prefix(a)), Some(Prefix(b))) if a == b => {}
|
||||
(Some(Scheme(_) | Prefix(_) | RootDir), _) | (_, Some(Scheme(_) | Prefix(_) | RootDir)) => {
|
||||
return Ok(to);
|
||||
}
|
||||
(None, None) => break (None, None),
|
||||
(a, b) if a != b => break (a, b),
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
|
||||
let dots = f_head.into_iter().chain(f_it).map(|_| ParentDir);
|
||||
let rest = t_head.into_iter().chain(t_it);
|
||||
|
||||
let buf: PathBuf = dots.chain(rest).collect();
|
||||
Ok(UrlBuf { loc: LocBuf::zeroed(buf), scheme: to.scheme().clone() }.into())
|
||||
}
|
||||
|
|
@ -1,90 +1,270 @@
|
|||
use std::{io, path::{Path, PathBuf}};
|
||||
|
||||
use crate::provider::local::{Gate, ReadDir, ReadDirSync, RwFile};
|
||||
use crate::{cha::Cha, provider::local::{Gate, ReadDir, ReadDirSync, RwFile}};
|
||||
|
||||
pub struct Local;
|
||||
|
||||
impl Local {
|
||||
#[inline]
|
||||
pub async fn canonicalize(path: impl AsRef<Path>) -> io::Result<PathBuf> {
|
||||
pub fn cache<P>(_: P) -> Option<PathBuf>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn canonicalize<P>(path: P) -> io::Result<PathBuf>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::canonicalize(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create(path: impl AsRef<Path>) -> io::Result<RwFile> {
|
||||
pub async fn copy<P, Q>(from: P, to: Q, cha: Cha) -> io::Result<u64>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
let from = from.as_ref().to_owned();
|
||||
let to = to.as_ref().to_owned();
|
||||
Self::copy_impl(from, to, cha).await
|
||||
}
|
||||
|
||||
async fn copy_impl(from: PathBuf, to: PathBuf, cha: Cha) -> io::Result<u64> {
|
||||
let mut ft = std::fs::FileTimes::new();
|
||||
cha.atime.map(|t| ft = ft.set_accessed(t));
|
||||
cha.mtime.map(|t| ft = ft.set_modified(t));
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use std::os::macos::fs::FileTimesExt;
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::FileTimesExt;
|
||||
cha.btime.map(|t| ft = ft.set_created(t));
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
{
|
||||
use std::os::{fd::AsRawFd, unix::fs::OpenOptionsExt};
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut reader = std::fs::File::open(from)?;
|
||||
let mut writer = std::fs::OpenOptions::new()
|
||||
.mode(cha.mode as u32) // Do not remove `as u32`, https://github.com/termux/termux-packages/pull/22481
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(to)?;
|
||||
|
||||
let written = std::io::copy(&mut reader, &mut writer)?;
|
||||
unsafe { libc::fchmod(writer.as_raw_fd(), cha.mode) };
|
||||
writer.set_times(ft).ok();
|
||||
|
||||
Ok(written)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
{
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let written = std::fs::copy(from, &to)?;
|
||||
std::fs::File::options().write(true).open(to).and_then(|f| f.set_times(ft)).ok();
|
||||
Ok(written)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create<P>(path: P) -> io::Result<RwFile>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Gate::default().write(true).create(true).truncate(true).open(path).await.map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn create_dir<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::create_dir(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn create_dir_all<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::create_dir_all(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn hard_link(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn hard_link<P, Q>(original: P, link: Q) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::hard_link(original, link).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn metadata(url: impl AsRef<Path>) -> io::Result<std::fs::Metadata> {
|
||||
pub async fn metadata<P>(url: P) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::metadata(url).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn open(path: impl AsRef<Path>) -> io::Result<RwFile> {
|
||||
pub async fn open<P>(path: P) -> io::Result<RwFile>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Gate::default().read(true).open(path).await.map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> { tokio::fs::read(path).await }
|
||||
pub async fn read<P>(path: P) -> io::Result<Vec<u8>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::read(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
|
||||
pub async fn read_dir<P>(path: P) -> io::Result<ReadDir>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::read_dir(path).await.map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_dir_sync(path: impl AsRef<Path>) -> io::Result<ReadDirSync> {
|
||||
pub fn read_dir_sync<P>(path: P) -> io::Result<ReadDirSync>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
std::fs::read_dir(path).map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_link(url: impl AsRef<Path>) -> io::Result<PathBuf> {
|
||||
pub async fn read_link<P>(url: P) -> io::Result<PathBuf>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::read_link(url).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_to_string(path: impl AsRef<Path>) -> io::Result<String> {
|
||||
pub async fn read_to_string<P>(path: P) -> io::Result<String>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::read_to_string(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn remove_dir<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::remove_dir(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn remove_dir_all<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::remove_dir_all(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn remove_file<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::remove_file(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn rename<P, Q>(from: P, to: Q) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::rename(from, to).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn same<P, Q>(a: P, b: Q) -> io::Result<bool>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
Self::same_impl(a.as_ref(), b.as_ref()).await
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn same_impl(a: &Path, b: &Path) -> io::Result<bool> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
let (a_, b_) = (tokio::fs::symlink_metadata(a).await?, tokio::fs::symlink_metadata(b).await?);
|
||||
Ok(
|
||||
a_.ino() == b_.ino()
|
||||
&& a_.dev() == b_.dev()
|
||||
&& tokio::fs::canonicalize(a).await? == tokio::fs::canonicalize(b).await?,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn same_impl(a: &Path, b: &Path) -> io::Result<bool> {
|
||||
use std::{ffi::OsString, os::windows::{ffi::OsStringExt, fs::OpenOptionsExt, io::AsRawHandle}};
|
||||
|
||||
use windows_sys::Win32::{Foundation::{HANDLE, MAX_PATH}, Storage::FileSystem::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, GetFinalPathNameByHandleW, VOLUME_NAME_DOS}};
|
||||
|
||||
async fn final_name(path: &Path) -> io::Result<PathBuf> {
|
||||
let path = path.to_owned();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let file = std::fs::OpenOptions::new()
|
||||
.access_mode(0)
|
||||
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)
|
||||
.open(path)?;
|
||||
|
||||
let mut buf = [0u16; MAX_PATH as usize];
|
||||
let len = unsafe {
|
||||
GetFinalPathNameByHandleW(
|
||||
file.as_raw_handle() as HANDLE,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as u32,
|
||||
VOLUME_NAME_DOS,
|
||||
)
|
||||
};
|
||||
|
||||
if len == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(PathBuf::from(OsString::from_wide(&buf[0..len as usize])))
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
Ok(final_name(a).await? == final_name(b).await?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir<P, Q>(original: P, link: Q) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
{
|
||||
tokio::fs::symlink(original, link).await
|
||||
|
|
@ -96,7 +276,11 @@ impl Local {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> io::Result<()> {
|
||||
pub async fn symlink_file<P, Q>(original: P, link: Q) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
{
|
||||
tokio::fs::symlink(original, link).await
|
||||
|
|
@ -108,17 +292,52 @@ impl Local {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<std::fs::Metadata> {
|
||||
pub async fn symlink_metadata<P>(path: P) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
tokio::fs::symlink_metadata(path).await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn symlink_metadata_sync(path: impl AsRef<Path>) -> io::Result<std::fs::Metadata> {
|
||||
pub fn symlink_metadata_sync<P>(path: P) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
std::fs::symlink_metadata(path)
|
||||
}
|
||||
|
||||
pub async fn trash<P>(path: P) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let path = path.as_ref().to_owned();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported OS for trash operation"))
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
use trash::{TrashContext, macos::{DeleteMethod, TrashContextExtMacos}};
|
||||
let mut ctx = TrashContext::default();
|
||||
ctx.set_delete_method(DeleteMethod::NsFileManager);
|
||||
ctx.delete(path).map_err(io::Error::other)
|
||||
}
|
||||
#[cfg(all(not(target_os = "macos"), not(target_os = "android")))]
|
||||
{
|
||||
trash::delete(path).map_err(io::Error::other)
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
|
||||
pub async fn write<P, C>(path: P, contents: C) -> io::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
C: AsRef<[u8]>,
|
||||
{
|
||||
tokio::fs::write(path, contents).await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,4 @@ impl From<tokio::fs::File> for crate::provider::RwFile {
|
|||
impl RwFile {
|
||||
#[inline]
|
||||
pub fn reader(self) -> tokio::io::BufReader<tokio::fs::File> { tokio::io::BufReader::new(self.0) }
|
||||
|
||||
#[inline]
|
||||
pub async fn reader_sync(self) -> std::io::BufReader<std::fs::File> {
|
||||
std::io::BufReader::new(self.0.into_std().await)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,22 @@
|
|||
use std::io;
|
||||
use std::{io, path::{Path, PathBuf}};
|
||||
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
|
||||
use crate::provider::{ReadDir, ReadDirSync, RwFile, local::Local};
|
||||
use crate::{cha::Cha, provider::{ReadDir, ReadDirSync, RwFile, local::Local}};
|
||||
|
||||
#[inline]
|
||||
pub async fn canonicalize<'a>(url: impl Into<Url<'a>>) -> io::Result<UrlBuf> {
|
||||
pub fn cache<'a, U>(url: U) -> Option<PathBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() { Local::cache(path) } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn canonicalize<'a, U>(url: U) -> io::Result<UrlBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::canonicalize(path).await.map(Into::into)
|
||||
} else {
|
||||
|
|
@ -14,7 +25,23 @@ pub async fn canonicalize<'a>(url: impl Into<Url<'a>>) -> io::Result<UrlBuf> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create<'a>(url: impl Into<Url<'a>>) -> io::Result<RwFile> {
|
||||
pub async fn copy<'a, U, V>(from: U, to: V, cha: Cha) -> io::Result<u64>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
{
|
||||
if let (Some(from), Some(to)) = (from.into().as_path(), to.into().as_path()) {
|
||||
Local::copy(from, to, cha).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create<'a, U>(url: U) -> io::Result<RwFile>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::create(path).await.map(Into::into)
|
||||
} else {
|
||||
|
|
@ -23,7 +50,10 @@ pub async fn create<'a>(url: impl Into<Url<'a>>) -> io::Result<RwFile> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn create_dir<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::create_dir(path).await
|
||||
} else {
|
||||
|
|
@ -32,7 +62,10 @@ pub async fn create_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn create_dir_all<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn create_dir_all<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::create_dir_all(path).await
|
||||
} else {
|
||||
|
|
@ -41,10 +74,11 @@ pub async fn create_dir_all<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn hard_link<'a>(
|
||||
original: impl Into<Url<'a>>,
|
||||
link: impl Into<Url<'a>>,
|
||||
) -> io::Result<()> {
|
||||
pub async fn hard_link<'a, U, V>(original: U, link: V) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
{
|
||||
if let (Some(original), Some(link)) = (original.into().as_path(), link.into().as_path()) {
|
||||
Local::hard_link(original, link).await
|
||||
} else {
|
||||
|
|
@ -53,7 +87,10 @@ pub async fn hard_link<'a>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn metadata<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs::Metadata> {
|
||||
pub async fn metadata<'a, U>(url: U) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::metadata(path).await
|
||||
} else {
|
||||
|
|
@ -62,7 +99,10 @@ pub async fn metadata<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs::Metada
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn open<'a>(url: impl Into<Url<'a>>) -> io::Result<RwFile> {
|
||||
pub async fn open<'a, U>(url: U) -> io::Result<RwFile>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::open(path).await.map(Into::into)
|
||||
} else {
|
||||
|
|
@ -71,7 +111,10 @@ pub async fn open<'a>(url: impl Into<Url<'a>>) -> io::Result<RwFile> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<ReadDir> {
|
||||
pub async fn read_dir<'a, U>(url: U) -> io::Result<ReadDir>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::read_dir(path).await.map(Into::into)
|
||||
} else {
|
||||
|
|
@ -80,7 +123,10 @@ pub async fn read_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<ReadDir> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_dir_sync<'a>(url: impl Into<Url<'a>>) -> io::Result<ReadDirSync> {
|
||||
pub fn read_dir_sync<'a, U>(url: U) -> io::Result<ReadDirSync>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::read_dir_sync(path).map(Into::into)
|
||||
} else {
|
||||
|
|
@ -89,16 +135,22 @@ pub fn read_dir_sync<'a>(url: impl Into<Url<'a>>) -> io::Result<ReadDirSync> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn read_link<'a>(url: impl Into<Url<'a>>) -> io::Result<UrlBuf> {
|
||||
pub async fn read_link<'a, U>(url: U) -> io::Result<PathBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::read_link(path).await.map(Into::into)
|
||||
Local::read_link(path).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn remove_dir<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::remove_dir(path).await
|
||||
} else {
|
||||
|
|
@ -107,7 +159,10 @@ pub async fn remove_dir<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_dir_all<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn remove_dir_all<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::remove_dir_all(path).await
|
||||
} else {
|
||||
|
|
@ -116,7 +171,10 @@ pub async fn remove_dir_all<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn remove_file<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn remove_file<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::remove_file(path).await
|
||||
} else {
|
||||
|
|
@ -125,7 +183,11 @@ pub async fn remove_file<'a>(url: impl Into<Url<'a>>) -> io::Result<()> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn rename<'a>(from: impl Into<Url<'a>>, to: impl Into<Url<'a>>) -> io::Result<()> {
|
||||
pub async fn rename<'a, U, V>(from: U, to: V) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
{
|
||||
if let (Some(from), Some(to)) = (from.into().as_path(), to.into().as_path()) {
|
||||
Local::rename(from, to).await
|
||||
} else {
|
||||
|
|
@ -134,11 +196,24 @@ pub async fn rename<'a>(from: impl Into<Url<'a>>, to: impl Into<Url<'a>>) -> io:
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir<'a>(
|
||||
original: impl Into<Url<'a>>,
|
||||
link: impl Into<Url<'a>>,
|
||||
) -> io::Result<()> {
|
||||
if let (Some(original), Some(link)) = (original.into().as_path(), link.into().as_path()) {
|
||||
pub async fn same<'a, U, V>(a: U, b: V) -> io::Result<bool>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
{
|
||||
if let (Some(a), Some(b)) = (a.into().as_path(), b.into().as_path()) {
|
||||
Local::same(a, b).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_dir<'a, U>(original: &Path, link: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(link) = link.into().as_path() {
|
||||
Local::symlink_dir(original, link).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
|
|
@ -146,11 +221,11 @@ pub async fn symlink_dir<'a>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_file<'a>(
|
||||
original: impl Into<Url<'a>>,
|
||||
link: impl Into<Url<'a>>,
|
||||
) -> io::Result<()> {
|
||||
if let (Some(original), Some(link)) = (original.into().as_path(), link.into().as_path()) {
|
||||
pub async fn symlink_file<'a, U>(original: &Path, link: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(link) = link.into().as_path() {
|
||||
Local::symlink_file(original, link).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
|
|
@ -158,7 +233,10 @@ pub async fn symlink_file<'a>(
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn symlink_metadata<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs::Metadata> {
|
||||
pub async fn symlink_metadata<'a, U>(url: U) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::symlink_metadata(path).await
|
||||
} else {
|
||||
|
|
@ -166,7 +244,11 @@ pub async fn symlink_metadata<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs
|
|||
}
|
||||
}
|
||||
|
||||
pub fn symlink_metadata_sync<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs::Metadata> {
|
||||
#[inline]
|
||||
pub fn symlink_metadata_sync<'a, U>(url: U) -> io::Result<std::fs::Metadata>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::symlink_metadata_sync(path)
|
||||
} else {
|
||||
|
|
@ -175,7 +257,23 @@ pub fn symlink_metadata_sync<'a>(url: impl Into<Url<'a>>) -> io::Result<std::fs:
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn write<'a>(url: impl Into<Url<'a>>, contents: impl AsRef<[u8]>) -> io::Result<()> {
|
||||
pub async fn trash<'a, U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::trash(path).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn write<'a, U, C>(url: U, contents: C) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
C: AsRef<[u8]>,
|
||||
{
|
||||
if let Some(path) = url.into().as_path() {
|
||||
Local::write(path, contents).await
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::provider::{BufRead, BufReadSync};
|
||||
use crate::provider::BufRead;
|
||||
|
||||
pub enum RwFile {
|
||||
Local(super::local::RwFile),
|
||||
|
|
@ -11,11 +11,4 @@ impl RwFile {
|
|||
RwFile::Local(local) => Box::new(local.reader()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn reader_sync(self) -> Box<dyn BufReadSync> {
|
||||
match self {
|
||||
RwFile::Local(local) => Box::new(local.reader_sync().await),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue