Skip to content

Commit 7911d53

Browse files
committed
feat!: Use yarn for lower memory footprint and better performance.
However, this also removes `serde` support for now.
1 parent 9c528dc commit 7911d53

File tree

9 files changed

+48
-44
lines changed

9 files changed

+48
-44
lines changed

Cargo.lock

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

gix-attributes/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ doctest = false
1414

1515
[features]
1616
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
17-
serde = ["dep:serde", "bstr/serde", "gix-glob/serde", "kstring/serde"]
17+
serde = ["dep:serde", "bstr/serde", "gix-glob/serde"]
1818

1919
[dependencies]
2020
gix-path = { version = "^0.10.0", path = "../gix-path" }
@@ -24,7 +24,7 @@ gix-trace = { version = "^0.1.3", path = "../gix-trace" }
2424

2525
bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"]}
2626
smallvec = "1.10.0"
27-
kstring = "2.0.0"
27+
byteyarn = "0.2.3"
2828
unicode-bom = "2.0.2"
2929
thiserror = "1.0.26"
3030
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}

gix-attributes/src/lib.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
99
#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
1010

11+
use byteyarn::{Yarn, YarnRef};
1112
pub use gix_glob as glob;
12-
use kstring::{KString, KStringRef};
1313

1414
mod assignment;
1515
///
@@ -34,15 +34,13 @@ pub fn parse(bytes: &[u8]) -> parse::Lines<'_> {
3434
///
3535
/// Note that this doesn't contain the name.
3636
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
37-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3837
pub enum StateRef<'a> {
3938
/// The attribute is listed, or has the special value 'true'
4039
Set,
4140
/// The attribute has the special value 'false', or was prefixed with a `-` sign.
4241
Unset,
4342
/// The attribute is set to the given value, which followed the `=` sign.
4443
/// Note that values can be empty.
45-
#[cfg_attr(feature = "serde", serde(borrow))]
4644
Value(state::ValueRef<'a>),
4745
/// The attribute isn't mentioned with a given path or is explicitly set to `Unspecified` using the `!` sign.
4846
Unspecified,
@@ -52,7 +50,6 @@ pub enum StateRef<'a> {
5250
///
5351
/// Note that this doesn't contain the name.
5452
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
55-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5653
pub enum State {
5754
/// The attribute is listed, or has the special value 'true'
5855
Set,
@@ -67,16 +64,14 @@ pub enum State {
6764

6865
/// Represents a validated attribute name
6966
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
70-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71-
pub struct Name(pub(crate) KString);
67+
pub struct Name(pub(crate) Yarn);
7268

7369
/// Holds a validated attribute name as a reference
7470
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
75-
pub struct NameRef<'a>(KStringRef<'a>);
71+
pub struct NameRef<'a>(YarnRef<'a, str>);
7672

7773
/// Name an attribute and describe it's assigned state.
7874
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
79-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8075
pub struct Assignment {
8176
/// The validated name of the attribute.
8277
pub name: Name,

gix-attributes/src/name.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use bstr::{BStr, BString, ByteSlice};
2-
use kstring::KStringRef;
2+
use byteyarn::YarnRef;
33

44
use crate::{Name, NameRef};
55

66
impl<'a> NameRef<'a> {
77
/// Turn this ref into its owned counterpart.
88
pub fn to_owned(self) -> Name {
9-
Name(self.0.into())
9+
Name(
10+
self.0
11+
.immortalize()
12+
.map_or_else(|| self.0.to_boxed_str().into(), YarnRef::to_box),
13+
)
1014
}
1115

1216
/// Return the inner `str`.
@@ -35,7 +39,7 @@ impl<'a> TryFrom<&'a BStr> for NameRef<'a> {
3539
}
3640

3741
attr_valid(attr)
38-
.then(|| NameRef(KStringRef::from_ref(attr.to_str().expect("no illformed utf8"))))
42+
.then(|| NameRef(YarnRef::from(attr.to_str().expect("no illformed utf8"))))
3943
.ok_or_else(|| Error { attribute: attr.into() })
4044
}
4145
}

