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}