refactor: generalize Loc, LocBuf, Uri, and Urn (#3295)

This commit is contained in:
三咲雅 misaki masa 2025-10-30 19:37:46 +08:00 committed by GitHub
parent 564b885196
commit a3e9ea0d16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 532 additions and 285 deletions

68
Cargo.lock generated
View file

@ -54,9 +54,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "1.1.3"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
@ -527,9 +527,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.50"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
dependencies = [
"clap_builder",
"clap_derive",
@ -537,9 +537,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.50"
version = "4.5.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
dependencies = [
"anstream",
"anstyle",
@ -549,9 +549,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.59"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2348487adcd4631696ced64ccdb40d38ac4d31cae7f2eec8817fcea1b9d1c43c"
checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971"
dependencies = [
"clap",
]
@ -1820,9 +1820,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
dependencies = [
"once_cell",
"wasm-bindgen",
@ -2136,9 +2136,9 @@ dependencies = [
[[package]]
name = "moxcms"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574"
checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6"
dependencies = [
"num-traits",
"pxfm",
@ -3972,9 +3972,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "unicode-ident"
version = "1.0.20"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-segmentation"
@ -4149,9 +4149,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
dependencies = [
"cfg-if",
"once_cell",
@ -4160,25 +4160,11 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.54"
version = "0.4.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c"
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0"
dependencies = [
"cfg-if",
"js-sys",
@ -4189,9 +4175,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -4199,31 +4185,31 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.104"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.81"
version = "0.3.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120"
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
dependencies = [
"js-sys",
"wasm-bindgen",

View file

@ -24,7 +24,7 @@ ansi-to-tui = "7.0.0"
anyhow = "1.0.100"
base64 = "0.22.1"
bitflags = { version = "2.10.0", features = [ "serde" ] }
clap = { version = "4.5.50", features = [ "derive" ] }
clap = { version = "4.5.51", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.29.0", features = [ "event-stream" ] }
dirs = "6.0.0"

View file

@ -51,7 +51,7 @@ impl Create {
&& let Some((parent, urn)) = real.pair()
{
ok_or_not_found!(provider::remove_file(&new).await);
FilesOp::Deleting(parent.into(), [urn.into()].into()).emit();
FilesOp::Deleting(parent.into(), [urn.to_owned()].into()).emit();
provider::create(&new).await?;
} else if let Some(parent) = new.parent() {
provider::create_dir_all(parent).await.ok();
@ -65,7 +65,7 @@ impl Create {
&& let Some((parent, urn)) = real.pair()
{
let file = File::new(&real).await?;
FilesOp::Upserting(parent.into(), [(urn.into(), file)].into()).emit();
FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into()).emit();
MgrProxy::reveal(&real);
}

View file

@ -26,7 +26,7 @@ impl Actor for Hover {
// Turn on tracing
if let (Some(h), Some(u)) = (tab.hovered(), opt.urn)
&& *h.urn() == u
&& h.urn() == u
{
// `hover(Some)` occurs after user actions, such as create, rename, reveal, etc.
// At this point, it's intuitive to track the location of the file regardless.

View file

@ -73,7 +73,7 @@ impl Rename {
&& let Some((parent, urn)) = u.pair()
{
ok_or_not_found!(provider::rename(&u, &new).await);
FilesOp::Deleting(parent.to_owned(), [urn.into()].into()).emit();
FilesOp::Deleting(parent.to_owned(), [urn.to_owned()].into()).emit();
}
let new = provider::casefold(&new).await?;
@ -81,10 +81,10 @@ impl Rename {
let file = File::new(&new).await?;
if new_p == old_p {
FilesOp::Upserting(old_p.into(), [(old_n.into(), file)].into()).emit();
FilesOp::Upserting(old_p.into(), [(old_n.to_owned(), file)].into()).emit();
} else {
FilesOp::Deleting(old_p.into(), [old_n.into()].into()).emit();
FilesOp::Upserting(new_p.into(), [(new_n.into(), file)].into()).emit();
FilesOp::Deleting(old_p.into(), [old_n.to_owned()].into()).emit();
FilesOp::Upserting(new_p.into(), [(new_n.to_owned(), file)].into()).emit();
}
MgrProxy::reveal(&new);

View file

@ -31,7 +31,7 @@ impl Actor for Reveal {
}
// Now, we can safely hover on the target
act!(mgr:hover, cx, Some(child.into()))?;
act!(mgr:hover, cx, Some(child.to_owned()))?;
act!(mgr:peek, cx)?;
act!(mgr:watch, cx)?;

View file

@ -1,26 +1,39 @@
use std::ops::Deref;
use std::{ops::Deref, path::PathBuf};
use mlua::{ExternalError, FromLua, Lua, UserData, Value};
use yazi_shared::path::PathBufLike;
pub struct Urn {
inner: yazi_shared::url::UrnBuf,
pub struct Urn<P: PathBufLike = PathBuf> {
inner: yazi_shared::url::UrnBuf<P>,
}
impl Deref for Urn {
type Target = yazi_shared::url::UrnBuf;
impl<P> Deref for Urn<P>
where
P: PathBufLike,
{
type Target = yazi_shared::url::UrnBuf<P>;
fn deref(&self) -> &Self::Target { &self.inner }
}
impl From<Urn> for yazi_shared::url::UrnBuf {
fn from(value: Urn) -> Self { value.inner }
impl<P> From<Urn<P>> for yazi_shared::url::UrnBuf<P>
where
P: PathBufLike,
{
fn from(value: Urn<P>) -> Self { value.inner }
}
impl Urn {
pub fn new(urn: impl Into<yazi_shared::url::UrnBuf>) -> Self { Self { inner: urn.into() } }
impl<P> Urn<P>
where
P: PathBufLike,
{
pub fn new(urn: impl Into<yazi_shared::url::UrnBuf<P>>) -> Self { Self { inner: urn.into() } }
}
impl FromLua for Urn {
impl<P> FromLua for Urn<P>
where
P: PathBufLike,
{
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => ud.take()?,
@ -29,4 +42,4 @@ impl FromLua for Urn {
}
}
impl UserData for Urn {}
impl<P> UserData for Urn<P> where P: PathBufLike {}

View file

@ -28,7 +28,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
# External dependencies
clap = { workspace = true }
clap_complete = "4.5.59"
clap_complete = "4.5.60"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.9"
vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] }

View file

@ -38,7 +38,7 @@ impl Boot {
};
if provider::metadata(&entry).await.is_ok_and(|m| m.is_file()) {
(parent.into(), child.into())
(parent.into(), child.to_owned())
} else {
(entry, UrnBuf::default())
}

View file

@ -41,7 +41,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
# External build dependencies
anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.59"
clap_complete = "4.5.60"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.9"
serde_json = { workspace = true }

View file

@ -121,7 +121,7 @@ impl Folder {
if let Some(u) = urn {
self.hover(u)
} else if let Some(u) = &self.trace {
self.hover(u.clone().as_ref())
self.hover(&u.clone())
} else {
self.arrow(0)
}

View file

@ -2,7 +2,7 @@ use std::{ffi::OsStr, fmt::Display, ops::Range};
use anyhow::Result;
use regex::bytes::{Regex, RegexBuilder};
use yazi_shared::event::Cmd;
use yazi_shared::{event::Cmd, url::Urn};
pub struct Filter {
raw: String,
@ -23,9 +23,8 @@ impl Filter {
}
#[inline]
pub fn matches(&self, name: impl AsRef<OsStr>) -> bool {
self.regex.is_match(name.as_ref().as_encoded_bytes())
}
#[allow(private_bounds)]
pub fn matches(&self, name: impl Needle) -> bool { self.regex.is_match(name.needle()) }
#[inline]
pub fn highlighted(&self, name: impl AsRef<OsStr>) -> Option<Vec<Range<usize>>> {
@ -58,3 +57,16 @@ impl From<&Cmd> for FilterCase {
}
}
}
// --- Needle
trait Needle {
fn needle(&self) -> &[u8];
}
impl Needle for &OsStr {
fn needle(&self) -> &[u8] { self.as_encoded_bytes() }
}
impl Needle for &Urn {
fn needle(&self) -> &[u8] { self.encoded_bytes() }
}

View file

@ -1,6 +1,6 @@
#![allow(clippy::option_map_unit_fn)]
yazi_macro::mod_pub!(data errors event loc pool scheme shell translit url);
yazi_macro::mod_pub!(data errors event loc path pool scheme shell translit url);
yazi_macro::mod_flat!(alias bytes chars condition debounce either env id layer natsort os osstr rand ro_cell source string sync_cell terminal tests throttle time utf8);

View file

@ -1,44 +1,69 @@
use std::{cmp, ffi::{OsStr, OsString}, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, mem, ops::Deref, path::{Path, PathBuf}};
use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, ops::Deref, path::PathBuf};
use anyhow::Result;
use crate::{loc::Loc, url::{Uri, Urn}};
use crate::{loc::Loc, path::{PathBufLike, PathLike}, url::{Uri, Urn}};
#[derive(Clone, Default, Eq)]
pub struct LocBuf {
pub(super) inner: PathBuf,
pub struct LocBuf<P: PathBufLike = PathBuf> {
pub(super) inner: P,
pub(super) uri: usize,
pub(super) urn: usize,
}
impl Deref for LocBuf {
type Target = PathBuf;
impl<P> Deref for LocBuf<P>
where
P: PathBufLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { &self.inner }
}
impl AsRef<Path> for LocBuf {
fn as_ref(&self) -> &Path { &self.inner }
impl<P> AsRef<P::Borrowed> for LocBuf<P>
where
P: PathBufLike,
{
fn as_ref(&self) -> &P::Borrowed { self.inner.as_ref() }
}
impl PartialEq for LocBuf {
impl<P> PartialEq for LocBuf<P>
where
P: PathBufLike + PartialEq,
{
fn eq(&self, other: &Self) -> bool { self.inner == other.inner }
}
impl Ord for LocBuf {
impl<P> Ord for LocBuf<P>
where
P: PathBufLike + Ord,
{
fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) }
}
impl PartialOrd for LocBuf {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) }
impl<P> PartialOrd for LocBuf<P>
where
P: PathBufLike + PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.inner.partial_cmp(&other.inner)
}
}
// --- Hash
impl Hash for LocBuf {
impl<P> Hash for LocBuf<P>
where
P: PathBufLike,
P::Borrowed: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) { self.as_loc().hash(state) }
}
impl Debug for LocBuf {
impl<P> Debug for LocBuf<P>
where
P: PathBufLike + Debug,
P::Borrowed: Debug,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("LocBuf")
.field("path", &self.inner)
@ -48,39 +73,47 @@ impl Debug for LocBuf {
}
}
impl From<PathBuf> for LocBuf {
fn from(path: PathBuf) -> Self {
let Loc { inner, uri, urn } = Loc::from(path.as_path());
let len = inner.as_os_str().len();
impl<P> From<P> for LocBuf<P>
where
P: PathBufLike,
{
fn from(path: P) -> Self {
let Loc { inner, uri, urn } = Loc::from(&path);
let len = inner.len();
let mut bytes = path.into_os_string().into_encoded_bytes();
let mut bytes = path.into_encoded_bytes();
bytes.truncate(len);
Self {
inner: PathBuf::from(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }),
uri,
urn,
}
Self { inner: unsafe { P::from_encoded_bytes(bytes) }, uri, urn }
}
}
impl<T: ?Sized + AsRef<OsStr>> From<&T> for LocBuf {
impl<T: ?Sized + AsRef<OsStr>> From<&T> for LocBuf<PathBuf> {
fn from(value: &T) -> Self { Self::from(PathBuf::from(value)) }
}
impl LocBuf {
pub fn new(path: impl Into<PathBuf>, base: &Path, trail: &Path) -> Self {
let loc = Self::from(path.into());
impl<P> LocBuf<P>
where
P: PathBufLike,
{
pub fn new<T>(path: P, base: &T, trail: &T) -> Self
where
T: AsRef<P::Borrowed> + ?Sized,
{
let loc = Self::from(path);
let Loc { inner, uri, urn } = Loc::new(&loc.inner, base, trail);
debug_assert!(inner.as_os_str() == loc.inner.as_os_str());
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
}
pub fn with(path: PathBuf, uri: usize, urn: usize) -> Result<Self> {
pub fn with(path: P, uri: usize, urn: usize) -> Result<Self>
where
P::Borrowed: PathLike,
{
let loc = Self::from(path);
let Loc { inner, uri, urn } = Loc::with(&loc.inner, uri, urn)?;
debug_assert!(inner.as_os_str() == loc.inner.as_os_str());
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Ok(Self { inner: loc.inner, uri, urn })
}
@ -88,36 +121,53 @@ impl LocBuf {
// pub const fn empty() -> Self { Self { inner: PathBuf::new(), uri: 0, urn: 0 }
// }
pub fn zeroed(path: impl Into<PathBuf>) -> Self {
pub fn zeroed<T>(path: T) -> Self
where
T: Into<P>,
{
let loc = Self::from(path.into());
let Loc { inner, uri, urn } = Loc::zeroed(&loc.inner);
debug_assert!(inner.as_os_str() == loc.inner.as_os_str());
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
}
pub fn floated(path: impl Into<PathBuf>, base: &Path) -> Self {
pub fn floated<T, U>(path: T, base: &U) -> Self
where
T: Into<P>,
U: AsRef<P::Borrowed> + ?Sized,
{
let loc = Self::from(path.into());
let Loc { inner, uri, urn } = Loc::floated(&loc.inner, base);
debug_assert!(inner.as_os_str() == loc.inner.as_os_str());
debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes());
Self { inner: loc.inner, uri, urn }
}
#[inline]
pub fn as_loc<'a>(&'a self) -> Loc<'a> { Loc::from(self) }
pub fn as_loc<'a>(&'a self) -> Loc<'a, P::Borrowed> {
Loc { inner: self.inner.as_ref(), uri: self.uri, urn: self.urn }
}
#[inline]
pub fn to_path(&self) -> PathBuf { self.inner.clone() }
pub fn to_path(&self) -> P
where
P: Clone,
{
self.inner.clone()
}
#[inline]
pub fn into_path(self) -> PathBuf { self.inner }
pub fn into_path(self) -> P { self.inner }
pub fn set_name(&mut self, name: impl AsRef<OsStr>) {
let old = self.bytes().len();
pub fn set_name<T>(&mut self, name: T)
where
T: AsRef<P::InnerRef>,
{
let old = self.inner.len();
self.mutate(|path| path.set_file_name(name));
let new = self.bytes().len();
let new = self.len();
if new == old {
return;
}
@ -139,55 +189,63 @@ impl LocBuf {
}
#[inline]
pub fn rebase(&self, base: &Path) -> Self {
pub fn rebase(&self, base: &P::Borrowed) -> Self
where
<P::Borrowed as PathLike>::Owned: Into<Self>,
{
let mut loc: Self = base.join(self.uri()).into();
(loc.uri, loc.urn) = (self.uri, self.urn);
loc
}
#[inline]
fn bytes(&self) -> &[u8] { self.inner.as_os_str().as_encoded_bytes() }
#[inline]
fn mutate<F: FnOnce(&mut PathBuf)>(&mut self, f: F) {
let mut inner = mem::take(&mut self.inner);
fn mutate<F: FnOnce(&mut P)>(&mut self, f: F)
where
P: Default,
{
let mut inner = std::mem::take(&mut self.inner);
f(&mut inner);
self.inner = Self::from(inner).inner;
}
}
// FIXME: macro
impl LocBuf {
impl<P> LocBuf<P>
where
P: PathBufLike,
{
#[inline]
pub fn uri(&self) -> &Uri { self.as_loc().uri() }
pub fn uri(&self) -> &Uri<P::Borrowed> { self.as_loc().uri() }
#[inline]
pub fn urn(&self) -> &Urn { self.as_loc().urn() }
pub fn urn(&self) -> &Urn<P::Borrowed> { self.as_loc().urn() }
#[inline]
pub fn base(&self) -> &Urn { self.as_loc().base() }
pub fn base(&self) -> &Urn<P::Borrowed> { self.as_loc().base() }
#[inline]
pub fn has_base(&self) -> bool { self.as_loc().has_base() }
#[inline]
pub fn trail(&self) -> &Urn { self.as_loc().trail() }
pub fn trail(&self) -> &Urn<P::Borrowed> { self.as_loc().trail() }
#[inline]
pub fn has_trail(&self) -> bool { self.as_loc().has_trail() }
#[inline]
pub fn name(&self) -> Option<&OsStr> { self.as_loc().name() }
pub fn name(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().name() }
#[inline]
pub fn stem(&self) -> Option<&OsStr> { self.as_loc().stem() }
pub fn stem(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().stem() }
#[inline]
pub fn ext(&self) -> Option<&OsStr> { self.as_loc().ext() }
pub fn ext(&self) -> Option<&<P::Borrowed as PathLike>::Inner> { self.as_loc().ext() }
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::*;
use crate::url::{UrlBuf, UrlLike};
@ -217,42 +275,42 @@ mod tests {
#[test]
fn test_with() -> Result<()> {
let loc = LocBuf::with("/".into(), 0, 0)?;
let loc = LocBuf::<PathBuf>::with("/".into(), 0, 0)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new(""));
assert_eq!(loc.urn().as_os_str(), OsStr::new(""));
assert_eq!(loc.name(), None);
assert_eq!(loc.base().as_os_str(), OsStr::new("/"));
assert_eq!(loc.trail().as_os_str(), OsStr::new("/"));
let loc = LocBuf::with("/root/code/".into(), 1, 1)?;
let loc = LocBuf::<PathBuf>::with("/root/code/".into(), 1, 1)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new("code"));
assert_eq!(loc.urn().as_os_str(), OsStr::new("code"));
assert_eq!(loc.name().unwrap(), OsStr::new("code"));
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/"));
let loc = LocBuf::with("/root/code/foo//".into(), 2, 1)?;
let loc = LocBuf::<PathBuf>::with("/root/code/foo//".into(), 2, 1)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo"));
assert_eq!(loc.urn().as_os_str(), OsStr::new("foo"));
assert_eq!(loc.name().unwrap(), OsStr::new("foo"));
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/"));
let loc = LocBuf::with("/root/code/foo//".into(), 2, 2)?;
let loc = LocBuf::<PathBuf>::with("/root/code/foo//".into(), 2, 2)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo"));
assert_eq!(loc.urn().as_os_str(), OsStr::new("code/foo"));
assert_eq!(loc.name().unwrap(), OsStr::new("foo"));
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/"));
assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/"));
let loc = LocBuf::with("/root/code/foo//bar/".into(), 2, 2)?;
let loc = LocBuf::<PathBuf>::with("/root/code/foo//bar/".into(), 2, 2)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new("foo//bar"));
assert_eq!(loc.urn().as_os_str(), OsStr::new("foo//bar"));
assert_eq!(loc.name().unwrap(), OsStr::new("bar"));
assert_eq!(loc.base().as_os_str(), OsStr::new("/root/code/"));
assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/"));
let loc = LocBuf::with("/root/code/foo//bar/".into(), 3, 2)?;
let loc = LocBuf::<PathBuf>::with("/root/code/foo//bar/".into(), 3, 2)?;
assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo//bar"));
assert_eq!(loc.urn().as_os_str(), OsStr::new("foo//bar"));
assert_eq!(loc.name().unwrap(), OsStr::new("bar"));

View file

@ -1,95 +1,120 @@
use std::{ffi::OsStr, hash::{Hash, Hasher}, ops::Deref, path::Path};
use std::{hash::{Hash, Hasher}, ops::Deref, path::Path};
use anyhow::{Result, bail};
use crate::{loc::LocBuf, url::{Uri, Urn}};
use crate::{loc::LocBuf, path::{PathInner, PathLike}, url::{Uri, Urn}};
#[derive(Clone, Copy, Debug)]
pub struct Loc<'a> {
pub(super) inner: &'a Path,
#[derive(Debug)]
pub struct Loc<'a, P: ?Sized + PathLike = Path> {
pub(super) inner: &'a P,
pub(super) uri: usize,
pub(super) urn: usize,
}
impl Default for Loc<'_> {
fn default() -> Self { Self { inner: Path::new(""), uri: 0, urn: 0 } }
impl<'a, P> Copy for Loc<'a, P> where P: ?Sized + PathLike {}
impl<'a, P> Clone for Loc<'a, P>
where
P: ?Sized + PathLike,
{
fn clone(&self) -> Self { *self }
}
impl Deref for Loc<'_> {
type Target = Path;
impl<P> Default for Loc<'static, P>
where
P: ?Sized + PathLike,
{
fn default() -> Self { Self { inner: P::default(), uri: 0, urn: 0 } }
}
impl<P> Deref for Loc<'_, P>
where
P: ?Sized + PathLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { self.inner }
}
impl AsRef<Path> for Loc<'_> {
fn as_ref(&self) -> &Path { self.inner }
}
impl<'a> From<&'a LocBuf> for Loc<'a> {
fn from(value: &'a LocBuf) -> Self {
Self { inner: &value.inner, uri: value.uri, urn: value.urn }
}
impl<P> AsRef<P> for Loc<'_, P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { self.inner }
}
// --- Hash
impl Hash for Loc<'_> {
impl<P> Hash for Loc<'_, P>
where
P: ?Sized + PathLike + Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) { self.inner.hash(state) }
}
impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for Loc<'a> {
impl<'a, P, T> From<&'a T> for Loc<'a, P>
where
P: ?Sized + PathLike,
T: ?Sized + AsRef<P>,
{
fn from(value: &'a T) -> Self {
let path = Path::new(value.as_ref());
let path = value.as_ref();
let Some(name) = path.file_name() else {
let uri = path.as_os_str().len();
let uri = path.len();
return Self { inner: path, uri, urn: 0 };
};
let name_len = name.len();
let prefix_len = unsafe {
name
.as_encoded_bytes()
.as_ptr()
.offset_from_unsigned(path.as_os_str().as_encoded_bytes().as_ptr())
};
let prefix_len =
unsafe { name.encoded_bytes().as_ptr().offset_from_unsigned(path.encoded_bytes().as_ptr()) };
let bytes = path.as_os_str().as_encoded_bytes();
let bytes = path.encoded_bytes();
Self {
inner: Path::new(unsafe {
OsStr::from_encoded_bytes_unchecked(&bytes[..prefix_len + name_len])
}),
inner: unsafe { P::from_encoded_bytes(&bytes[..prefix_len + name_len]) },
uri: name_len,
urn: name_len,
}
}
}
impl From<Loc<'_>> for LocBuf {
fn from(value: Loc<'_>) -> Self {
impl<P> From<Loc<'_, P>> for LocBuf<<P as PathLike>::Owned>
where
P: ?Sized + PathLike + ToOwned<Owned = <P as PathLike>::Owned>,
{
fn from(value: Loc<'_, P>) -> Self {
Self { inner: value.inner.to_owned(), uri: value.uri, urn: value.urn }
}
}
// --- Eq
impl PartialEq for Loc<'_> {
impl<P> PartialEq for Loc<'_, P>
where
P: ?Sized + PathLike + PartialEq,
{
fn eq(&self, other: &Self) -> bool { self.inner == other.inner }
}
impl Eq for Loc<'_> {}
impl<P> Eq for Loc<'_, P> where P: ?Sized + PathLike + Eq {}
impl<'a> Loc<'a> {
pub fn new<T>(path: &'a T, base: &Path, trail: &Path) -> Self
impl<'a, P> Loc<'a, P>
where
P: ?Sized + PathLike,
{
pub fn new<T, U>(path: &'a T, base: &U, trail: &U) -> Self
where
T: AsRef<Path> + ?Sized,
T: AsRef<P> + ?Sized,
U: AsRef<P> + ?Sized,
{
let mut loc = Self::from(path.as_ref());
loc.uri =
loc.inner.strip_prefix(base).expect("Loc must start with the given base").as_os_str().len();
loc.urn =
loc.inner.strip_prefix(trail).expect("Loc must start with the given trail").as_os_str().len();
let mut loc = Self::from(path);
loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len();
loc.urn = loc.inner.strip_prefix(trail).expect("Loc must start with the given trail").len();
loc
}
pub fn with(path: &'a Path, uri: usize, urn: usize) -> Result<Self> {
pub fn with<T>(path: &'a T, uri: usize, urn: usize) -> Result<Self>
where
T: ?Sized + AsRef<P>,
<P as PathLike>::Components<'a>: AsRef<P> + Clone + DoubleEndedIterator,
{
if urn > uri {
bail!("URN cannot be longer than URI");
}
@ -108,26 +133,32 @@ impl<'a> Loc<'a> {
bail!("URI exceeds the entire URL");
}
if i == urn {
loc.urn = loc.strip_prefix(it.clone()).unwrap().as_os_str().len();
loc.urn = loc.strip_prefix(it.clone()).unwrap().len();
}
if i == uri {
loc.uri = loc.strip_prefix(it).unwrap().as_os_str().len();
loc.uri = loc.strip_prefix(it).unwrap().len();
break;
}
}
Ok(loc)
}
pub fn zeroed<T: AsRef<Path> + ?Sized>(path: &'a T) -> Self {
let mut loc = Self::from(path.as_ref());
pub fn zeroed<T>(path: &'a T) -> Self
where
T: AsRef<P> + ?Sized,
{
let mut loc = Self::from(path);
(loc.uri, loc.urn) = (0, 0);
loc
}
pub fn floated<T: AsRef<Path> + ?Sized>(path: &'a T, base: &Path) -> Self {
let mut loc = Self::from(path.as_ref());
loc.uri =
loc.inner.strip_prefix(base).expect("Loc must start with the given base").as_os_str().len();
pub fn floated<T, U>(path: &'a T, base: &U) -> Self
where
T: AsRef<P> + ?Sized,
U: AsRef<P> + ?Sized,
{
let mut loc = Self::from(path);
loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len();
loc
}
@ -135,65 +166,57 @@ impl<'a> Loc<'a> {
pub fn as_loc(self) -> Self { self }
#[inline]
pub fn as_path(self) -> &'a Path { self.inner }
pub fn as_path(self) -> &'a P { self.inner }
#[inline]
pub fn uri(self) -> &'a Uri {
pub fn uri(self) -> &'a Uri<P> {
Uri::new(unsafe {
OsStr::from_encoded_bytes_unchecked(
self.bytes().get_unchecked(self.bytes().len() - self.uri..),
)
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.uri..))
})
}
#[inline]
pub fn urn(self) -> &'a Urn {
pub fn urn(self) -> &'a Urn<P> {
Urn::new(unsafe {
OsStr::from_encoded_bytes_unchecked(
self.bytes().get_unchecked(self.bytes().len() - self.urn..),
)
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.urn..))
})
}
#[inline]
pub fn base(self) -> &'a Urn {
pub fn base(self) -> &'a Urn<P> {
Urn::new(unsafe {
OsStr::from_encoded_bytes_unchecked(
self.bytes().get_unchecked(..self.bytes().len() - self.uri),
)
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.uri))
})
}
#[inline]
pub fn has_base(self) -> bool { self.bytes().len() != self.uri }
pub fn has_base(self) -> bool { self.inner.len() != self.uri }
#[inline]
pub fn trail(self) -> &'a Urn {
pub fn trail(self) -> &'a Urn<P> {
Urn::new(unsafe {
OsStr::from_encoded_bytes_unchecked(
self.bytes().get_unchecked(..self.bytes().len() - self.urn),
)
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.urn))
})
}
#[inline]
pub fn has_trail(self) -> bool { self.bytes().len() != self.urn }
pub fn has_trail(self) -> bool { self.inner.len() != self.urn }
#[inline]
pub fn name(self) -> Option<&'a OsStr> { self.inner.file_name() }
pub fn name(self) -> Option<&'a P::Inner> { self.inner.file_name() }
#[inline]
pub fn stem(self) -> Option<&'a OsStr> { self.inner.file_stem() }
pub fn stem(self) -> Option<&'a P::Inner> { self.inner.file_stem() }
#[inline]
pub fn ext(self) -> Option<&'a OsStr> { self.inner.extension() }
pub fn ext(self) -> Option<&'a P::Inner> { self.inner.extension() }
#[inline]
pub fn parent(self) -> Option<&'a Path> { self.inner.parent() }
pub fn parent(self) -> Option<&'a P> { self.inner.parent() }
#[inline]
pub fn triple(self) -> (&'a Path, &'a Path, &'a Path) {
let len = self.bytes().len();
pub fn triple(self) -> (&'a P, &'a P, &'a P) {
let len = self.inner.len();
let base = ..len - self.uri;
let rest = len - self.uri..len - self.urn;
@ -201,18 +224,18 @@ impl<'a> Loc<'a> {
unsafe {
(
Path::new(OsStr::from_encoded_bytes_unchecked(self.bytes().get_unchecked(base))),
Path::new(OsStr::from_encoded_bytes_unchecked(self.bytes().get_unchecked(rest))),
Path::new(OsStr::from_encoded_bytes_unchecked(self.bytes().get_unchecked(urn))),
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(base)),
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(rest)),
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(urn)),
)
}
}
#[inline]
pub fn strip_prefix(self, base: impl AsRef<Path>) -> Option<&'a Path> {
self.inner.strip_prefix(base).ok()
pub fn strip_prefix<T>(self, base: T) -> Option<&'a P>
where
T: AsRef<P>,
{
self.inner.strip_prefix(base)
}
#[inline]
pub fn bytes(self) -> &'a [u8] { self.inner.as_os_str().as_encoded_bytes() }
}

View file

@ -0,0 +1 @@
yazi_macro::mod_flat!(traits);

View file

@ -0,0 +1,122 @@
use std::{ffi::{OsStr, OsString}, path::{Path, PathBuf}};
pub trait PathLike: AsRef<Self> {
type Inner: ?Sized + PathInner;
type Owned: PathBufLike + Into<Self::Owned>;
type Components<'a>: AsRef<Self> + Clone + DoubleEndedIterator
where
Self: 'a;
fn components(&self) -> Self::Components<'_>;
fn default() -> &'static Self;
fn encoded_bytes(&self) -> &[u8];
fn extension(&self) -> Option<&Self::Inner>;
fn file_name(&self) -> Option<&Self::Inner>;
fn file_stem(&self) -> Option<&Self::Inner>;
unsafe fn from_encoded_bytes(bytes: &[u8]) -> &Self;
fn join<T>(&self, base: T) -> Self::Owned
where
T: AsRef<Self>;
fn len(&self) -> usize { self.encoded_bytes().len() }
fn parent(&self) -> Option<&Self>;
fn strip_prefix<T>(&self, base: T) -> Option<&Self>
where
T: AsRef<Self>;
}
pub trait PathBufLike: AsRef<Self::Borrowed> + Default + 'static {
type Inner: AsRef<Self::InnerRef>;
type InnerRef: ?Sized + PathInner;
type Borrowed: ?Sized + PathLike + AsRef<Self::Borrowed>;
fn encoded_bytes(&self) -> &[u8];
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self;
fn into_encoded_bytes(self) -> Vec<u8>;
fn len(&self) -> usize { self.encoded_bytes().len() }
fn set_file_name<T>(&mut self, name: T)
where
T: AsRef<Self::InnerRef>;
}
pub trait PathInner {
fn len(&self) -> usize { self.encoded_bytes().len() }
fn encoded_bytes(&self) -> &[u8];
}
impl PathLike for Path {
type Components<'a> = std::path::Components<'a>;
type Inner = OsStr;
type Owned = PathBuf;
fn components(&self) -> Self::Components<'_> { self.components() }
fn default() -> &'static Self { Path::new("") }
fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() }
fn extension(&self) -> Option<&Self::Inner> { self.extension() }
fn file_name(&self) -> Option<&Self::Inner> { self.file_name() }
fn file_stem(&self) -> Option<&Self::Inner> { self.file_stem() }
unsafe fn from_encoded_bytes(bytes: &[u8]) -> &Self {
Self::new(unsafe { Self::Inner::from_encoded_bytes_unchecked(bytes) })
}
fn join<T>(&self, base: T) -> Self::Owned
where
T: AsRef<Self>,
{
self.join(base)
}
fn parent(&self) -> Option<&Self> { self.parent() }
fn strip_prefix<T>(&self, base: T) -> Option<&Self>
where
T: AsRef<Self>,
{
self.strip_prefix(base).ok()
}
}
impl PathBufLike for PathBuf {
type Borrowed = Path;
type Inner = OsString;
type InnerRef = OsStr;
fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() }
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self {
Self::from(unsafe { Self::Inner::from_encoded_bytes_unchecked(bytes) })
}
fn into_encoded_bytes(self) -> Vec<u8> { self.into_os_string().into_encoded_bytes() }
fn set_file_name<T>(&mut self, name: T)
where
T: AsRef<Self::InnerRef>,
{
self.set_file_name(name);
}
}
impl PathInner for OsStr {
fn encoded_bytes(&self) -> &[u8] { self.as_encoded_bytes() }
}

View file

@ -1,31 +1,39 @@
use std::{ops::Deref, path::{Component, Path}};
use std::{ops::Deref, path::Path};
use crate::path::PathLike;
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Uri(Path);
pub struct Uri<P: ?Sized + PathLike = Path>(P);
impl Uri {
impl<P> Uri<P>
where
P: ?Sized + PathLike,
{
#[inline]
pub fn new<T: AsRef<Path> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const Path as *const Self) }
pub fn new<T: AsRef<P> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const P as *const Self) }
}
#[inline]
pub fn count(&self) -> usize { self.0.components().count() }
#[inline]
pub fn nth(&self, n: usize) -> Option<Component<'_>> { self.0.components().nth(n) }
#[inline]
pub fn is_empty(&self) -> bool { self.0.as_os_str().is_empty() }
pub fn is_empty(&self) -> bool { self.0.len() == 0 }
}
impl Deref for Uri {
type Target = Path;
impl<P> Deref for Uri<P>
where
P: ?Sized + PathLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl AsRef<Path> for Uri {
fn as_ref(&self) -> &Path { &self.0 }
impl<P> AsRef<P> for Uri<P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { &self.0 }
}

View file

@ -161,7 +161,7 @@ impl<'a> Url<'a> {
// Archive
S::Archive(_) if uri.is_empty() => Self { loc: parent.into(), scheme: S::Regular },
S::Archive(_) if uri.nth(1).is_none() => {
S::Archive(_) if uri.components().nth(1).is_none() => {
Self { loc: Loc::zeroed(parent), scheme: self.scheme }
}
S::Archive(_) => Self { loc: Loc::floated(parent, self.loc.base()), scheme: self.scheme },

View file

@ -1,100 +1,124 @@
use std::{borrow::{Borrow, Cow}, ffi::OsStr, ops::Deref, path::{Path, PathBuf}};
use std::{borrow::Borrow, ops::Deref, path::{Path, PathBuf}};
use serde::Serialize;
use crate::path::{PathBufLike, PathLike};
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Urn(Path);
pub struct Urn<P: ?Sized + PathLike = Path>(P);
impl Urn {
impl<P> Urn<P>
where
P: ?Sized + PathLike,
{
#[inline]
pub fn new<T: AsRef<Path> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const Path as *const Self) }
pub fn new<T: AsRef<P> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const P as *const Self) }
}
#[inline]
pub fn name(&self) -> Option<&OsStr> { self.0.file_name() }
pub fn name(&self) -> Option<&P::Inner> { self.0.file_name() }
#[inline]
pub fn count(&self) -> usize { self.0.components().count() }
#[inline]
pub fn encoded_bytes(&self) -> &[u8] { self.0.as_os_str().as_encoded_bytes() }
pub fn encoded_bytes(&self) -> &[u8] { self.0.encoded_bytes() }
#[cfg(unix)]
#[inline]
pub fn is_hidden(&self) -> bool {
use std::os::unix::ffi::OsStrExt;
self.name().is_some_and(|s| s.as_bytes().starts_with(b"."))
use crate::path::PathInner;
self.name().is_some_and(|s| s.encoded_bytes().starts_with(b"."))
}
}
impl Deref for Urn {
type Target = Path;
impl<P> Deref for Urn<P>
where
P: ?Sized + PathLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl AsRef<Path> for Urn {
fn as_ref(&self) -> &Path { &self.0 }
impl<P> AsRef<P> for Urn<P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { &self.0 }
}
impl AsRef<OsStr> for Urn {
fn as_ref(&self) -> &OsStr { self.0.as_os_str() }
impl<P> From<&Urn<P>> for PathBuf
where
P: ?Sized + PathLike + ToOwned<Owned = PathBuf>,
{
fn from(value: &Urn<P>) -> Self { value.0.to_owned() }
}
impl ToOwned for Urn {
type Owned = UrnBuf;
impl<P> ToOwned for Urn<P>
where
P: ?Sized + PathLike + ToOwned<Owned = <P as PathLike>::Owned>,
UrnBuf<<P as PathLike>::Owned>: Borrow<Urn<P>>,
{
type Owned = UrnBuf<<P as PathLike>::Owned>;
fn to_owned(&self) -> Self::Owned { UrnBuf(self.0.to_owned()) }
}
impl<T: AsRef<OsStr>> PartialEq<T> for Urn {
fn eq(&self, other: &T) -> bool { self.0 == other.as_ref() }
}
impl PartialEq<Cow<'_, OsStr>> for &Urn {
fn eq(&self, other: &Cow<OsStr>) -> bool { self.0 == other.as_ref() }
impl<P> PartialEq<UrnBuf<P::Owned>> for &Urn<P>
where
P: ?Sized + PathLike + PartialEq<P::Owned>,
{
fn eq(&self, other: &UrnBuf<P::Owned>) -> bool { self.0 == other.0 }
}
// --- UrnBuf
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize)]
pub struct UrnBuf(PathBuf);
pub struct UrnBuf<P: PathBufLike = PathBuf>(P);
impl Deref for UrnBuf {
type Target = Urn;
fn deref(&self) -> &Self::Target { self.borrow() }
impl<P> Borrow<Urn<P::Borrowed>> for UrnBuf<P>
where
P: PathBufLike,
{
fn borrow(&self) -> &Urn<P::Borrowed> { Urn::new(&self.0) }
}
impl Borrow<Urn> for UrnBuf {
fn borrow(&self) -> &Urn { Urn::new(&self.0) }
impl<P> Deref for UrnBuf<P>
where
P: PathBufLike,
{
type Target = Urn<P::Borrowed>;
fn deref(&self) -> &Self::Target { Urn::new(&self.0) }
}
impl AsRef<Urn> for UrnBuf {
fn as_ref(&self) -> &Urn { self.borrow() }
impl<P> AsRef<P::Borrowed> for UrnBuf<P>
where
P: PathBufLike,
{
fn as_ref(&self) -> &P::Borrowed { Urn::new(&self.0) }
}
impl AsRef<Path> for UrnBuf {
fn as_ref(&self) -> &Path { &self.0 }
impl<P> PartialEq<Urn<P::Borrowed>> for UrnBuf<P>
where
P: PathBufLike + PartialEq<P::Borrowed>,
{
fn eq(&self, other: &Urn<P::Borrowed>) -> bool { self.0 == other.0 }
}
impl PartialEq<Urn> for UrnBuf {
fn eq(&self, other: &Urn) -> bool { self.0 == other.0 }
impl<T> From<T> for UrnBuf<PathBuf>
where
T: Into<PathBuf>,
{
fn from(value: T) -> Self { Self(value.into()) }
}
impl PartialEq<UrnBuf> for Urn {
fn eq(&self, other: &UrnBuf) -> bool { self.0 == other.0 }
}
impl<T: Into<PathBuf>> From<T> for UrnBuf {
fn from(p: T) -> Self { Self(p.into()) }
}
impl UrnBuf {
impl<P> UrnBuf<P>
where
P: PathBufLike,
{
#[inline]
pub fn as_urn(&self) -> &Urn { self.borrow() }
#[inline]
pub fn as_os_str(&self) -> &OsStr { self.0.as_os_str() }
pub fn as_urn(&self) -> &Urn<P::Borrowed> { self }
}

View file

@ -15,7 +15,7 @@ impl VfsFilesOp for FilesOp {
} else if maybe_exists(cwd).await {
Self::IOErr(cwd.clone(), err).emit();
} else if let Some((p, n)) = cwd.pair() {
Self::Deleting(p.into(), [n.into()].into()).emit();
Self::Deleting(p.into(), [n.to_owned()].into()).emit();
}
}
}

View file

@ -70,18 +70,18 @@ impl Local {
for u in urls {
let Some((parent, urn)) = u.pair() else { continue };
let Ok(file) = File::new(&u).await else {
ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into()));
ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into()));
continue;
};
if let Some(p) = file.url.as_path()
&& !provider::local::must_case_match(p).await
{
ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into()));
ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into()));
continue;
}
ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into()));
ops.push(FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into()));
}
FilesOp::mutate(ops);

View file

@ -39,14 +39,14 @@ impl Remote {
for u in urls {
let Some((parent, urn)) = u.pair() else { continue };
let Ok(mut file) = File::new(&u).await else {
ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into()));
ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into()));
continue;
};
let is_file = file.is_file();
file.cha.ctime = Some(SystemTime::now());
ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into()));
ops.push(FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into()));
if is_file {
ups.push(u);
}