forked from oven-sh/bun
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEnvPath.rs
More file actions
105 lines (88 loc) · 2.72 KB
/
Copy pathEnvPath.rs
File metadata and controls
105 lines (88 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use bun_alloc::AllocError;
use bun_core::strings;
use crate::DELIMITER;
fn trim_path_delimiters(input: &[u8]) -> &[u8] {
let mut trimmed = input;
while !trimmed.is_empty() && trimmed[0] == DELIMITER {
trimmed = &trimmed[1..];
}
while !trimmed.is_empty() && trimmed[trimmed.len() - 1] == DELIMITER {
trimmed = &trimmed[0..trimmed.len() - 1];
}
trimmed
}
#[derive(Default)]
pub struct EnvPath {
buf: Vec<u8>,
}
/// Input accepted by [`EnvPath::append`].
///
/// Raw slices are trimmed; anything else is assumed already-trimmed and has
/// `.slice()` called on it.
pub trait EnvPathInput {
fn as_trimmed(&self) -> &[u8];
}
impl EnvPathInput for [u8] {
fn as_trimmed(&self) -> &[u8] {
strings::without_trailing_slash(trim_path_delimiters(self))
}
}
// "assume already trimmed" — blanket over all const params so callers may pass
// any `&Path<u8, KIND, SEP, CHECK>` (e.g. `PathComponentBuilder.apply()`).
impl<const KIND: u8, const SEP_OPT: u8, const CHECK: u8> EnvPathInput
for crate::Path<u8, KIND, SEP_OPT, CHECK>
{
fn as_trimmed(&self) -> &[u8] {
self.slice()
}
}
impl EnvPath {
pub fn init() -> Self {
Self { buf: Vec::new() }
}
pub fn init_capacity(capacity: usize) -> Result<Self, AllocError> {
// `Vec::with_capacity` aborts on OOM under the global mimalloc allocator.
Ok(Self {
buf: Vec::with_capacity(capacity),
})
}
pub fn slice(&self) -> &[u8] {
self.buf.as_slice()
}
pub fn append<I: EnvPathInput + ?Sized>(&mut self, input: &I) -> Result<(), AllocError> {
let trimmed: &[u8] = input.as_trimmed();
if trimmed.is_empty() {
return Ok(());
}
if !self.buf.is_empty() {
self.buf.reserve(trimmed.len() + 1);
self.buf.push(DELIMITER);
self.buf.extend_from_slice(trimmed);
} else {
self.buf.extend_from_slice(trimmed);
}
Ok(())
}
pub fn path_component_builder(&mut self) -> PathComponentBuilder<'_> {
PathComponentBuilder {
env_path: self,
path_buf: crate::AutoAbsPath::init(),
}
}
}
pub struct PathComponentBuilder<'a> {
env_path: &'a mut EnvPath,
path_buf: crate::AutoAbsPath,
}
impl<'a> PathComponentBuilder<'a> {
pub fn append(&mut self, component: &[u8]) {
let _ = self.path_buf.append(component); // OOM/capacity: fire-and-forget
}
pub fn append_fmt(&mut self, args: core::fmt::Arguments<'_>) {
let _ = self.path_buf.append_fmt(args); // OOM/capacity: fire-and-forget
}
pub fn apply(self) -> Result<(), AllocError> {
self.env_path.append(&self.path_buf)?;
Ok(())
}
}