mit_commit/
subject.rs

1use std::{
2    borrow::Cow,
3    fmt,
4    fmt::{Display, Formatter},
5    str::Chars,
6};
7
8use crate::{body::Body, fragment::Fragment};
9
10/// The [`Subject`] from the [`CommitMessage`]
11#[derive(Debug, PartialEq, Eq, Clone, Default)]
12pub struct Subject<'a> {
13    text: Cow<'a, str>,
14}
15
16impl<'a> Subject<'a> {
17    /// Count characters in [`Subject`]
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use mit_commit::Subject;
23    ///
24    /// assert_eq!(Subject::from("hello, world!").len(), 13);
25    /// assert_eq!(Subject::from("goodbye").len(), 7)
26    /// ```
27    #[must_use]
28    pub fn len(&self) -> usize {
29        self.text.len()
30    }
31
32    /// Is the [`Subject`] empty
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use mit_commit::Subject;
38    ///
39    /// assert_eq!(Subject::from("hello, world!").is_empty(), false);
40    /// assert_eq!(Subject::from("").is_empty(), true)
41    /// ```
42    #[must_use]
43    pub fn is_empty(&self) -> bool {
44        self.text.is_empty()
45    }
46
47    /// Convert the [`Subject`] into chars
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use mit_commit::Subject;
53    ///
54    /// let subject = Subject::from("y\u{306}");
55    ///
56    /// let mut chars = subject.chars();
57    ///
58    /// assert_eq!(Some('y'), chars.next());
59    /// assert_eq!(Some('\u{0306}'), chars.next());
60    ///
61    /// assert_eq!(None, chars.next());
62    /// ```
63    pub fn chars(&self) -> Chars<'_> {
64        self.text.chars()
65    }
66}
67
68impl<'a> From<&'a str> for Subject<'a> {
69    fn from(subject: &'a str) -> Self {
70        Self {
71            text: subject.into(),
72        }
73    }
74}
75
76impl<'a> From<String> for Subject<'a> {
77    /// Convert from an owned string
78    ///
79    /// # Examples
80    ///
81    /// ```
82    /// use mit_commit::Subject;
83    ///
84    /// let subject = Subject::from("y\u{306}".to_string());
85    ///
86    /// let mut chars = subject.chars();
87    ///
88    /// assert_eq!(Some('y'), chars.next());
89    /// assert_eq!(Some('\u{0306}'), chars.next());
90    /// assert_eq!(None, chars.next());
91    /// ```
92    fn from(subject: String) -> Self {
93        Self {
94            text: subject.into(),
95        }
96    }
97}
98
99impl<'a> From<Cow<'a, str>> for Subject<'a> {
100    fn from(subject: Cow<'a, str>) -> Self {
101        Self { text: subject }
102    }
103}
104
105impl<'a> From<Subject<'a>> for String {
106    fn from(subject: Subject<'_>) -> Self {
107        subject.text.into_owned()
108    }
109}
110
111impl<'a> Display for Subject<'a> {
112    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
113        write!(f, "{}", String::from(self.clone()))
114    }
115}
116
117impl<'a> From<Body<'a>> for Subject<'a> {
118    fn from(body: Body<'_>) -> Self {
119        Self::from(String::from(body))
120    }
121}
122
123impl<'a> From<Vec<Fragment<'a>>> for Subject<'a> {
124    fn from(ast: Vec<Fragment<'a>>) -> Self {
125        ast.iter()
126            .find_map(|values| {
127                if let Fragment::Body(body) = values {
128                    Some(Self::from(body.clone()))
129                } else {
130                    None
131                }
132            })
133            .unwrap_or_default()
134    }
135}