Skip to main content

radicle_git_ref_format/name/
iter.rs

1use std::{
2    borrow::Cow,
3    fmt::{self, Display},
4    ops::Deref,
5};
6
7use super::RefStr;
8use crate::lit;
9
10pub type Iter<'a> = std::str::Split<'a, char>;
11
12/// Iterator created by the [`RefStr::iter`] method.
13#[must_use = "iterators are lazy and do nothing unless consumed"]
14#[derive(Clone)]
15pub struct Components<'a> {
16    inner: std::str::Split<'a, char>,
17}
18
19impl<'a> Iterator for Components<'a> {
20    type Item = Component<'a>;
21
22    #[inline]
23    fn next(&mut self) -> Option<Self::Item> {
24        self.inner
25            .next()
26            .map(RefStr::from_str)
27            .map(Cow::from)
28            .map(Component)
29    }
30}
31
32impl DoubleEndedIterator for Components<'_> {
33    #[inline]
34    fn next_back(&mut self) -> Option<Self::Item> {
35        self.inner
36            .next_back()
37            .map(RefStr::from_str)
38            .map(Cow::from)
39            .map(Component)
40    }
41}
42
43impl<'a> From<&'a RefStr> for Components<'a> {
44    #[inline]
45    fn from(rs: &'a RefStr) -> Self {
46        Self {
47            inner: rs.as_str().split('/'),
48        }
49    }
50}
51
52/// A path component of a [`RefStr`].
53///
54/// A [`Component`] is a valid [`RefStr`] which does not contain any '/'
55/// separators.
56#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
57pub struct Component<'a>(Cow<'a, RefStr>);
58
59impl<'a> Component<'a> {
60    #[inline]
61    pub fn from_refstr(r: impl Into<Cow<'a, RefStr>>) -> Option<Self> {
62        let r = r.into();
63        if !r.contains('/') {
64            Some(Self(r))
65        } else {
66            None
67        }
68    }
69
70    #[inline]
71    pub fn as_lit<T: lit::Lit>(&self) -> Option<T> {
72        T::from_component(self)
73    }
74
75    #[inline]
76    pub fn into_inner(self) -> Cow<'a, RefStr> {
77        self.0
78    }
79}
80
81impl Deref for Component<'_> {
82    type Target = RefStr;
83
84    #[inline]
85    fn deref(&self) -> &Self::Target {
86        &self.0
87    }
88}
89
90impl AsRef<RefStr> for Component<'_> {
91    #[inline]
92    fn as_ref(&self) -> &RefStr {
93        self
94    }
95}
96
97impl<'a> From<&'a RefStr> for Option<Component<'a>> {
98    #[inline]
99    fn from(r: &'a RefStr) -> Self {
100        if !r.contains('/') {
101            Some(Component(Cow::from(r)))
102        } else {
103            None
104        }
105    }
106}
107
108impl<'a> From<Component<'a>> for Cow<'a, RefStr> {
109    #[inline]
110    fn from(c: Component<'a>) -> Self {
111        c.0
112    }
113}
114
115impl<T: lit::Lit> From<T> for Component<'static> {
116    #[inline]
117    fn from(_: T) -> Self {
118        Component(Cow::from(T::NAME))
119    }
120}
121
122impl<'a> From<lit::SomeLit<'a>> for Component<'a> {
123    #[inline]
124    fn from(s: lit::SomeLit<'a>) -> Self {
125        use lit::SomeLit::*;
126
127        match s {
128            Known(k) => k.into(),
129            Any(c) => c,
130        }
131    }
132}
133
134impl Display for Component<'_> {
135    #[inline]
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        f.write_str(self.0.as_str())
138    }
139}
140
141pub mod component {
142    use super::Component;
143    use crate::name;
144    use std::borrow::Cow;
145
146    pub const HEADS: Component = Component(Cow::Borrowed(name::HEADS));
147    pub const MAIN: Component = Component(Cow::Borrowed(name::MAIN));
148    pub const MASTER: Component = Component(Cow::Borrowed(name::MASTER));
149    pub const NAMESPACES: Component = Component(Cow::Borrowed(name::NAMESPACES));
150    pub const NOTES: Component = Component(Cow::Borrowed(name::NOTES));
151    pub const ORIGIN: Component = Component(Cow::Borrowed(name::ORIGIN));
152    pub const REFS: Component = Component(Cow::Borrowed(name::REFS));
153    pub const REMOTES: Component = Component(Cow::Borrowed(name::REMOTES));
154    pub const TAGS: Component = Component(Cow::Borrowed(name::TAGS));
155}