gix-attributes/src/parse.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use std::borrow::Cow;
22

33
use bstr::{BStr, ByteSlice};
4-
use kstring::KStringRef;
4+
use byteyarn::YarnRef;
55

66
use crate::{name, AssignmentRef, Name, NameRef, StateRef};
77

88
/// The kind of attribute that was parsed.
99
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
10-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1110
pub enum Kind {
1211
/// A pattern to match paths against
1312
Pattern(gix_glob::Pattern),
@@ -76,7 +75,7 @@ fn check_attr(attr: &BStr) -> Result<NameRef<'_>, name::Error> {
7675
}
7776

7877
attr_valid(attr)
79-
.then(|| NameRef(KStringRef::from_ref(attr.to_str().expect("no illformed utf8"))))
78+
.then(|| NameRef(YarnRef::from(attr.to_str().expect("no illformed utf8"))))
8079
.ok_or_else(|| name::Error { attribute: attr.into() })
8180
}
8281

gix-attributes/src/search/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::collections::HashMap;
22

3-
use kstring::KString;
3+
use byteyarn::Yarn;
44
use smallvec::SmallVec;
55

66
use crate::{Assignment, AssignmentRef};
@@ -99,7 +99,7 @@ pub struct Outcome {
9999
/// A stack of attributes to use for processing attributes of matched patterns and for resolving their macros.
100100
attrs_stack: SmallVec<[(AttributeId, Assignment, Option<AttributeId>); 8]>,
101101
/// A set of attributes we should limit ourselves to, or empty if we should fill in all attributes, made of
102-
selected: SmallVec<[(KString, Option<AttributeId>); AVERAGE_NUM_ATTRS]>,
102+
selected: SmallVec<[(Yarn, Option<AttributeId>); AVERAGE_NUM_ATTRS]>,
103103
/// storage for all patterns we have matched so far (in order to avoid referencing them, we copy them, but only once).
104104
patterns: RefMap<gix_glob::Pattern>,
105105
/// storage for all assignments we have matched so far (in order to avoid referencing them, we copy them, but only once).
@@ -135,7 +135,7 @@ pub struct MetadataCollection {
135135
/// A mapping of an attribute or macro name to its order, that is the time when it was *first* seen.
136136
///
137137
/// This is the inverse of the order attributes are searched.
138-
name_to_meta: HashMap<KString, Metadata>,
138+
name_to_meta: HashMap<Yarn, Metadata>,
139139
}
140140

141141
/// Metadata associated with an attribute or macro name.

gix-attributes/src/search/outcome.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bstr::{BString, ByteSlice};
2+
use byteyarn::Yarn;
23
use gix_glob::Pattern;
3-
use kstring::{KString, KStringRef};
44

55
use crate::{
66
search::{
@@ -44,23 +44,23 @@ impl Outcome {
4444
pub fn initialize_with_selection<'a>(
4545
&mut self,
4646
collection: &MetadataCollection,
47-
attribute_names: impl IntoIterator<Item = impl Into<KStringRef<'a>>>,
47+
attribute_names: impl IntoIterator<Item = impl Into<&'a str>>,
4848
) {
4949
self.initialize_with_selection_inner(collection, &mut attribute_names.into_iter().map(Into::into))
5050
}
5151

5252
fn initialize_with_selection_inner(
5353
&mut self,
5454
collection: &MetadataCollection,
55-
attribute_names: &mut dyn Iterator<Item = KStringRef<'_>>,
55+
attribute_names: &mut dyn Iterator<Item = &str>,
5656
) {
5757
self.initialize(collection);
5858

5959
self.selected.clear();
6060
self.selected.extend(attribute_names.map(|name| {
6161
(
62-
name.to_owned(),
63-
collection.name_to_meta.get(name.as_str()).map(|meta| meta.id),
62+
Yarn::inlined(name).unwrap_or_else(|| name.to_string().into_boxed_str().into()),
63+
collection.name_to_meta.get(name).map(|meta| meta.id),
6464
)
6565
}));
6666
self.reset_remaining();
@@ -315,7 +315,7 @@ impl MetadataCollection {
315315
None => {
316316
let order = AttributeId(self.name_to_meta.len());
317317
self.name_to_meta.insert(
318-
KString::from_ref(name),
318+
Yarn::inlined(name).unwrap_or_else(|| name.to_string().into_boxed_str().into()),
319319
Metadata {
320320
id: order,
321321
macro_attributes: Default::default(),
@@ -335,7 +335,10 @@ impl MetadataCollection {
335335
Some(meta) => meta.id,
336336
None => {
337337
let order = AttributeId(self.name_to_meta.len());
338-
self.name_to_meta.insert(KString::from_ref(name), order.into());
338+
self.name_to_meta.insert(
339+
Yarn::inlined(name).unwrap_or_else(|| name.to_string().into_boxed_str().into()),
340+
order.into(),
341+
);
339342
order
340343
}
341344
}

gix-attributes/src/state.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
11
use bstr::{BStr, ByteSlice};
2-
use kstring::{KString, KStringRef};
2+
use byteyarn::{ByteYarn, YarnRef};
33

44
use crate::{State, StateRef};
55

66
/// A container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
77
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)]
8-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9-
pub struct Value(KString);
8+
pub struct Value(ByteYarn);
109

1110
/// A reference container to encapsulate a tightly packed and typically unallocated byte value that isn't necessarily UTF8 encoded.
1211
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
13-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14-
pub struct ValueRef<'a>(#[cfg_attr(feature = "serde", serde(borrow))] KStringRef<'a>);
12+
pub struct ValueRef<'a>(YarnRef<'a, [u8]>);
1513

1614
/// Lifecycle
1715
impl<'a> ValueRef<'a> {
1816
/// Keep `input` as our value.
1917
pub fn from_bytes(input: &'a [u8]) -> Self {
20-
Self(KStringRef::from_ref(
21-
// SAFETY: our API makes accessing that value as `str` impossible, so illformed UTF8 is never exposed as such.
22-
#[allow(unsafe_code)]
23-
unsafe {
24-
std::str::from_utf8_unchecked(input)
25-
},
26-
))
18+
Self(YarnRef::from(input))
2719
}
2820
}
2921

@@ -42,19 +34,25 @@ impl ValueRef<'_> {
4234

4335
impl<'a> From<&'a str> for ValueRef<'a> {
4436
fn from(v: &'a str) -> Self {
45-
ValueRef(v.into())
37+
ValueRef(v.as_bytes().into())
4638
}
4739
}
4840

4941
impl<'a> From<ValueRef<'a>> for Value {
5042
fn from(v: ValueRef<'a>) -> Self {
51-
Value(v.0.into())
43+
Value(
44+
v.0.immortalize()
45+
.map_or_else(|| v.0.to_boxed_bytes().into(), YarnRef::to_box),
46+
)
5247
}
5348
}
5449

5550
impl From<&str> for Value {
5651
fn from(v: &str) -> Self {
57-
Value(KString::from_ref(v))
52+
Value(
53+
ByteYarn::inlined(v.as_bytes())
54+
.unwrap_or_else(|| ByteYarn::from_boxed_bytes(v.as_bytes().to_vec().into_boxed_slice())),
55+
)
5856
}
5957
}
6058

gix-attributes/tests/search/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ fn given_attributes_are_made_available_in_given_order() -> crate::Result {
270270
fn size_of_outcome() {
271271
assert_eq!(
272272
std::mem::size_of::<Outcome>(),
273-
904,
273+
752,
274274
"it's quite big, shouldn't change without us noticing"
275275
)
276276
}

0 commit comments

Comments
 (0)