1use std::fmt::{Display, Formatter};
2
3use crate::errors::ParseError;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7#[allow(clippy::exhaustive_enums)]
8pub enum Action {
9 Break,
11 Drop,
13 Edit,
15 Exec,
17 Fixup,
19 Noop,
21 Pick,
23 Reword,
25 Squash,
27 Label,
29 Reset,
31 Merge,
33 UpdateRef,
35}
36
37impl Action {
38 #[must_use]
40 #[inline]
41 pub fn to_abbreviation(self) -> String {
42 String::from(match self {
43 Self::Break => "b",
44 Self::Drop => "d",
45 Self::Edit => "e",
46 Self::Exec => "x",
47 Self::Fixup => "f",
48 Self::Label => "l",
49 Self::Merge => "m",
50 Self::Noop => "n",
51 Self::Pick => "p",
52 Self::Reset => "t",
53 Self::Reword => "r",
54 Self::Squash => "s",
55 Self::UpdateRef => "u",
56 })
57 }
58
59 #[must_use]
61 #[inline]
62 pub const fn is_static(self) -> bool {
63 match self {
64 Self::Break | Self::Exec | Self::Noop | Self::Reset | Self::Label | Self::Merge | Self::UpdateRef => true,
65 Self::Drop | Self::Edit | Self::Fixup | Self::Pick | Self::Reword | Self::Squash => false,
66 }
67 }
68}
69
70impl Display for Action {
71 #[inline]
72 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
73 write!(f, "{}", match *self {
74 Self::Break => "break",
75 Self::Drop => "drop",
76 Self::Edit => "edit",
77 Self::Exec => "exec",
78 Self::Fixup => "fixup",
79 Self::Label => "label",
80 Self::Merge => "merge",
81 Self::Noop => "noop",
82 Self::Pick => "pick",
83 Self::Reset => "reset",
84 Self::Reword => "reword",
85 Self::Squash => "squash",
86 Self::UpdateRef => "update-ref",
87 })
88 }
89}
90
91impl TryFrom<&str> for Action {
92 type Error = ParseError;
93
94 #[inline]
95 fn try_from(s: &str) -> Result<Self, Self::Error> {
96 match s {
97 "break" | "b" => Ok(Self::Break),
98 "drop" | "d" => Ok(Self::Drop),
99 "edit" | "e" => Ok(Self::Edit),
100 "exec" | "x" => Ok(Self::Exec),
101 "fixup" | "f" => Ok(Self::Fixup),
102 "noop" | "n" => Ok(Self::Noop),
103 "pick" | "p" => Ok(Self::Pick),
104 "reword" | "r" => Ok(Self::Reword),
105 "squash" | "s" => Ok(Self::Squash),
106 "label" | "l" => Ok(Self::Label),
107 "reset" | "t" => Ok(Self::Reset),
108 "merge" | "m" => Ok(Self::Merge),
109 "update-ref" | "u" => Ok(Self::UpdateRef),
110 _ => Err(ParseError::InvalidAction(String::from(s))),
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use claim::assert_ok_eq;
118 use rstest::rstest;
119 use testutils::assert_err_eq;
120
121 use super::*;
122
123 #[rstest]
124 #[case::break_str(Action::Break, "break")]
125 #[case::drop(Action::Drop, "drop")]
126 #[case::edit(Action::Edit, "edit")]
127 #[case::exec(Action::Exec, "exec")]
128 #[case::fixup(Action::Fixup, "fixup")]
129 #[case::noop(Action::Noop, "noop")]
130 #[case::pick(Action::Pick, "pick")]
131 #[case::reword(Action::Reword, "reword")]
132 #[case::squash(Action::Squash, "squash")]
133 #[case::label(Action::Label, "label")]
134 #[case::reset(Action::Reset, "reset")]
135 #[case::merge(Action::Merge, "merge")]
136 #[case::update_ref(Action::UpdateRef, "update-ref")]
137 fn to_string(#[case] action: Action, #[case] expected: &str) {
138 assert_eq!(format!("{action}"), expected);
139 }
140
141 #[rstest]
142 #[case::b("b", Action::Break)]
143 #[case::break_str("break", Action::Break)]
144 #[case::d("d", Action::Drop)]
145 #[case::drop("drop", Action::Drop)]
146 #[case::e("e", Action::Edit)]
147 #[case::edit("edit", Action::Edit)]
148 #[case::x("x", Action::Exec)]
149 #[case::exec("exec", Action::Exec)]
150 #[case::f("f", Action::Fixup)]
151 #[case::fixup("fixup", Action::Fixup)]
152 #[case::n("n", Action::Noop)]
153 #[case::noop("noop", Action::Noop)]
154 #[case::p("p", Action::Pick)]
155 #[case::pick("pick", Action::Pick)]
156 #[case::r("r", Action::Reword)]
157 #[case::reword("reword", Action::Reword)]
158 #[case::s("s", Action::Squash)]
159 #[case::squash("squash", Action::Squash)]
160 #[case::l("l", Action::Label)]
161 #[case::label("label", Action::Label)]
162 #[case::t("t", Action::Reset)]
163 #[case::reset("reset", Action::Reset)]
164 #[case::m("m", Action::Merge)]
165 #[case::merge("merge", Action::Merge)]
166 #[case::u("u", Action::UpdateRef)]
167 #[case::update_ref("update-ref", Action::UpdateRef)]
168 fn try_from(#[case] action_str: &str, #[case] expected: Action) {
169 assert_ok_eq!(Action::try_from(action_str), expected);
170 }
171
172 #[test]
173 fn action_try_from_invalid() {
174 let invalid = String::from("invalid");
175 assert_err_eq!(Action::try_from(invalid.as_str()), ParseError::InvalidAction(invalid));
176 }
177
178 #[rstest]
179 #[case::b(Action::Break, "b")]
180 #[case::d(Action::Drop, "d")]
181 #[case::e(Action::Edit, "e")]
182 #[case::x(Action::Exec, "x")]
183 #[case::f(Action::Fixup, "f")]
184 #[case::n(Action::Noop, "n")]
185 #[case::p(Action::Pick, "p")]
186 #[case::r(Action::Reword, "r")]
187 #[case::s(Action::Squash, "s")]
188 #[case::l(Action::Label, "l")]
189 #[case::t(Action::Reset, "t")]
190 #[case::m(Action::Merge, "m")]
191 #[case::u(Action::UpdateRef, "u")]
192 fn to_abbreviation(#[case] action: Action, #[case] expected: &str) {
193 assert_eq!(action.to_abbreviation(), expected);
194 }
195
196 #[rstest]
197 #[case::break_action(Action::Break, true)]
198 #[case::drop(Action::Drop, false)]
199 #[case::edit(Action::Edit, false)]
200 #[case::exec(Action::Exec, true)]
201 #[case::fixup(Action::Fixup, false)]
202 #[case::noop(Action::Noop, true)]
203 #[case::pick(Action::Pick, false)]
204 #[case::reword(Action::Reword, false)]
205 #[case::squash(Action::Squash, false)]
206 #[case::label(Action::Label, true)]
207 #[case::reset(Action::Reset, true)]
208 #[case::merge(Action::Merge, true)]
209 #[case::update_ref(Action::UpdateRef, true)]
210 fn module_lifecycle(#[case] action: Action, #[case] expected: bool) {
211 assert_eq!(action.is_static(), expected);
212 }
213}