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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
mod iter;
pub use iter::*;
use crate::rawvalue::RawValue;
use crate::{PropertyKey, PropertyValue};
/// Map of property names to property values.
///
/// It features O(log n) lookup and preserves insertion order,
/// as well as convenience methods for type-safe access and parsing of values.
///
/// This structure is case-sensitive.
/// It's the caller's responsibility to ensure all keys and values are lowercased.
#[derive(Clone, Default)]
pub struct Properties {
// Don't use Cow<'static, str> here because it's actually less-optimal
// for the vastly more-common case of reading parsed properties.
// It's a micro-optimization anyway.
/// Key-value pairs, ordered from oldest to newest.
pairs: Vec<(String, RawValue)>,
/// Indices of `pairs`, ordered matching the key of the pair each index refers to.
/// This part is what allows logarithmic lookups.
idxes: Vec<usize>,
// Unfortunately, we hand out `&mut RawValue`s all over the place,
// so "no empty RawValues in Properties" cannot be made an invariant
// without breaking API changes.
}
// TODO: Deletion.
impl Properties {
/// Constructs a new empty [`Properties`].
pub const fn new() -> Properties {
Properties {
pairs: Vec::new(),
idxes: Vec::new(),
}
}
/// Returns the number of key-value pairs, including those with empty values.
pub fn len(&self) -> usize {
self.pairs.len()
}
/// Returns `true` if `self` contains no key-value pairs.
pub fn is_empty(&self) -> bool {
self.pairs.is_empty()
}
/// Returns either the index of the pair with the desired key in `pairs`,
/// or the index to insert a new index into `index`.
fn find_idx(&self, key: &str) -> Result<usize, usize> {
self.idxes
.as_slice()
.binary_search_by_key(&key, |ki| self.pairs[*ki].0.as_str())
.map(|idx| self.idxes[idx])
}
/// Returns the unparsed "raw" value for the specified key.
///
/// Does not test for the "unset" value. Use [`RawValue::filter_unset`].
pub fn get_raw_for_key(&self, key: impl AsRef<str>) -> &RawValue {
self.find_idx(key.as_ref())
.ok()
.map_or(&crate::rawvalue::UNSET, |idx| &self.pairs[idx].1)
}
/// Returns the unparsed "raw" value for the specified property.
///
/// Does not test for the "unset" value. Use [`RawValue::filter_unset`].
pub fn get_raw<T: PropertyKey>(&self) -> &RawValue {
self.get_raw_for_key(T::key())
}
/// Returns the parsed value for the specified property.
///
/// Does not test for the "unset" value if parsing fails. Use [`RawValue::filter_unset`].
pub fn get<T: PropertyKey + PropertyValue>(&self) -> Result<T, &RawValue> {
let retval = self.get_raw::<T>();
retval.parse::<T>().or(Err(retval))
}
/// Returns an iterator over the key-value pairs.
///
/// If the `allow-empty-values` feature is NOT used,
/// key-value pairs where the value is empty will be skipped.
/// Otherwise, they will be returned as normal.
///
/// Pairs are returned from oldest to newest.
pub fn iter(&self) -> Iter<'_> {
Iter(self.pairs.iter())
}
/// Returns an iterator over the key-value pairs that allows mutation of the values.
///
/// If the `allow-empty-values` feature is NOT used,
/// key-value pairs where the value is empty will be skipped.
/// Otherwise, they will be returned as normal.
///
/// Pairs are returned from oldest to newest.
pub fn iter_mut(&mut self) -> IterMut<'_> {
IterMut(self.pairs.iter_mut())
}
fn get_at_mut(&mut self, idx: usize) -> &mut RawValue {
&mut self.pairs.get_mut(idx).unwrap().1
}
fn insert_at(&mut self, idx: usize, key: String, val: RawValue) {
self.idxes.insert(idx, self.pairs.len());
self.pairs.push((key, val));
}
/// Sets the value for a specified key.
pub fn insert_raw_for_key(&mut self, key: impl AsRef<str>, val: impl Into<RawValue>) {
let key_str = key.as_ref();
match self.find_idx(key_str) {
Ok(idx) => {
*self.get_at_mut(idx) = val.into();
}
Err(idx) => {
self.insert_at(idx, key_str.to_owned(), val.into());
}
}
}
/// Sets the value for a specified property's key.
pub fn insert_raw<K: PropertyKey, V: Into<RawValue>>(&mut self, val: V) {
self.insert_raw_for_key(K::key(), val)
}
/// Inserts a specified property into the map.
pub fn insert<T: PropertyKey + Into<RawValue>>(&mut self, prop: T) {
self.insert_raw_for_key(T::key(), prop.into())
}
/// Attempts to add a new key-value pair to the map.
///
/// If the key was already associated with a value,
/// returns a mutable reference to the old value and does not update the map.
pub fn try_insert_raw_for_key(
&mut self,
key: impl AsRef<str>,
value: impl Into<RawValue>,
) -> Result<(), &mut RawValue> {
let key_str = key.as_ref();
#[allow(clippy::unit_arg)]
match self.find_idx(key_str) {
Ok(idx) => {
let valref = self.get_at_mut(idx);
if valref.is_unset() {
*valref = value.into();
Ok(())
} else {
Err(valref)
}
}
Err(idx) => Ok(self.insert_at(idx, key_str.to_owned(), value.into())),
}
}
/// Attempts to add a new property to the map with a specified value.
///
/// If the key was already associated with a value,
/// returns a mutable reference to the old value and does not update the map.
pub fn try_insert_raw<K: PropertyKey, V: Into<RawValue>>(
&mut self,
val: V,
) -> Result<(), &mut RawValue> {
self.try_insert_raw_for_key(K::key(), val)
}
/// Attempts to add a new property to the map.
///
/// If the key was already associated with a value,
/// returns a mutable reference to the old value and does not update the map.
pub fn try_insert<T: PropertyKey + Into<RawValue>>(
&mut self,
prop: T,
) -> Result<(), &mut RawValue> {
self.try_insert_raw_for_key(T::key(), prop.into())
}
/// Adds fallback values for certain common key-value pairs.
///
/// Used to obtain spec-compliant values for [`crate::property::IndentSize`]
/// and [`crate::property::TabWidth`].
pub fn use_fallbacks(&mut self) {
crate::fallback::add_fallbacks(self, false)
}
/// Adds pre-0.9.0 fallback values for certain common key-value pairs.
///
/// This shouldn't be used outside of narrow cases where
/// compatibility with those older standards is required.
/// Prefer [`Properties::use_fallbacks`] instead.
pub fn use_fallbacks_legacy(&mut self) {
crate::fallback::add_fallbacks(self, true)
}
}
impl PartialEq for Properties {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.idxes
.iter()
.zip(other.idxes.iter())
.all(|(idx_s, idx_o)| self.pairs[*idx_s] == other.pairs[*idx_o])
}
}
impl Eq for Properties {}
impl std::fmt::Debug for Properties {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Properties")
.field(&self.pairs.as_slice())
.finish()
}
}
impl<'a> IntoIterator for &'a Properties {
type Item = <Iter<'a> as Iterator>::Item;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Properties {
type Item = <IterMut<'a> as Iterator>::Item;
type IntoIter = IterMut<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<K: AsRef<str>, V: Into<RawValue>> FromIterator<(K, V)> for Properties {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut result = Properties::new();
result.extend(iter);
result
}
}
impl<K: AsRef<str>, V: Into<RawValue>> Extend<(K, V)> for Properties {
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
let iter = iter.into_iter();
let min_len = iter.size_hint().0;
self.pairs.reserve(min_len);
self.idxes.reserve(min_len);
for (k, v) in iter {
let k = k.as_ref();
let v = v.into();
self.insert_raw_for_key(k, v);
}
}
}
/// Trait for types that can add properties to a [`Properties`] map.
pub trait PropertiesSource {
/// Adds properties that apply to a file at the specified path
/// to the provided [`Properties`].
fn apply_to(
self,
props: &mut Properties,
path: impl AsRef<std::path::Path>,
) -> Result<(), crate::Error>;
}
impl<'a> PropertiesSource for &'a Properties {
fn apply_to(
self,
props: &mut Properties,
_: impl AsRef<std::path::Path>,
) -> Result<(), crate::Error> {
props.extend(self.pairs.iter().cloned());
Ok(())
}
}