mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
refactor: generalize Loc, LocBuf, Uri, and Urn (#3295)
This commit is contained in:
parent
564b885196
commit
a3e9ea0d16
23 changed files with 532 additions and 285 deletions
68
Cargo.lock
generated
68
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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" ] }
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
1
yazi-shared/src/path/mod.rs
Normal file
1
yazi-shared/src/path/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(traits);
|
||||
122
yazi-shared/src/path/traits.rs
Normal file
122
yazi-shared/src/path/traits.rs
Normal 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() }
|
||||
}
|
||||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue