Skip to content

Commit 35eade3

Browse files
committed
nice
1 parent 5dc645c commit 35eade3

7 files changed

Lines changed: 108 additions & 29 deletions

File tree

Cargo.lock

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/astr/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ rust-version.workspace = true
66

77
[dependencies]
88
diesel.workspace = true
9+
stable_deref_trait = "1.2.1"
910
triomphe.workspace = true
1011

1112
[lints]

crates/astr/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
path::Path,
77
};
88

9+
use stable_deref_trait::StableDeref;
910
use triomphe::{Arc, HeaderWithLength};
1011

1112
mod diesel;
@@ -41,6 +42,8 @@ impl Deref for AStr {
4142
}
4243
}
4344

45+
unsafe impl StableDeref for AStr {}
46+
4447
impl Borrow<str> for AStr {
4548
#[inline]
4649
fn borrow(&self) -> &str {

crates/vfs/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ edition.workspace = true
77

88
[dependencies]
99
astr.workspace = true
10+
derive_more.workspace = true
11+
elsa = "1.11.2"
1012
indextree.workspace = true
1113
snafu.workspace = true
1214

crates/vfs/src/path.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use std::ops::Deref;
2+
13
use astr::AStr;
4+
use derive_more::Debug;
25

36
pub fn join(a: &str, b: impl AsRef<str> + Into<AStr>) -> AStr {
47
let b_ = b.as_ref();
@@ -11,16 +14,66 @@ pub fn join(a: &str, b: impl AsRef<str> + Into<AStr>) -> AStr {
1114
}
1215
}
1316

14-
pub fn file_name(path: &str) -> Option<&str> {
15-
path.trim_end_matches('/').rsplit('/').next()
17+
#[derive(Clone, Debug)]
18+
#[debug("{path:?}")]
19+
pub struct VfsPath {
20+
path: AStr,
21+
file_name_start_idx: u32,
22+
parent_end_idx: u32,
23+
}
24+
25+
impl VfsPath {
26+
pub fn new(path: AStr) -> Self {
27+
assert!(path.starts_with('/'));
28+
if path.len() > 1 {
29+
assert!(!path.ends_with('/'));
30+
}
31+
32+
let file_name_start_idx = (path.rfind('/').unwrap() + 1).try_into().unwrap();
33+
let parent_end_idx = if file_name_start_idx == 1 {
34+
1
35+
} else {
36+
file_name_start_idx - 1
37+
};
38+
Self {
39+
path,
40+
file_name_start_idx,
41+
parent_end_idx,
42+
}
43+
}
44+
45+
pub fn astr(&self) -> AStr {
46+
self.path.clone()
47+
}
48+
49+
pub fn file_name(&self) -> &str {
50+
&self.path[self.file_name_start_idx as usize..]
51+
}
52+
53+
pub fn parent(&self) -> Option<&str> {
54+
(self.path.len() > 1).then(|| &self.path[..self.parent_end_idx as usize])
55+
}
56+
}
57+
58+
impl Deref for VfsPath {
59+
type Target = str;
60+
61+
fn deref(&self) -> &Self::Target {
62+
&self.path
63+
}
64+
}
65+
66+
/*pub fn file_name(path: &str) -> Option<&str> {
67+
let (_, file_name) = path.trim_end_matches('/').rsplit_once('/')?;
68+
Some(file_name)
1669
}
1770
1871
pub fn parent(path: &str) -> Option<&str> {
1972
path.trim_end_matches('/').rsplit_once('/').map(|(parent, _)| {
2073
// We had to have split on a direct descendent of `/`
2174
if parent.is_empty() { "/" } else { parent }
2275
})
23-
}
76+
}*/
2477

2578
pub fn components(path: &str) -> impl Iterator<Item = &str> {
2679
path.starts_with('/')

crates/vfs/src/tree/builder.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use std::collections::BTreeMap;
77

88
use astr::AStr;
9+
use elsa::FrozenVec;
910

1011
use crate::path;
1112
use crate::tree::{Kind, Tree};
@@ -51,7 +52,7 @@ impl<T: BlitFile> TreeBuilder<T> {
5152
let file = File::new(item);
5253

5354
// Find all parent paths
54-
if let Some(parent) = &file.parent {
55+
if let Some(parent) = file.parent() {
5556
let mut leading_path: Option<AStr> = None;
5657
// Build a set of parent paths skipping `/`, yielding `usr`, `usr/bin`, etc.
5758
for component in path::components(parent) {
@@ -64,6 +65,7 @@ impl<T: BlitFile> TreeBuilder<T> {
6465
.insert(full_path.clone(), File::new(full_path.into()));
6566
}
6667
}
68+
6769
self.explicit.push(file);
6870
}
6971

@@ -73,7 +75,7 @@ impl<T: BlitFile> TreeBuilder<T> {
7375

7476
// Walk again to remove accidental dupes
7577
for i in self.explicit.iter() {
76-
self.implicit_dirs.remove(&i.path);
78+
self.implicit_dirs.remove(&*i.path);
7779
}
7880
}
7981

@@ -85,25 +87,27 @@ impl<T: BlitFile> TreeBuilder<T> {
8587
.iter()
8688
.filter(|f| matches!(f.kind, Kind::Directory))
8789
.chain(self.implicit_dirs.values())
88-
.map(|d| (&d.path, d))
90+
.map(|d| (&*d.path, d))
8991
.collect::<BTreeMap<_, _>>();
9092

9193
// build a set of redirects
94+
let scratch = FrozenVec::new();
9295
let mut redirects = BTreeMap::new();
9396

9497
// Resolve symlinks-to-dirs
9598
for link in self.explicit.iter() {
9699
if let Kind::Symlink(target) = &link.kind {
97100
// Resolve the link.
98101
let target = if target.starts_with('/') {
99-
target.clone()
100-
} else if let Some(parent) = &link.parent {
101-
path::join(parent, target)
102+
&**target
103+
} else if let Some(parent) = link.parent() {
104+
scratch.push(path::join(parent, target));
105+
scratch.last().unwrap()
102106
} else {
103-
target.clone()
107+
&**target
104108
};
105109
if all_dirs.contains_key(&target) {
106-
redirects.insert(&link.path, target);
110+
redirects.insert(&*link.path, target);
107111
}
108112
}
109113
}
@@ -123,14 +127,14 @@ impl<T: BlitFile> TreeBuilder<T> {
123127
// New node for this guy
124128
let node = tree.new_node(entry.clone());
125129

126-
if let Some(parent) = &entry.parent {
130+
if let Some(parent) = entry.parent() {
127131
tree.add_child_to_node(node, parent)?;
128132
}
129133
}
130134

131135
// Reparent any symlink redirects.
132136
for (source_tree, target_tree) in redirects {
133-
tree.reparent(source_tree, &target_tree)?;
137+
tree.reparent(source_tree, target_tree)?;
134138
}
135139
Ok(tree)
136140
}

crates/vfs/src/tree/mod.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use astr::AStr;
1212
use indextree::{Arena, Descendants, NodeId};
1313
use snafu::Snafu;
1414

15-
use crate::path;
15+
use crate::path::{self, VfsPath};
1616

1717
pub mod builder;
1818

@@ -44,28 +44,32 @@ pub trait BlitFile: Clone + Sized + Debug + From<AStr> {
4444
#[derive(Debug, Clone)]
4545
struct File<T> {
4646
id: AStr,
47-
path: AStr,
48-
file_name: Option<AStr>,
49-
parent: Option<AStr>,
47+
path: VfsPath,
5048
kind: Kind,
5149
inner: T,
5250
}
5351

5452
impl<T: BlitFile> File<T> {
5553
pub fn new(inner: T) -> Self {
56-
let path = inner.path();
57-
let file_name = path::file_name(&path).map(AStr::from);
58-
let parent = path::parent(&path).map(AStr::from);
54+
let path = VfsPath::new(inner.path());
5955

6056
Self {
6157
id: inner.id(),
6258
path,
63-
file_name,
64-
parent,
6559
kind: inner.kind(),
6660
inner,
6761
}
6862
}
63+
64+
#[inline]
65+
fn file_name(&self) -> &str {
66+
self.path.file_name()
67+
}
68+
69+
#[inline]
70+
fn parent(&self) -> Option<&str> {
71+
self.path.parent()
72+
}
6973
}
7074

7175
/// Actual tree implementation, encapsulating indextree
@@ -98,7 +102,7 @@ impl<T: BlitFile> Tree<T> {
98102

99103
/// Generate a new node, store the path mapping for it
100104
fn new_node(&mut self, data: File<T>) -> NodeId {
101-
let path = data.path.clone();
105+
let path = data.path.astr();
102106
let node = self.arena.new_node(data);
103107
self.map.insert(path, node);
104108
self.length += 1;
@@ -123,7 +127,7 @@ impl<T: BlitFile> Tree<T> {
123127
.children(&self.arena)
124128
.filter_map(|n| {
125129
let n = self.arena.get(n)?.get();
126-
if n.file_name == node.get().file_name {
130+
if n.file_name() == node.get().file_name() {
127131
Some(n)
128132
} else {
129133
None
@@ -132,7 +136,7 @@ impl<T: BlitFile> Tree<T> {
132136
.collect::<Vec<_>>();
133137
if !others.is_empty() {
134138
let e = Error::Duplicate {
135-
node_path: node.get().path.clone(),
139+
node_path: node.get().path.astr(),
136140
node_id: node.get().id.clone(),
137141
other_id: others.first().unwrap().id.clone(),
138142
};
@@ -186,7 +190,7 @@ impl<T: BlitFile> Tree<T> {
186190
Some(n) => *n,
187191
None => self.new_node(orphan.clone()),
188192
};
189-
if let Some(parent) = &orphan.parent {
193+
if let Some(parent) = orphan.parent() {
190194
self.add_child_to_node(node, parent)?;
191195
}
192196
}
@@ -211,7 +215,7 @@ impl<T: BlitFile> Tree<T> {
211215
fn structured_children(&self, start: &NodeId) -> Element<'_, T> {
212216
let node = &self.arena[*start];
213217
let item = node.get();
214-
let partial = item.file_name.as_deref().unwrap_or_default();
218+
let partial = item.file_name();
215219

216220
match item.kind {
217221
Kind::Directory => {

0 commit comments

Comments
 (0)