Skip to content

Commit 0c26f8b

Browse files
cijiugechuarcanis
andauthored
Use ecow as the representation for short, immutable strings (#211)
Extract a new crate that wraps `ecow` using the newtype pattern. --------- Co-authored-by: Maël Nison <nison.mael@gmail.com>
1 parent 31ae78a commit 0c26f8b

18 files changed

Lines changed: 1036 additions & 848 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ clipanion = { git = "https://github.com/arcanis/clipanion-rs.git", features = ["
4444
colored = "3.0.0"
4545
dialoguer = "0.11.0"
4646
divan = { version = "4.2.0", package = "codspeed-divan-compat" }
47+
ecow = "0.2.6"
4748
erased-serde = "0.4.6"
4849
env_logger = "0.11.8"
4950
fancy-regex = "0.13.0"

packages/zpm-primitives/src/ident.rs

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use std::{hash::Hash, str::FromStr, sync::LazyLock};
22

3-
use rkyv::Archive;
3+
use zpm_utils::EcoString;
4+
use rkyv::{
5+
Archive, Deserialize, DeserializeUnsized, Place, Serialize, SerializeUnsized,
6+
};
7+
use rkyv::rancor::{Fallible, Source};
8+
use rkyv::string::{ArchivedString, StringResolver};
49
use zpm_utils::{impl_file_string_from_str, impl_file_string_serialization, DataType, FromFileString, Path, ToFileString, ToHumanString};
510

611
#[derive(thiserror::Error, Clone, Debug)]
@@ -9,13 +14,40 @@ pub enum IdentError {
914
SyntaxError(String),
1015
}
1116

12-
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Archive, rkyv::Serialize, rkyv::Deserialize)]
13-
#[rkyv(derive(PartialEq, Eq, PartialOrd, Ord, Hash))]
14-
pub struct Ident(String);
17+
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
18+
pub struct Ident(EcoString);
19+
20+
impl Archive for Ident {
21+
type Archived = ArchivedString;
22+
type Resolver = StringResolver;
23+
24+
fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
25+
ArchivedString::resolve_from_str(self.0.as_str(), resolver, out);
26+
}
27+
}
28+
29+
impl<S: Fallible + ?Sized> Serialize<S> for Ident
30+
where
31+
S::Error: Source,
32+
str: SerializeUnsized<S>,
33+
{
34+
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
35+
ArchivedString::serialize_from_str(self.0.as_str(), serializer)
36+
}
37+
}
38+
39+
impl<D: Fallible + ?Sized> Deserialize<Ident, D> for ArchivedString
40+
where
41+
str: DeserializeUnsized<str, D>,
42+
{
43+
fn deserialize(&self, _: &mut D) -> Result<Ident, D::Error> {
44+
Ok(Ident(EcoString::from(self.as_str())))
45+
}
46+
}
1547

