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
use crate::core::parser::matchable::Matchable;

pub trait ToMatchable: Matchable + Sized {
    fn to_matchable(self) -> Box<dyn Matchable> {
        self.boxed()
    }
}

impl<T: Matchable> ToMatchable for T {}

pub trait Boxed {
    fn boxed(self) -> Box<Self>
    where
        Self: Sized;
}

impl<T> Boxed for T {
    fn boxed(self) -> Box<Self> {
        Box::new(self)
    }
}

pub fn capitalize(s: &str) -> String {
    assert!(s.is_ascii());

    let mut chars = s.chars();
    let Some(first_char) = chars.next() else {
        return String::new();
    };

    first_char.to_uppercase().chain(chars.map(|ch| ch.to_ascii_lowercase())).collect()
}

pub trait Config: Sized {
    fn config(mut self, f: impl FnOnce(&mut Self)) -> Self {
        f(&mut self);
        self
    }
}

impl<T> Config for T {}

#[derive(Clone, Debug)]
pub struct HashableFancyRegex(pub fancy_regex::Regex);

impl std::ops::DerefMut for HashableFancyRegex {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl std::ops::Deref for HashableFancyRegex {
    type Target = fancy_regex::Regex;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Eq for HashableFancyRegex {}

impl PartialEq for HashableFancyRegex {
    fn eq(&self, other: &HashableFancyRegex) -> bool {
        self.0.as_str() == other.0.as_str()
    }
}

impl std::hash::Hash for HashableFancyRegex {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.as_str().hash(state);
    }
}

pub fn skip_last<T>(mut iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
    let last = iter.next();
    iter.scan(last, |state, item| std::mem::replace(state, Some(item)))
}