refactor: Url::pair() without allocation (#3116)

This commit is contained in:
三咲雅 misaki masa 2025-08-27 23:52:09 +08:00 committed by GitHub
parent c2a94daad6
commit dd7afaa64a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 74 additions and 71 deletions

View file

@ -52,7 +52,7 @@ impl Actor for Cd {
tab.history.insert(rep.url.to_owned(), rep); tab.history.insert(rep.url.to_owned(), rep);
// Parent // Parent
if let Some(parent) = opt.target.parent_url() { if let Some(parent) = opt.target.parent() {
tab.parent = Some(tab.history.remove_or(&parent)); tab.parent = Some(tab.history.remove_or(&parent));
} }
@ -83,7 +83,7 @@ impl Cd {
return MgrProxy::cd(&url); return MgrProxy::cd(&url);
} }
if let Some(p) = url.parent_url() { if let Some(p) = url.parent() {
FilesOp::Upserting(p.into(), [(url.urn().to_owned(), file)].into()).emit(); FilesOp::Upserting(p.into(), [(url.urn().to_owned(), file)].into()).emit();
} }
MgrProxy::reveal(&url); MgrProxy::reveal(&url);

View file

@ -33,7 +33,7 @@ impl Actor for Copy {
s.push(opt.separator.transform(&u.os_str())); s.push(opt.separator.transform(&u.os_str()));
} }
"dirname" => { "dirname" => {
if let Some(p) = u.parent_url() { if let Some(p) = u.parent() {
s.push(opt.separator.transform(&p.os_str())); s.push(opt.separator.transform(&p.os_str()));
} }
} }

View file

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

View file