1648
impl Ident {
1749
pub fn new<P: AsRef<str>>(full: P) -> Ident {
18-
Ident(full.as_ref().to_string())
50+
Ident(EcoString::from(full.as_ref()))
1951
}
2052

2153
pub fn split(&self) -> (Option<&str>, &str) {
@@ -30,15 +62,15 @@ impl Ident {
3062
}
3163

3264
pub fn name(&self) -> &str {
33-
self.0.split_once('/').map(|(_, name)| name).unwrap_or(&self.0)
65+
self.0.split_once('/').map(|(_, name)| name).unwrap_or(self.0.as_str())
3466
}
3567

3668
pub fn as_str(&self) -> &str {
37-
&self.0
69+
self.0.as_str()
3870
}
3971

4072
pub fn slug(&self) -> String {
41-
self.0.replace("/", "-")
73+
self.0.replace("/", "-").into()
4274
}
4375

4476
pub fn nm_subdir(&self) -> Path {
@@ -55,7 +87,7 @@ impl Ident {
5587

5688
impl AsRef<str> for Ident {
5789
fn as_ref(&self) -> &str {
58-
&self.0
90+
self.0.as_str()
5991
}
6092
}
6193

@@ -100,3 +132,19 @@ impl ToHumanString for Ident {
100132

101133
impl_file_string_from_str!(Ident);
102134
impl_file_string_serialization!(Ident);
135+
136+
#[cfg(test)]
137+
mod tests {
138+
use super::Ident;
139+
140+
#[test]
141+
fn ident_rkyv_roundtrip() {
142+
let ident = Ident::new("@scope/name");
143+
let bytes =
144+
rkyv::to_bytes::<rkyv::rancor::BoxedError>(&ident).unwrap();
145+
let decoded =
146+
rkyv::from_bytes::<Ident, rkyv::rancor::BoxedError>(&bytes)
147+
.unwrap();
148+
assert_eq!(ident, decoded);
149+
}
150+
}

packages/zpm-primitives/src/range.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{hash::Hash, str::FromStr, sync::LazyLock};
22

3+
use zpm_utils::EcoString;
34
use regex::Regex;
45
use rkyv::Archive;
56
use zpm_macro_enum::zpm_enum;
@@ -85,11 +86,11 @@ pub enum Range {
8586
},
8687

8788
#[pattern(r"npm:(?:(?<ident>.*)@)?(?<tag>[-a-z0-9._^v][-a-z0-9._]*)")]
88-
#[to_file_string(|params| format_registry_tag(&params.ident, &params.tag))]
89-
#[to_print_string(|params| DataType::Range.colorize(&format_registry_tag(&params.ident, &params.tag)))]
89+
#[to_file_string(|params| format_registry_tag(&params.ident, params.tag.as_str()))]
90+
#[to_print_string(|params| DataType::Range.colorize(&format_registry_tag(&params.ident, params.tag.as_str())))]
9091
RegistryTag {
9192
ident: Option<Ident>,
92-
tag: String,
93+
tag: EcoString,
9394
},
9495

9596
#[pattern(r"link:(?<path>.*)")]
@@ -184,10 +185,10 @@ pub enum Range {
184185
},
185186

186187
#[pattern(r"(?<tag>.*)")]
187-
#[to_file_string(|params| params.tag.clone())]
188-
#[to_print_string(|params| DataType::Range.colorize(&params.tag))]
188+
#[to_file_string(|params| params.tag.as_str().to_string())]
189+
#[to_print_string(|params| DataType::Range.colorize(params.tag.as_str()))]
189190
AnonymousTag {
190-
tag: String,
191+
tag: EcoString,
191192
},
192193

193194
// We keep this at the end so virtual ranges are listed last when sorted

packages/zpm-semver/src/extract.rs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use zpm_utils::EcoVec;
2+
13
use super::{range::{OperatorType, Token, TokenType}, version::VersionRc, Version};
24
use crate::{
35
MAX_SAFE_COMPONENT_LENGTH,
@@ -73,11 +75,11 @@ pub fn extract_rc_segment(str: &mut std::iter::Peekable<std::str::Chars>) -> Opt
7375

7476
*str = curr;
7577

76-
Some(VersionRc::String(extract_alnum_hyphen(str)?))
78+
Some(VersionRc::String(extract_alnum_hyphen(str)?.into()))
7779
}
7880

79-
pub fn extract_rc(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<Vec<VersionRc>> {
80-
let mut segments = vec![];
81+
pub fn extract_rc(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<EcoVec<VersionRc>> {
82+
let mut segments = EcoVec::new();
8183

8284
segments.push(extract_rc_segment(str)?);
8385

@@ -145,7 +147,7 @@ pub fn extract_version(str: &mut std::iter::Peekable<std::str::Chars>) -> Option
145147
Some((Version::new_from_components(major, minor, patch, rc), missing))
146148
}
147149

148-
pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<Vec<Token>> {
150+
pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<EcoVec<Token>> {
149151
if let Some(c) = str.peek() {
150152
match c {
151153
'^' => {
@@ -162,7 +164,7 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
162164
_ => version.next_major_rc(),
163165
};
164166

165-
Some(vec![
167+
Some(EcoVec::from([
166168
Token::Operation(
167169
OperatorType::GreaterThanOrEqual,
168170
version,
@@ -172,7 +174,7 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
172174
OperatorType::LessThan,
173175
upper_bound,
174176
),
175-
])
177+
]))
176178
} else {
177179
None
178180
}
@@ -189,7 +191,7 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
189191
let next_minor
190192
= version.next_minor_rc();
191193

192-
Some(vec![
194+
Some(EcoVec::from([
193195
Token::Operation(
194196
OperatorType::GreaterThanOrEqual,
195197
version,
@@ -199,7 +201,7 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
199201
OperatorType::LessThan,
200202
next_minor,
201203
),
202-
])
204+
]))
203205
} else {
204206
None
205207
}
@@ -218,10 +220,10 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
218220
}
219221

220222
if let Some((version, _)) = extract_version(str) {
221-
Some(vec![Token::Operation(
223+
Some(EcoVec::from([Token::Operation(
222224
operator,
223225
version,
224-
)])
226+
)]))
225227
} else {
226228
None
227229
}
@@ -240,10 +242,10 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
240242
}
241243

242244
if let Some((version, _)) = extract_version(str) {
243-
Some(vec![Token::Operation(
245+
Some(EcoVec::from([Token::Operation(
244246
operator,
245247
version,
246-
)])
248+
)]))
247249
} else {
248250
None
249251
}
@@ -258,10 +260,10 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
258260
}
259261

260262
if let Some((version, _)) = extract_version(str) {
261-
Some(vec![Token::Operation(
263+
Some(EcoVec::from([Token::Operation(
262264
OperatorType::Equal,
263265
version,
264-
)])
266+
)]))
265267
} else {
266268
None
267269
}
@@ -280,7 +282,7 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
280282
}
281283

282284
return extract_version(str).map(|(other_version, _)| {
283-
vec![
285+
EcoVec::from([
284286
Token::Operation(
285287
OperatorType::GreaterThanOrEqual,
286288
version,
@@ -290,25 +292,25 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
290292
OperatorType::LessThan,
291293
other_version,
292294
),
293-
]
295+
])
294296
})
295297
}
296298
}
297299

298300
match missing {
299301
3 => {
300-
Some(vec![
302+
Some(EcoVec::from([
301303
Token::Operation(
302304
OperatorType::GreaterThanOrEqual,
303305
version,
304306
),
305-
])
307+
]))
306308
}
307309

308310
2 => {
309311
let next_major = version.next_major();
310312

311-
Some(vec![
313+
Some(EcoVec::from([
312314
Token::Operation(
313315
OperatorType::GreaterThanOrEqual,
314316
version,
@@ -318,13 +320,13 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
318320
OperatorType::LessThan,
319321
next_major,
320322
),
321-
])
323+
]))
322324
}
323325

324326
1 => {
325327
let next_minor = version.next_minor();
326328

327-
Some(vec![
329+
Some(EcoVec::from([
328330
Token::Operation(
329331
OperatorType::GreaterThanOrEqual,
330332
version,
@@ -334,14 +336,14 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
334336
OperatorType::LessThan,
335337
next_minor,
336338
),
337-
])
339+
]))
338340
}
339341

340342
0 => {
341-
Some(vec![Token::Operation(
343+
Some(EcoVec::from([Token::Operation(
342344
OperatorType::Equal,
343345
version,
344-
)])
346+
)]))
345347
}
346348

347349
_ => {
@@ -358,8 +360,8 @@ pub fn extract_predicate(str: &mut std::iter::Peekable<std::str::Chars>) -> Opti
358360
}
359361
}
360362

361-
pub fn extract_tokens(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<Vec<Token>> {
362-
let mut tokens = Vec::new();
363+
pub fn extract_tokens(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<EcoVec<Token>> {
364+
let mut tokens = EcoVec::new();
363365

364366
while let Some(c) = str.peek() {
365367
match c {
@@ -405,7 +407,7 @@ pub fn extract_tokens(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<
405407
tokens.push(Token::Syntax(TokenType::SAnd));
406408
}
407409

408-
tokens.extend(predicate);
410+
tokens.extend(predicate.into_iter());
409411
} else {
410412
return None;
411413
}
@@ -416,7 +418,7 @@ pub fn extract_tokens(str: &mut std::iter::Peekable<std::str::Chars>) -> Option<
416418
Some(tokens)
417419
}
418420

419-
pub fn infix_to_prefix(input: &[Token]) -> Option<Vec<Token>> {
421+
pub fn infix_to_prefix(input: &[Token]) -> Option<EcoVec<Token>> {
420422
let mut prefix = vec![];
421423
let mut stack = vec![];
422424

@@ -458,5 +460,5 @@ pub fn infix_to_prefix(input: &[Token]) -> Option<Vec<Token>> {
458460

459461
prefix.reverse();
460462

461-
Some(prefix)
463+
Some(EcoVec::from(prefix))
462464
}

0 commit comments

Comments
 (0)