1 use std::borrow::Cow;
2 use std::str::FromStr;
3
4 use crate::repr::{Decor, Repr};
5 use crate::InternalString;
6
7 /// Key as part of a Key/Value Pair or a table header.
8 ///
9 /// # Examples
10 ///
11 /// ```notrust
12 /// [dependencies."nom"]
13 /// version = "5.0"
14 /// 'literal key' = "nonsense"
15 /// "basic string key" = 42
16 /// ```
17 ///
18 /// There are 3 types of keys:
19 ///
20 /// 1. Bare keys (`version` and `dependencies`)
21 ///
22 /// 2. Basic quoted keys (`"basic string key"` and `"nom"`)
23 ///
24 /// 3. Literal quoted keys (`'literal key'`)
25 ///
26 /// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair).
27 ///
28 /// To parse a key use `FromStr` trait implementation: `"string".parse::<Key>()`.
29 #[derive(Debug)]
30 pub struct Key {
31 key: InternalString,
32 pub(crate) repr: Option<Repr>,
33 pub(crate) leaf_decor: Decor,
34 pub(crate) dotted_decor: Decor,
35 }
36
37 impl Key {
38 /// Create a new table key
new(key: impl Into<InternalString>) -> Self39 pub fn new(key: impl Into<InternalString>) -> Self {
40 Self {
41 key: key.into(),
42 repr: None,
43 leaf_decor: Default::default(),
44 dotted_decor: Default::default(),
45 }
46 }
47
48 /// Parse a TOML key expression
49 ///
50 /// Unlike `"".parse<Key>()`, this supports dotted keys.
51 #[cfg(feature = "parse")]
parse(repr: &str) -> Result<Vec<Self>, crate::TomlError>52 pub fn parse(repr: &str) -> Result<Vec<Self>, crate::TomlError> {
53 Self::try_parse_path(repr)
54 }
55
with_repr_unchecked(mut self, repr: Repr) -> Self56 pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self {
57 self.repr = Some(repr);
58 self
59 }
60
61 /// While creating the `Key`, add `Decor` to it
62 #[deprecated(since = "0.21.1", note = "Replaced with `with_leaf_decor`")]
with_decor(self, decor: Decor) -> Self63 pub fn with_decor(self, decor: Decor) -> Self {
64 self.with_leaf_decor(decor)
65 }
66
67 /// While creating the `Key`, add `Decor` to it for the line entry
with_leaf_decor(mut self, decor: Decor) -> Self68 pub fn with_leaf_decor(mut self, decor: Decor) -> Self {
69 self.leaf_decor = decor;
70 self
71 }
72
73 /// While creating the `Key`, add `Decor` to it for between dots
with_dotted_decor(mut self, decor: Decor) -> Self74 pub fn with_dotted_decor(mut self, decor: Decor) -> Self {
75 self.dotted_decor = decor;
76 self
77 }
78
79 /// Access a mutable proxy for the `Key`.
as_mut(&mut self) -> KeyMut<'_>80 pub fn as_mut(&mut self) -> KeyMut<'_> {
81 KeyMut { key: self }
82 }
83
84 /// Returns the parsed key value.
get(&self) -> &str85 pub fn get(&self) -> &str {
86 &self.key
87 }
88
get_internal(&self) -> &InternalString89 pub(crate) fn get_internal(&self) -> &InternalString {
90 &self.key
91 }
92
93 /// Returns key raw representation, if available.
as_repr(&self) -> Option<&Repr>94 pub fn as_repr(&self) -> Option<&Repr> {
95 self.repr.as_ref()
96 }
97
98 /// Returns the default raw representation.
99 #[cfg(feature = "display")]
default_repr(&self) -> Repr100 pub fn default_repr(&self) -> Repr {
101 to_key_repr(&self.key)
102 }
103
104 /// Returns a raw representation.
105 #[cfg(feature = "display")]
display_repr(&self) -> Cow<'_, str>106 pub fn display_repr(&self) -> Cow<'_, str> {
107 self.as_repr()
108 .and_then(|r| r.as_raw().as_str())
109 .map(Cow::Borrowed)
110 .unwrap_or_else(|| {
111 Cow::Owned(self.default_repr().as_raw().as_str().unwrap().to_owned())
112 })
113 }
114
115 /// Returns the surrounding whitespace
116 #[deprecated(
117 since = "0.21.1",
118 note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut"
119 )]
decor_mut(&mut self) -> &mut Decor120 pub fn decor_mut(&mut self) -> &mut Decor {
121 self.leaf_decor_mut()
122 }
123
124 /// Returns the surrounding whitespace for the line entry
leaf_decor_mut(&mut self) -> &mut Decor125 pub fn leaf_decor_mut(&mut self) -> &mut Decor {
126 &mut self.leaf_decor
127 }
128
129 /// Returns the surrounding whitespace for between dots
dotted_decor_mut(&mut self) -> &mut Decor130 pub fn dotted_decor_mut(&mut self) -> &mut Decor {
131 &mut self.dotted_decor
132 }
133
134 /// Returns the surrounding whitespace
135 #[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")]
decor(&self) -> &Decor136 pub fn decor(&self) -> &Decor {
137 self.leaf_decor()
138 }
139
140 /// Returns the surrounding whitespace for the line entry
leaf_decor(&self) -> &Decor141 pub fn leaf_decor(&self) -> &Decor {
142 &self.leaf_decor
143 }
144
145 /// Returns the surrounding whitespace for between dots
dotted_decor(&self) -> &Decor146 pub fn dotted_decor(&self) -> &Decor {
147 &self.dotted_decor
148 }
149
150 /// The location within the original document
151 ///
152 /// This generally requires an [`ImDocument`][crate::ImDocument].
span(&self) -> Option<std::ops::Range<usize>>153 pub fn span(&self) -> Option<std::ops::Range<usize>> {
154 self.repr.as_ref().and_then(|r| r.span())
155 }
156
despan(&mut self, input: &str)157 pub(crate) fn despan(&mut self, input: &str) {
158 self.leaf_decor.despan(input);
159 self.dotted_decor.despan(input);
160 if let Some(repr) = &mut self.repr {
161 repr.despan(input);
162 }
163 }
164
165 /// Auto formats the key.
fmt(&mut self)166 pub fn fmt(&mut self) {
167 self.repr = None;
168 self.leaf_decor.clear();
169 self.dotted_decor.clear();
170 }
171
172 #[cfg(feature = "parse")]
try_parse_simple(s: &str) -> Result<Key, crate::TomlError>173 fn try_parse_simple(s: &str) -> Result<Key, crate::TomlError> {
174 let mut key = crate::parser::parse_key(s)?;
175 key.despan(s);
176 Ok(key)
177 }
178
179 #[cfg(feature = "parse")]
try_parse_path(s: &str) -> Result<Vec<Key>, crate::TomlError>180 fn try_parse_path(s: &str) -> Result<Vec<Key>, crate::TomlError> {
181 let mut keys = crate::parser::parse_key_path(s)?;
182 for key in &mut keys {
183 key.despan(s);
184 }
185 Ok(keys)
186 }
187 }
188
189 impl Clone for Key {
190 #[inline(never)]
clone(&self) -> Self191 fn clone(&self) -> Self {
192 Self {
193 key: self.key.clone(),
194 repr: self.repr.clone(),
195 leaf_decor: self.leaf_decor.clone(),
196 dotted_decor: self.dotted_decor.clone(),
197 }
198 }
199 }
200
201 impl std::ops::Deref for Key {
202 type Target = str;
203
deref(&self) -> &Self::Target204 fn deref(&self) -> &Self::Target {
205 self.get()
206 }
207 }
208
209 impl std::hash::Hash for Key {
hash<H: std::hash::Hasher>(&self, state: &mut H)210 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
211 self.get().hash(state);
212 }
213 }
214
215 impl Ord for Key {
cmp(&self, other: &Self) -> std::cmp::Ordering216 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
217 self.get().cmp(other.get())
218 }
219 }
220
221 impl PartialOrd for Key {
partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>222 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
223 Some(self.cmp(other))
224 }
225 }
226
227 impl Eq for Key {}
228
229 impl PartialEq for Key {
230 #[inline]
eq(&self, other: &Key) -> bool231 fn eq(&self, other: &Key) -> bool {
232 PartialEq::eq(self.get(), other.get())
233 }
234 }
235
236 impl PartialEq<str> for Key {
237 #[inline]
eq(&self, other: &str) -> bool238 fn eq(&self, other: &str) -> bool {
239 PartialEq::eq(self.get(), other)
240 }
241 }
242
243 impl<'s> PartialEq<&'s str> for Key {
244 #[inline]
eq(&self, other: &&str) -> bool245 fn eq(&self, other: &&str) -> bool {
246 PartialEq::eq(self.get(), *other)
247 }
248 }
249
250 impl PartialEq<String> for Key {
251 #[inline]
eq(&self, other: &String) -> bool252 fn eq(&self, other: &String) -> bool {
253 PartialEq::eq(self.get(), other.as_str())
254 }
255 }
256
257 #[cfg(feature = "display")]
258 impl std::fmt::Display for Key {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 crate::encode::encode_key(self, f, None)
261 }
262 }
263
264 #[cfg(feature = "parse")]
265 impl FromStr for Key {
266 type Err = crate::TomlError;
267
268 /// Tries to parse a key from a &str,
269 /// if fails, tries as basic quoted key (surrounds with "")
270 /// and then literal quoted key (surrounds with '')
from_str(s: &str) -> Result<Self, Self::Err>271 fn from_str(s: &str) -> Result<Self, Self::Err> {
272 Key::try_parse_simple(s)
273 }
274 }
275
276 #[cfg(feature = "display")]
to_key_repr(key: &str) -> Repr277 fn to_key_repr(key: &str) -> Repr {
278 #[cfg(feature = "parse")]
279 {
280 if key
281 .as_bytes()
282 .iter()
283 .copied()
284 .all(crate::parser::key::is_unquoted_char)
285 && !key.is_empty()
286 {
287 Repr::new_unchecked(key)
288 } else {
289 crate::encode::to_string_repr(
290 key,
291 Some(crate::encode::StringStyle::OnelineSingle),
292 None,
293 )
294 }
295 }
296 #[cfg(not(feature = "parse"))]
297 {
298 crate::encode::to_string_repr(key, Some(crate::encode::StringStyle::OnelineSingle), None)
299 }
300 }
301
302 impl<'b> From<&'b str> for Key {
from(s: &'b str) -> Self303 fn from(s: &'b str) -> Self {
304 Key::new(s)
305 }
306 }
307
308 impl<'b> From<&'b String> for Key {
from(s: &'b String) -> Self309 fn from(s: &'b String) -> Self {
310 Key::new(s)
311 }
312 }
313
314 impl From<String> for Key {
from(s: String) -> Self315 fn from(s: String) -> Self {
316 Key::new(s)
317 }
318 }
319
320 impl From<InternalString> for Key {
from(s: InternalString) -> Self321 fn from(s: InternalString) -> Self {
322 Key::new(s)
323 }
324 }
325
326 #[doc(hidden)]
327 impl From<Key> for InternalString {
from(key: Key) -> InternalString328 fn from(key: Key) -> InternalString {
329 key.key
330 }
331 }
332
333 /// A mutable reference to a `Key`'s formatting
334 #[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
335 pub struct KeyMut<'k> {
336 key: &'k mut Key,
337 }
338
339 impl<'k> KeyMut<'k> {
340 /// Returns the parsed key value.
get(&self) -> &str341 pub fn get(&self) -> &str {
342 self.key.get()
343 }
344
345 /// Returns the raw representation, if available.
as_repr(&self) -> Option<&Repr>346 pub fn as_repr(&self) -> Option<&Repr> {
347 self.key.as_repr()
348 }
349
350 /// Returns the default raw representation.
351 #[cfg(feature = "display")]
default_repr(&self) -> Repr352 pub fn default_repr(&self) -> Repr {
353 self.key.default_repr()
354 }
355
356 /// Returns a raw representation.
357 #[cfg(feature = "display")]
display_repr(&self) -> Cow<'_, str>358 pub fn display_repr(&self) -> Cow<'_, str> {
359 self.key.display_repr()
360 }
361
362 /// Returns the surrounding whitespace
363 #[deprecated(
364 since = "0.21.1",
365 note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut"
366 )]
decor_mut(&mut self) -> &mut Decor367 pub fn decor_mut(&mut self) -> &mut Decor {
368 #![allow(deprecated)]
369 self.key.decor_mut()
370 }
371
372 /// Returns the surrounding whitespace for the line entry
leaf_decor_mut(&mut self) -> &mut Decor373 pub fn leaf_decor_mut(&mut self) -> &mut Decor {
374 self.key.leaf_decor_mut()
375 }
376
377 /// Returns the surrounding whitespace for between dots
dotted_decor_mut(&mut self) -> &mut Decor378 pub fn dotted_decor_mut(&mut self) -> &mut Decor {
379 self.key.dotted_decor_mut()
380 }
381
382 /// Returns the surrounding whitespace
383 #[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")]
decor(&self) -> &Decor384 pub fn decor(&self) -> &Decor {
385 #![allow(deprecated)]
386 self.key.decor()
387 }
388
389 /// Returns the surrounding whitespace for the line entry
leaf_decor(&self) -> &Decor390 pub fn leaf_decor(&self) -> &Decor {
391 self.key.leaf_decor()
392 }
393
394 /// Returns the surrounding whitespace for between dots
dotted_decor(&self) -> &Decor395 pub fn dotted_decor(&self) -> &Decor {
396 self.key.dotted_decor()
397 }
398
399 /// Auto formats the key.
fmt(&mut self)400 pub fn fmt(&mut self) {
401 self.key.fmt();
402 }
403 }
404
405 impl<'k> std::ops::Deref for KeyMut<'k> {
406 type Target = str;
407
deref(&self) -> &Self::Target408 fn deref(&self) -> &Self::Target {
409 self.get()
410 }
411 }
412
413 impl<'s> PartialEq<str> for KeyMut<'s> {
414 #[inline]
eq(&self, other: &str) -> bool415 fn eq(&self, other: &str) -> bool {
416 PartialEq::eq(self.get(), other)
417 }
418 }
419
420 impl<'s> PartialEq<&'s str> for KeyMut<'s> {
421 #[inline]
eq(&self, other: &&str) -> bool422 fn eq(&self, other: &&str) -> bool {
423 PartialEq::eq(self.get(), *other)
424 }
425 }
426
427 impl<'s> PartialEq<String> for KeyMut<'s> {
428 #[inline]
eq(&self, other: &String) -> bool429 fn eq(&self, other: &String) -> bool {
430 PartialEq::eq(self.get(), other.as_str())
431 }
432 }
433
434 #[cfg(feature = "display")]
435 impl<'k> std::fmt::Display for KeyMut<'k> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 std::fmt::Display::fmt(&self.key, f)
438 }
439 }
440
441 #[test]
442 #[cfg(feature = "parse")]
443 #[cfg(feature = "display")]
string_roundtrip()444 fn string_roundtrip() {
445 Key::new("hello").to_string().parse::<Key>().unwrap();
446 }
447