todo_file/
action.rs

1use std::fmt::{Display, Formatter};
2
3use crate::errors::ParseError;
4
5/// Describes an rebase action.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7#[allow(clippy::exhaustive_enums)]
8pub enum Action {
9	/// A break action.
10	Break,
11	/// A drop action.
12	Drop,
13	/// An edit action.
14	Edit,
15	/// An exec action.
16	Exec,
17	/// A fixup action.
18	Fixup,
19	/// A noop action.
20	Noop,
21	/// A pick action.
22	Pick,
23	/// A reword action.
24	Reword,
25	/// A squash action.
26	Squash,
27	/// A label for a merge block.
28	Label,
29	/// A reset for a merge block.
30	Reset,
31	/// A merge action.
32	Merge,
33	/// Update a reference
34	UpdateRef,
35}
36
37impl Action {
38	/// Get the abbreviated version of the action.
39	#[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	/// Can the action be changed.
60	#[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}