1use core::fmt::Write;
8
9use crate::error::{ConfigError, ConfigResult};
10use nom::IResult;
11use nom::Parser;
12use nom::bytes::complete::take_while1;
13use nom::character::complete::{char, digit1};
14use nom::combinator::map_res;
15
16fn parse_index_inner(input: &str) -> IResult<&str, usize> {
17 map_res(digit1, |s: &str| s.parse::<usize>()).parse(input)
18}
19
20fn parse_key(input: &str) -> IResult<&str, String> {
21 let (input, key) =
22 take_while1(|c: char| c.is_ascii_alphanumeric() || c == '_' || c == '-')(input)?;
23 Ok((input, key.to_string()))
24}
25
26fn parse_segment(input: &str) -> IResult<&str, KeySegment> {
27 if let Ok((input, _)) = char::<&str, nom::error::Error<&str>>('[').parse(input) {
28 let (input, idx) = parse_index_inner(input)?;
29 let (input, _) = char::<&str, nom::error::Error<&str>>(']').parse(input)?;
30 return Ok((input, KeySegment::Index(idx)));
31 }
32
33 if let Ok((input, _)) = char::<&str, nom::error::Error<&str>>('@').parse(input) {
34 let (input, name) = parse_key(input)?;
35 return Ok((input, KeySegment::Attribute(name)));
36 }
37
38 let (input, key) = parse_key(input)?;
39 Ok((input, KeySegment::Key(key)))
40}
41
42fn parse_key_segments(input: &str) -> IResult<&str, Vec<KeySegment>> {
43 let estimated = std::cmp::max(1, input.len() / 5);
46 let (input, first) = parse_segment(input)?;
47 let mut segments = Vec::with_capacity(estimated);
48 segments.push(first);
49 let mut rest = input;
50
51 while !rest.is_empty() {
52 if let Ok((new_rest, _)) = char::<&str, nom::error::Error<&str>>('.').parse(rest) {
53 let (new_rest, seg) = parse_segment(new_rest)?;
54 segments.push(seg);
55 rest = new_rest;
56 } else if let Ok((new_rest, _)) = char::<&str, nom::error::Error<&str>>('[').parse(rest) {
57 let (new_rest, idx) = parse_index_inner(new_rest)?;
58 let (new_rest, _) = char::<&str, nom::error::Error<&str>>(']').parse(new_rest)?;
59 segments.push(KeySegment::Index(idx));
60 rest = new_rest;
61 } else if let Ok((new_rest, _)) = char::<&str, nom::error::Error<&str>>('@').parse(rest) {
62 let (new_rest, name) = parse_key(new_rest)?;
63 segments.push(KeySegment::Attribute(name));
64 rest = new_rest;
65 } else {
66 break;
67 }
68 }
69
70 Ok((rest, segments))
71}
72
73fn parse_key_path(input: &str) -> IResult<&str, Vec<KeySegment>> {
74 let input = if let Some(rest) = input.strip_prefix('.') {
75 if rest.is_empty() {
76 return Err(nom::Err::Error(nom::error::Error::new(
77 input,
78 nom::error::ErrorKind::Char,
79 )));
80 }
81 rest
82 } else {
83 return Err(nom::Err::Error(nom::error::Error::new(
84 input,
85 nom::error::ErrorKind::Char,
86 )));
87 };
88 parse_key_segments(input)
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Hash)]
98pub enum KeySegment {
99 Key(String),
101 Index(usize),
103 Attribute(String),
105}
106
107impl KeySegment {
108 #[must_use]
110 pub fn as_key(&self) -> Option<&str> {
111 match self {
112 Self::Key(s) => Some(s),
113 _ => None,
114 }
115 }
116
117 #[must_use]
119 pub const fn as_index(&self) -> Option<usize> {
120 match self {
121 Self::Index(i) => Some(*i),
122 _ => None,
123 }
124 }
125
126 #[must_use]
128 pub fn as_attribute(&self) -> Option<&str> {
129 match self {
130 Self::Attribute(s) => Some(s),
131 _ => None,
132 }
133 }
134
135 #[must_use]
137 pub fn into_key(self) -> Option<String> {
138 match self {
139 Self::Key(s) => Some(s),
140 _ => None,
141 }
142 }
143
144 #[must_use]
146 pub fn into_index(self) -> Option<usize> {
147 match self {
148 Self::Index(i) => Some(i),
149 _ => None,
150 }
151 }
152
153 #[must_use]
155 pub fn into_attribute(self) -> Option<String> {
156 match self {
157 Self::Attribute(s) => Some(s),
158 _ => None,
159 }
160 }
161}
162
163impl From<String> for KeySegment {
164 fn from(s: String) -> Self {
165 Self::Key(s)
166 }
167}
168
169impl From<&str> for KeySegment {
170 fn from(s: &str) -> Self {
171 Self::Key(s.to_string())
172 }
173}
174
175impl From<usize> for KeySegment {
176 fn from(i: usize) -> Self {
177 Self::Index(i)
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
196pub struct Key {
197 segments: Vec<KeySegment>,
198}
199
200impl Key {
201 #[allow(clippy::should_implement_trait)]
202 pub fn from_str(s: &str) -> ConfigResult<Self> {
208 let (_, segments) = parse_key_path(s)
209 .map_err(|e| ConfigError::InvalidKey(format!("Parse error: {e:?}")))?;
210
211 if segments.is_empty() {
212 return Err(ConfigError::InvalidKey(
213 "Key must have at least one segment".to_string(),
214 ));
215 }
216
217 Ok(Self { segments })
218 }
219
220 #[must_use]
222 pub const fn from_segments(segments: Vec<KeySegment>) -> Self {
223 Self { segments }
224 }
225
226 #[must_use]
228 pub fn segments(&self) -> &[KeySegment] {
229 &self.segments
230 }
231
232 #[must_use]
234 #[allow(clippy::incompatible_msrv)]
235 pub const fn len(&self) -> usize {
236 self.segments.len()
237 }
238
239 #[must_use]
241 #[allow(clippy::incompatible_msrv)]
242 pub const fn is_empty(&self) -> bool {
243 self.segments.is_empty()
244 }
245
246 #[must_use]
250 pub fn parent(&self) -> Option<Self> {
251 if self.segments.len() > 1 {
252 Some(Self {
253 segments: self.segments[..self.segments.len() - 1].to_vec(),
254 })
255 } else {
256 None
257 }
258 }
259
260 #[must_use]
262 pub fn last_segment(&self) -> Option<&KeySegment> {
263 self.segments.last()
264 }
265
266 #[must_use]
268 pub fn first_segment(&self) -> Option<&KeySegment> {
269 self.segments.first()
270 }
271
272 #[must_use]
274 pub fn append(mut self, segment: KeySegment) -> Self {
275 self.segments.push(segment);
276 self
277 }
278
279 #[must_use]
281 pub fn to_key_string(&self) -> String {
282 let mut result = String::new();
283
284 for (i, segment) in self.segments.iter().enumerate() {
285 if i > 0 {
286 match segment {
287 KeySegment::Attribute(_) | KeySegment::Index(_) => {}
288 _ => result.push('.'),
289 }
290 }
291
292 match segment {
293 KeySegment::Key(s) => {
294 result.push_str(s);
295 }
296 KeySegment::Index(i) => {
297 result.push('[');
298 let _ = write!(&mut result, "{i}");
299 result.push(']');
300 }
301 KeySegment::Attribute(s) => {
302 result.push('@');
303 result.push_str(s);
304 }
305 }
306 }
307
308 result
309 }
310
311 pub fn traverse<F, T>(&self, mut f: F) -> ConfigResult<T>
317 where
318 F: FnMut(&KeySegment) -> ConfigResult<T>,
319 {
320 let mut last = None;
321 for segment in &self.segments {
322 last = Some(f(segment)?);
323 }
324 last.ok_or_else(|| ConfigError::InvalidKey("Cannot traverse empty key".to_string()))
325 }
326
327 pub fn walk<F>(&self, mut f: F) -> ConfigResult<()>
333 where
334 F: FnMut(usize, &KeySegment) -> ConfigResult<()>,
335 {
336 for (i, segment) in self.segments.iter().enumerate() {
337 f(i, segment)?;
338 }
339 Ok(())
340 }
341
342 #[must_use]
346 pub fn head(&self, n: usize) -> Option<Self> {
347 if n > 0 && n <= self.segments.len() {
348 Some(Self {
349 segments: self.segments[..n].to_vec(),
350 })
351 } else {
352 None
353 }
354 }
355
356 #[must_use]
360 pub fn tail(&self, n: usize) -> Option<Self> {
361 if n > 0 && n <= self.segments.len() {
362 Some(Self {
363 segments: self.segments[self.segments.len() - n..].to_vec(),
364 })
365 } else {
366 None
367 }
368 }
369
370 #[must_use]
372 pub fn child(&self, segment: KeySegment) -> Self {
373 let mut new_segments = Vec::with_capacity(self.segments.len() + 1);
374 new_segments.extend(self.segments.iter().cloned());
375 new_segments.push(segment);
376 Self {
377 segments: new_segments,
378 }
379 }
380}
381
382impl From<Vec<KeySegment>> for Key {
383 fn from(segments: Vec<KeySegment>) -> Self {
384 Self { segments }
385 }
386}
387
388impl std::fmt::Display for Key {
389 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
390 write!(f, ".{}", self.to_key_string())
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn test_key_from_str_simple() {
400 let key = Key::from_str(".database").expect("test should succeed");
401 assert_eq!(key.len(), 1);
402 assert_eq!(key.segments()[0].as_key(), Some("database"));
403 }
404
405 #[test]
406 fn test_key_from_str_nested() {
407 let key = Key::from_str(".database.url").expect("test should succeed");
408 assert_eq!(key.len(), 2);
409 assert_eq!(key.segments()[0].as_key(), Some("database"));
410 assert_eq!(key.segments()[1].as_key(), Some("url"));
411 }
412
413 #[test]
414 fn test_key_from_str_index() {
415 let key = Key::from_str(".users[0]").expect("test should succeed");
416 assert_eq!(key.len(), 2);
417 assert_eq!(key.segments()[0].as_key(), Some("users"));
418 assert_eq!(key.segments()[1].as_index(), Some(0));
419 }
420
421 #[test]
422 fn test_key_from_str_attribute() {
423 let key = Key::from_str(".server@port").expect("test should succeed");
424 assert_eq!(key.len(), 2);
425 assert_eq!(key.segments()[0].as_key(), Some("server"));
426 assert_eq!(key.segments()[1].as_attribute(), Some("port"));
427 }
428
429 #[test]
430 fn test_key_from_str_complex() {
431 let key = Key::from_str(".users[0].name@text").expect("test should succeed");
432 assert_eq!(key.len(), 4);
433 assert_eq!(key.segments()[0].as_key(), Some("users"));
434 assert_eq!(key.segments()[1].as_index(), Some(0));
435 assert_eq!(key.segments()[2].as_key(), Some("name"));
436 assert_eq!(key.segments()[3].as_attribute(), Some("text"));
437 }
438
439 #[test]
440 fn test_key_from_str_invalid_empty() {
441 let result = Key::from_str("");
442 assert!(result.is_err());
443 }
444
445 #[test]
446 fn test_key_from_str_invalid_no_dot() {
447 let result = Key::from_str("database");
448 assert!(result.is_err());
449 }
450
451 #[test]
452 fn test_key_parent() {
453 let key = Key::from_str(".a.b.c").expect("test should succeed");
454 let parent = key.parent().expect("test should succeed");
455 assert_eq!(parent.len(), 2);
456 }
457
458 #[test]
459 fn test_key_to_string() {
460 let key = Key::from_str(".database.url").expect("test should succeed");
461 assert_eq!(key.to_key_string(), "database.url");
462 }
463
464 #[test]
465 fn test_key_display() {
466 let key = Key::from_str(".database").expect("test should succeed");
467 assert_eq!(format!("{}", key), ".database");
468 }
469
470 #[test]
471 fn test_key_append() {
472 let key = Key::from_str(".database").expect("test should succeed");
473 let key = key.append(KeySegment::Key("url".to_string()));
474 assert_eq!(key.len(), 2);
475 }
476
477 #[test]
478 fn test_key_traverse() {
479 let key = Key::from_str(".a.b.c").expect("test should succeed");
480 let values: Vec<&str> = key.segments().iter().filter_map(|s| s.as_key()).collect();
481 assert_eq!(values, vec!["a", "b", "c"]);
482 }
483
484 #[test]
485 fn test_key_walk() {
486 let key = Key::from_str(".a[0].b").expect("test should succeed");
487 let mut count = 0;
488 key.walk(|i, _segment| {
489 count = i;
490 Ok(())
491 })
492 .expect("test should succeed");
493 assert_eq!(count, 2);
494 }
495
496 #[test]
497 fn test_key_head_tail() {
498 let key = Key::from_str(".a.b.c.d").expect("test should succeed");
499 let head = key.head(2).expect("test should succeed");
500 let tail = key.tail(2).expect("test should succeed");
501 assert_eq!(head.len(), 2);
502 assert_eq!(tail.len(), 2);
503 }
504
505 #[test]
506 fn test_key_child() {
507 let key = Key::from_str(".a").expect("test should succeed");
508 let child = key.child(KeySegment::Key("b".to_string()));
509 assert_eq!(child.len(), 2);
510 }
511}