Skip to main content

radicle_git_ref_format/refspec/
iter.rs

1use std::fmt::{self, Display};
2
3use super::PatternStr;
4use crate::{RefStr, lit};
5
6pub type Iter<'a> = std::str::Split<'a, char>;
7
8pub enum Component<'a> {
9    Glob(Option<&'a PatternStr>),
10    Normal(&'a RefStr),
11}
12
13impl Component<'_> {
14    #[inline]
15    pub fn as_str(&self) -> &str {
16        self.as_ref()
17    }
18}
19
20impl AsRef<str> for Component<'_> {
21    #[inline]
22    fn as_ref(&self) -> &str {
23        match self {
24            Self::Glob(None) => "*",
25            Self::Glob(Some(x)) => x.as_str(),
26            Self::Normal(x) => x.as_str(),
27        }
28    }
29}
30
31impl Display for Component<'_> {
32    #[inline]
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        f.write_str(self.as_str())
35    }
36}
37
38impl<T: lit::Lit> From<T> for Component<'static> {
39    #[inline]
40    fn from(_: T) -> Self {
41        Self::Normal(T::NAME)
42    }
43}
44
45#[must_use = "iterators are lazy and do nothing unless consumed"]
46#[derive(Clone)]
47pub struct Components<'a> {
48    inner: Iter<'a>,
49}
50
51impl<'a> Iterator for Components<'a> {
52    type Item = Component<'a>;
53
54    #[inline]
55    fn next(&mut self) -> Option<Self::Item> {
56        self.inner.next().map(|next| match next {
57            "*" => Component::Glob(None),
58            x if x.contains('*') => Component::Glob(Some(PatternStr::from_str(x))),
59            x => Component::Normal(RefStr::from_str(x)),
60        })
61    }
62}
63
64impl DoubleEndedIterator for Components<'_> {
65    #[inline]
66    fn next_back(&mut self) -> Option<Self::Item> {
67        self.inner.next_back().map(|next| match next {
68            "*" => Component::Glob(None),
69            x if x.contains('*') => Component::Glob(Some(PatternStr::from_str(x))),
70            x => Component::Normal(RefStr::from_str(x)),
71        })
72    }
73}
74
75impl<'a> From<&'a PatternStr> for Components<'a> {
76    #[inline]
77    fn from(p: &'a PatternStr) -> Self {
78        Self {
79            inner: p.as_str().split('/'),
80        }
81    }
82}
83
84pub mod component {
85    use super::Component;
86    use crate::name;
87
88    pub const STAR: Component = Component::Glob(None);
89    pub const HEADS: Component = Component::Normal(name::HEADS);
90    pub const MAIN: Component = Component::Normal(name::MAIN);
91    pub const MASTER: Component = Component::Normal(name::MASTER);
92    pub const NAMESPACES: Component = Component::Normal(name::NAMESPACES);
93    pub const NOTES: Component = Component::Normal(name::NOTES);
94    pub const ORIGIN: Component = Component::Normal(name::ORIGIN);
95    pub const REFS: Component = Component::Normal(name::REFS);
96    pub const REMOTES: Component = Component::Normal(name::REMOTES);
97    pub const TAGS: Component = Component::Normal(name::TAGS);
98}