@ -17,7 +17,7 @@ impl Actor for Follow {
let Some(file) = cx.hovered() else { succ!() }; let Some(file) = cx.hovered() else { succ!() };
let Some(link_to) = &file.link_to else { succ!() }; let Some(link_to) = &file.link_to else { succ!() };
if let Some(p) = file.url.parent_url() { if let Some(p) = file.url.parent() {
act!(mgr:reveal, cx, clean_url(p.join(link_to))) act!(mgr:reveal, cx, clean_url(p.join(link_to)))
} else { } else {
succ!() succ!()

View file

@ -15,9 +15,9 @@ impl Actor for Leave {
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> { fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
let url = cx let url = cx
.hovered() .hovered()
.and_then(|h| h.url.parent_url()) .and_then(|h| h.url.parent())
.filter(|u| u != cx.cwd()) .filter(|u| u != cx.cwd())
.or_else(|| cx.cwd().parent_url()); .or_else(|| cx.cwd().parent());
let Some(mut url) = url else { succ!() }; let Some(mut url) = url else { succ!() };
if url.is_search() { if url.is_search() {

View file

@ -111,7 +111,7 @@ impl Actor for OpenDo {
impl Open { impl Open {
fn guess_folder(cx: &Ctx, url: &UrlBuf) -> bool { fn guess_folder(cx: &Ctx, url: &UrlBuf) -> bool {
let Some(p) = url.parent_url() else { let Some(p) = url.parent() else {
return true; return true;
}; };

View file

@ -48,7 +48,7 @@ impl Actor for Rename {
return; return;
} }
let new = old.parent_url().unwrap().join(name); let new = old.parent().unwrap().join(name);
if opt.force || !maybe_exists(&new).await || provider::must_identical(&old, &new).await { if opt.force || !maybe_exists(&new).await || provider::must_identical(&old, &new).await {
Self::r#do(tab, old, new).await.ok(); Self::r#do(tab, old, new).await.ok();
} else if ConfirmProxy::show(ConfirmCfg::overwrite(&new)).await { } else if ConfirmProxy::show(ConfirmCfg::overwrite(&new)).await {
@ -72,7 +72,7 @@ impl Rename {
&& let Some((parent, urn)) = u.pair() && let Some((parent, urn)) = u.pair()
{ {
ok_or_not_found(provider::rename(&u, &new).await)?; ok_or_not_found(provider::rename(&u, &new).await)?;
FilesOp::Deleting(parent.to_owned(), [urn].into()).emit(); FilesOp::Deleting(parent.to_owned(), [urn.into()].into()).emit();
} }
let new = provider::casefold(&new).await?; let new = provider::casefold(&new).await?;
@ -80,10 +80,10 @@ impl Rename {
let file = File::new(&new).await?; let file = File::new(&new).await?;
if new_p == old_p { if new_p == old_p {
FilesOp::Upserting(old_p.into(), [(old_n, file)].into()).emit(); FilesOp::Upserting(old_p.into(), [(old_n.into(), file)].into()).emit();
} else { } else {
FilesOp::Deleting(old_p.into(), [old_n].into()).emit(); FilesOp::Deleting(old_p.into(), [old_n.into()].into()).emit();
FilesOp::Upserting(new_p.into(), [(new_n, file)].into()).emit(); FilesOp::Upserting(new_p.into(), [(new_n.into(), file)].into()).emit();
} }
MgrProxy::reveal(&new); MgrProxy::reveal(&new);

View file

@ -21,17 +21,17 @@ impl Actor for Reveal {
// Try to hover on the child file // Try to hover on the child file
let tab = cx.tab_mut(); let tab = cx.tab_mut();
render!(tab.current.hover(child.as_urn())); render!(tab.current.hover(child));
// If the child is not hovered, which means it doesn't exist, // If the child is not hovered, which means it doesn't exist,
// create a dummy file // create a dummy file
if !opt.no_dummy && tab.hovered().is_none_or(|f| &child != f.urn()) { if !opt.no_dummy && tab.hovered().is_none_or(|f| child != f.urn()) {
let op = FilesOp::Creating(parent.into(), vec![File::from_dummy(opt.target, None)]); let op = FilesOp::Creating(parent.into(), vec![File::from_dummy(&opt.target, None)]);
tab.current.update_pub(tab.id, op); tab.current.update_pub(tab.id, op);
} }
// Now, we can safely hover on the target // Now, we can safely hover on the target
act!(mgr:hover, cx, Some(child))?; act!(mgr:hover, cx, Some(child.into()))?;
act!(mgr:peek, cx)?; act!(mgr:peek, cx)?;
act!(mgr:watch, cx)?; act!(mgr:watch, cx)?;

View file

@ -101,7 +101,7 @@ impl UpdateFiles {
fn update_history(cx: &mut Ctx, op: FilesOp) -> Result<Data> { fn update_history(cx: &mut Ctx, op: FilesOp) -> Result<Data> {
let tab = &mut cx.tab_mut(); let tab = &mut cx.tab_mut();
let leave = tab.parent.as_ref().and_then(|f| f.url.parent_url().map(|p| (p, f.url.urn()))).is_some_and( let leave = tab.parent.as_ref().and_then(|f| f.url.parent().map(|p| (p, f.url.urn()))).is_some_and(
|(p, n)| matches!(op, FilesOp::Deleting(ref parent, ref urns) if *parent == p && urns.contains(n)), |(p, n)| matches!(op, FilesOp::Deleting(ref parent, ref urns) if *parent == p && urns.contains(n)),
); );

View file

@ -102,7 +102,7 @@ impl UserData for Url {
cached_field!(fields, ext, |lua, me| { cached_field!(fields, ext, |lua, me| {
me.ext().map(|s| lua.create_string(s.as_encoded_bytes())).transpose() me.ext().map(|s| lua.create_string(s.as_encoded_bytes())).transpose()
}); });
cached_field!(fields, parent, |_, me| Ok(me.parent_url().map(Self::new))); cached_field!(fields, parent, |_, me| Ok(me.parent().map(Self::new)));
cached_field!(fields, urn, |_, me| Ok(Urn::new(me.urn()))); cached_field!(fields, urn, |_, me| Ok(Urn::new(me.urn())));
cached_field!(fields, base, |_, me| Ok(me.base().map(Self::new))); cached_field!(fields, base, |_, me| Ok(me.base().map(Self::new)));
cached_field!(fields, domain, |lua, me| { cached_field!(fields, domain, |lua, me| {

View file

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

View file

@ -34,10 +34,10 @@ pub async fn copy_and_seal(from: &Path, to: &Path) -> io::Result<()> {
pub async fn remove_sealed(p: &Path) -> io::Result<()> { pub async fn remove_sealed(p: &Path) -> io::Result<()> {
#[cfg(windows)] #[cfg(windows)]
{ {
let mut perm = tokio::fs::metadata(p).await?.permissions(); let mut perm = Local::metadata(p).await?.permissions();
perm.set_readonly(false); perm.set_readonly(false);
tokio::fs::set_permissions(p, perm).await?; tokio::fs::set_permissions(p, perm).await?;
} }
tokio::fs::remove_file(p).await Local::remove_file(p).await
} }

View file

@ -51,7 +51,7 @@ impl Yanked {
let mut it = u.components(); let mut it = u.components();
it.next_back().is_some() it.next_back().is_some()
&& it.covariant(&dir.components()) && it.covariant(&dir.components())
&& u.parent_url().is_some_and(|p| p == *dir) && u.parent().is_some_and(|p| p == *dir)
}) })
} }

View file

@ -35,10 +35,9 @@ impl Selected {
T: Into<Url<'a>>, T: Into<Url<'a>>,
{ {
let mut grouped: HashMap<_, Vec<_>> = Default::default(); let mut grouped: HashMap<_, Vec<_>> = Default::default();
for url in urls { for url in urls.into_iter().map(Into::into) {
let u = url.into(); if let Some(p) = url.parent() {
if let Some(p) = u.parent_url() { grouped.entry(p).or_default().push(url);
grouped.entry(p).or_default().push(u);
} }
} }
grouped.into_values().map(|v| self.add_same(v)).sum() grouped.into_values().map(|v| self.add_same(v)).sum()
@ -57,14 +56,14 @@ impl Selected {
} }
// If it has appeared as a child // If it has appeared as a child
let mut parent = urls[0].parent_url(); let mut parent = urls[0].parent();
let mut parents = vec![]; let mut parents = vec![];
while let Some(u) = parent { while let Some(u) = parent {
if self.inner.contains_key(&UrlCov::new(&u)) { if self.inner.contains_key(&UrlCov::new(&u)) {
return 0; return 0;
} }
parent = u.parent_url(); parent = u.parent();
parents.push(u); parents.push(u);
} }
@ -88,10 +87,9 @@ impl Selected {
T: Into<Url<'a>>, T: Into<Url<'a>>,
{ {
let mut grouped: HashMap<_, Vec<_>> = Default::default(); let mut grouped: HashMap<_, Vec<_>> = Default::default();
for url in urls { for url in urls.into_iter().map(Into::into) {
let u = url.into(); if let Some(p) = url.parent() {
if let Some(p) = u.parent_url() { grouped.entry(p).or_default().push(url);
grouped.entry(p).or_default().push(u);
} }
} }
@ -116,8 +114,8 @@ impl Selected {
return 0; return 0;
} }
// FIXME: use UrlCov::parent_url() instead // FIXME: use UrlCov::parent() instead
let mut parent = first.parent_url(); let mut parent = first.parent();
while let Some(u) = parent { while let Some(u) = parent {
let n = self.parents.get_mut(&UrlCov::new(&u)).unwrap(); let n = self.parents.get_mut(&UrlCov::new(&u)).unwrap();
@ -126,7 +124,7 @@ impl Selected {
self.parents.remove(&UrlCov::new(&u)); self.parents.remove(&UrlCov::new(&u));
} }
parent = u.parent_url(); parent = u.parent();
} }
count count
} }

View file

@ -1,5 +1,3 @@
// FIXME: VFS
use anyhow::Result; use anyhow::Result;
use tokio::{io, select, sync::{mpsc, oneshot}, time}; use tokio::{io, select, sync::{mpsc, oneshot}, time};
use yazi_shared::url::{Component, Url, UrlBuf}; use yazi_shared::url::{Component, Url, UrlBuf};
@ -159,7 +157,7 @@ pub fn max_common_root(urls: &[UrlBuf]) -> usize {
return urls[0].components().count() - 1; return urls[0].components().count() - 1;
} }
let mut it = urls.iter().map(|u| u.parent_url()); let mut it = urls.iter().map(|u| u.parent());
let Some(first) = it.next().unwrap() else { let Some(first) = it.next().unwrap() else {
return 0; // The first URL has no parent return 0; // The first URL has no parent
}; };

View file

@ -54,8 +54,8 @@ impl FilesOp {
pub fn rename(map: HashMap<UrlBuf, File>) { pub fn rename(map: HashMap<UrlBuf, File>) {
let mut parents: HashMap<_, (HashSet<_>, HashMap<_, _>)> = Default::default(); let mut parents: HashMap<_, (HashSet<_>, HashMap<_, _>)> = Default::default();
for (o, n) in map { for (o, n) in map {
let Some(o_p) = o.parent_url() else { continue }; let Some(o_p) = o.parent() else { continue };
let Some(n_p) = n.url.parent_url() else { continue }; let Some(n_p) = n.url.parent() else { continue };
if o_p != n_p { if o_p != n_p {
parents.entry_ref(&o_p).or_default().0.insert(o.urn().to_owned()); parents.entry_ref(&o_p).or_default().0.insert(o.urn().to_owned());
} }
@ -126,7 +126,7 @@ impl FilesOp {
} else if maybe_exists(cwd).await { } else if maybe_exists(cwd).await {
Self::IOErr(cwd.clone(), kind).emit(); Self::IOErr(cwd.clone(), kind).emit();
} else if let Some((p, n)) = cwd.pair() { } else if let Some((p, n)) = cwd.pair() {
Self::Deleting(p.into(), [n].into()).emit(); Self::Deleting(p.into(), [n.into()].into()).emit();
} }
} }

View file

@ -11,7 +11,7 @@ impl Utils {
pub(super) fn file_cache(lua: &Lua) -> mlua::Result<Function> { pub(super) fn file_cache(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|_, t: Table| { lua.create_function(|_, t: Table| {
let file: FileRef = t.raw_get("file")?; let file: FileRef = t.raw_get("file")?;
if file.url.parent_url() == Some(yazi_shared::url::Url::regular(&YAZI.preview.cache_dir)) { if file.url.parent() == Some(yazi_shared::url::Url::regular(&YAZI.preview.cache_dir)) {
return Ok(None); return Ok(None);
} }

View file

@ -77,7 +77,7 @@ impl File {
}; };
let src = if task.relative { let src = if task.relative {
path_relative_to(provider::canonicalize(&task.to.parent_url().unwrap()).await?.loc, &src)? path_relative_to(provider::canonicalize(&task.to.parent().unwrap()).await?.loc, &src)?
} else { } else {
src src
}; };

View file

@ -90,7 +90,7 @@ impl Prework {
} }
} }
let parent = buf[0].0.parent_url().unwrap(); let parent = buf[0].0.parent().unwrap();
FilesOp::Size( FilesOp::Size(
parent.into(), parent.into(),
HashMap::from_iter(buf.into_iter().map(|(u, s)| (u.urn().to_owned(), s))), HashMap::from_iter(buf.into_iter().map(|(u, s)| (u.urn().to_owned(), s))),

View file

@ -3,7 +3,6 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::BuildHasher, p
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::UrnBuf;
use crate::{loc::LocBuf, pool::Pool, url::{Components, Display, Encode, EncodeTilded, Scheme, Uri, Url, UrlCow, Urn}}; use crate::{loc::LocBuf, pool::Pool, url::{Components, Display, Encode, EncodeTilded, Scheme, Uri, Url, UrlCow, Urn}};
#[derive(Clone, Default, Eq, Ord, PartialOrd, PartialEq, Hash)] #[derive(Clone, Default, Eq, Ord, PartialOrd, PartialEq, Hash)]
@ -96,7 +95,7 @@ impl UrlBuf {
pub fn covariant(&self, other: &Self) -> bool { self.as_url().covariant(other) } pub fn covariant(&self, other: &Self) -> bool { self.as_url().covariant(other) }
#[inline] #[inline]
pub fn parent_url(&self) -> Option<Url<'_>> { self.as_url().parent_url() } pub fn parent(&self) -> Option<Url<'_>> { self.as_url().parent() }
#[inline] #[inline]
pub fn starts_with<'a>(&self, base: impl Into<Url<'a>>) -> bool { pub fn starts_with<'a>(&self, base: impl Into<Url<'a>>) -> bool {
@ -156,7 +155,7 @@ impl UrlBuf {
} }
#[inline] #[inline]
pub fn pair(&self) -> Option<(Url<'_>, UrnBuf)> { self.as_url().pair() } pub fn pair(&self) -> Option<(Url<'_>, &Urn)> { self.as_url().pair() }
#[inline] #[inline]
pub fn hash_u64(&self) -> u64 { foldhash::fast::FixedState::default().hash_one(self) } pub fn hash_u64(&self) -> u64 { foldhash::fast::FixedState::default().hash_one(self) }
@ -312,7 +311,7 @@ mod tests {
} }
#[test] #[test]
fn test_parent_url() -> anyhow::Result<()> { fn test_parent() -> anyhow::Result<()> {
crate::init_tests(); crate::init_tests();
let cases = [ let cases = [
// Regular // Regular
@ -339,7 +338,7 @@ mod tests {
for (path, expected) in cases { for (path, expected) in cases {
let path: UrlBuf = path.parse()?; let path: UrlBuf = path.parse()?;
assert_eq!(path.parent_url().map(|u| format!("{:?}", u)).as_deref(), expected); assert_eq!(path.parent().map(|u| format!("{:?}", u)).as_deref(), expected);
} }
Ok(()) Ok(())
@ -355,7 +354,7 @@ mod tests {
let u = u.into_search("kw"); let u = u.into_search("kw");
assert_eq!(format!("{u:?}"), "search://kw//root"); assert_eq!(format!("{u:?}"), "search://kw//root");
assert_eq!(format!("{:?}", u.parent_url().unwrap()), "/"); assert_eq!(format!("{:?}", u.parent().unwrap()), "/");
let u = u.join("examples"); let u = u.join("examples");
assert_eq!(format!("{u:?}"), format!("search://kw:1:1//root{S}examples")); assert_eq!(format!("{u:?}"), format!("search://kw:1:1//root{S}examples"));
@ -363,13 +362,13 @@ mod tests {
let u = u.join("README.md"); let u = u.join("README.md");
assert_eq!(format!("{u:?}"), format!("search://kw:2:2//root{S}examples{S}README.md")); assert_eq!(format!("{u:?}"), format!("search://kw:2:2//root{S}examples{S}README.md"));
let u = u.parent_url().unwrap(); let u = u.parent().unwrap();
assert_eq!(format!("{u:?}"), format!("search://kw:1:1//root{S}examples")); assert_eq!(format!("{u:?}"), format!("search://kw:1:1//root{S}examples"));
let u = u.parent_url().unwrap(); let u = u.parent().unwrap();
assert_eq!(format!("{u:?}"), "search://kw//root"); assert_eq!(format!("{u:?}"), "search://kw//root");
let u = u.parent_url().unwrap(); let u = u.parent().unwrap();
assert_eq!(format!("{u:?}"), "/"); assert_eq!(format!("{u:?}"), "/");
Ok(()) Ok(())

View file

@ -95,5 +95,5 @@ impl UrlBufCov {
pub fn as_url(&self) -> UrlCov<'_> { UrlCov::from(self) } pub fn as_url(&self) -> UrlCov<'_> { UrlCov::from(self) }
#[inline] #[inline]
pub fn parent_url(&self) -> Option<UrlBufCov> { self.0.parent_url().map(Into::into) } pub fn parent(&self) -> Option<UrlBufCov> { self.0.parent().map(Into::into) }
} }

View file

@ -3,7 +3,7 @@ use std::{borrow::Cow, path::{Path, PathBuf}};
use anyhow::Result; use anyhow::Result;
use percent_encoding::percent_decode; use percent_encoding::percent_decode;
use crate::{IntoOsStr, loc::{Loc, LocBuf}, url::{Components, Scheme, Url, UrlBuf, UrnBuf}}; use crate::{IntoOsStr, loc::{Loc, LocBuf}, url::{Components, Scheme, Url, UrlBuf, Urn}};
#[derive(Debug)] #[derive(Debug)]
pub enum UrlCow<'a> { pub enum UrlCow<'a> {
@ -35,6 +35,10 @@ impl From<UrlCow<'_>> for UrlBuf {
fn from(value: UrlCow<'_>) -> Self { value.into_owned() } fn from(value: UrlCow<'_>) -> Self { value.into_owned() }
} }
impl From<&UrlCow<'_>> for UrlBuf {
fn from(value: &UrlCow<'_>) -> Self { value.as_url().into() }
}
impl<'a> TryFrom<&'a [u8]> for UrlCow<'a> { impl<'a> TryFrom<&'a [u8]> for UrlCow<'a> {
type Error = anyhow::Error; type Error = anyhow::Error;
@ -107,6 +111,7 @@ impl UrlCow<'_> {
} }
} }
#[inline]
pub fn as_url(&self) -> Url<'_> { pub fn as_url(&self) -> Url<'_> {
match self { match self {
UrlCow::Borrowed(u) => u.as_url(), UrlCow::Borrowed(u) => u.as_url(),
@ -115,13 +120,18 @@ impl UrlCow<'_> {
} }
#[inline] #[inline]
pub fn into_owned(self) -> UrlBuf { self.as_url().into() } pub fn into_owned(self) -> UrlBuf {
match self {
UrlCow::Borrowed(u) => u.into(),
UrlCow::Owned(u) => u,
}
}
#[inline] #[inline]
pub fn parent_url(&self) -> Option<Url<'_>> { self.as_url().parent_url() } pub fn parent(&self) -> Option<Url<'_>> { self.as_url().parent() }
#[inline] #[inline]
pub fn pair(&self) -> Option<(Url<'_>, UrnBuf)> { self.as_url().pair() } pub fn pair(&self) -> Option<(Url<'_>, &Urn)> { self.as_url().pair() }
pub fn parse(bytes: &[u8]) -> Result<(Scheme, Cow<'_, Path>, Option<(usize, usize)>)> { pub fn parse(bytes: &[u8]) -> Result<(Scheme, Cow<'_, Path>, Option<(usize, usize)>)> {
let mut skip = 0; let mut skip = 0;

View file

@ -162,7 +162,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_decode_port() -> Result<()> { fn test_decode_ports() -> Result<()> {
fn assert(s: &str, len: usize, uri: Option<usize>, urn: Option<usize>) -> Result<()> { fn assert(s: &str, len: usize, uri: Option<usize>, urn: Option<usize>) -> Result<()> {
let mut n = usize::MAX; let mut n = usize::MAX;
let port = Scheme::decode_ports(s.as_bytes(), &mut n)?; let port = Scheme::decode_ports(s.as_bytes(), &mut n)?;

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::Path};
use hashbrown::Equivalent; use hashbrown::Equivalent;
use crate::{loc::{Loc, LocBuf}, url::{Components, Encode, Scheme, Uri, UrlBuf, Urn, UrnBuf}}; use crate::{loc::{Loc, LocBuf}, url::{Components, Encode, Scheme, Uri, UrlBuf, Urn}};
#[derive(Clone, Eq, Hash, PartialEq)] #[derive(Clone, Eq, Hash, PartialEq)]
pub struct Url<'a> { pub struct Url<'a> {
@ -121,7 +121,7 @@ impl<'a> Url<'a> {
}) })
} }
pub fn parent_url(&self) -> Option<Self> { pub fn parent(&self) -> Option<Self> {
use Scheme as S; use Scheme as S;
let parent = self.loc.parent()?; let parent = self.loc.parent()?;
@ -177,9 +177,7 @@ impl<'a> Url<'a> {
} }
#[inline] #[inline]
pub fn pair(&self) -> Option<(Url<'a>, UrnBuf)> { pub fn pair(&self) -> Option<(Url<'a>, &'a Urn)> { Some((self.parent()?, self.loc.urn())) }
Some((self.parent_url()?, self.loc.urn().to_owned()))
}
#[inline] #[inline]
pub fn as_path(&self) -> Option<&'a Path> { pub fn as_path(&self) -> Option<&'a Path> {

View file

@ -51,7 +51,7 @@ impl Backend {
{ {
let (mut todo, watched) = (HashSet::new(), WATCHED.read()); let (mut todo, watched) = (HashSet::new(), WATCHED.read());
for url in urls.into_iter().map(Into::into) { for url in urls.into_iter().map(Into::into) {
let Some(parent) = url.parent_url() else { continue }; let Some(parent) = url.parent() else { continue };
if todo.contains(&parent) { if todo.contains(&parent) {
todo.insert(url); todo.insert(url);
} else if watched.contains(&parent) } else if watched.contains(&parent)

View file

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