qemu_command_builder/args/
action.rs1use crate::parsers::ARG_ACTION;
2use std::str::FromStr;
3
4use bon::Builder;
5use proptest_derive::Arbitrary;
6
7use crate::parsers::DELIM_COMMA;
8use crate::to_command::{ToArg, ToCommand};
9
10const KEY_REBOOT: &str = "reboot=";
11const KEY_SHUTDOWN: &str = "shutdown=";
12const KEY_PANIC: &str = "panic=";
13const KEY_WATCHDOG: &str = "watchdog=";
14
15const VAL_RESET: &str = "reset";
16const VAL_SHUTDOWN: &str = "shutdown";
17const VAL_POWEROFF: &str = "poweroff";
18const VAL_PAUSE: &str = "pause";
19const VAL_EXIT_FAILURE: &str = "exit-failure";
20const VAL_NONE: &str = "none";
21const VAL_INJECT_NMI: &str = "inject-nmi";
22const VAL_DEBUG: &str = "debug";
23
24#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Arbitrary)]
26pub enum RebootAction {
27 #[default]
28 Reset,
29 Shutdown,
30}
31
32impl ToArg for RebootAction {
33 fn to_arg(&self) -> &str {
34 match self {
35 RebootAction::Reset => VAL_RESET,
36 RebootAction::Shutdown => VAL_SHUTDOWN,
37 }
38 }
39}
40
41impl FromStr for RebootAction {
42 type Err = String;
43
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
45 match s {
46 VAL_RESET => Ok(Self::Reset),
47 VAL_SHUTDOWN => Ok(Self::Shutdown),
48 _ => Err(format!("invalid reboot action: {s}")),
49 }
50 }
51}
52
53#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Arbitrary)]
55pub enum ShutdownAction {
56 #[default]
57 PowerOff,
58 Pause,
59}
60
61impl ToArg for ShutdownAction {
62 fn to_arg(&self) -> &str {
63 match self {
64 ShutdownAction::PowerOff => VAL_POWEROFF,
65 ShutdownAction::Pause => VAL_PAUSE,
66 }
67 }
68}
69
70impl FromStr for ShutdownAction {
71 type Err = String;
72
73 fn from_str(s: &str) -> Result<Self, Self::Err> {
74 match s {
75 VAL_POWEROFF => Ok(Self::PowerOff),
76 VAL_PAUSE => Ok(Self::Pause),
77 _ => Err(format!("invalid shutdown action: {s}")),
78 }
79 }
80}
81
82#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Arbitrary)]
84pub enum PanicAction {
85 Pause,
86 #[default]
87 Shutdown,
88 ExitFailure,
89 None,
90}
91
92impl ToArg for PanicAction {
93 fn to_arg(&self) -> &str {
94 match self {
95 PanicAction::Pause => VAL_PAUSE,
96 PanicAction::Shutdown => VAL_SHUTDOWN,
97 PanicAction::ExitFailure => VAL_EXIT_FAILURE,
98 PanicAction::None => VAL_NONE,
99 }
100 }
101}
102
103impl FromStr for PanicAction {
104 type Err = String;
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 match s {
108 VAL_PAUSE => Ok(Self::Pause),
109 VAL_SHUTDOWN => Ok(Self::Shutdown),
110 VAL_EXIT_FAILURE => Ok(Self::ExitFailure),
111 VAL_NONE => Ok(Self::None),
112 _ => Err(format!("invalid panic action: {s}")),
113 }
114 }
115}
116
117#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Arbitrary)]
119pub enum WatchdogAction {
120 #[default]
121 Reset,
122 Shutdown,
123 PowerOff,
124 InjectNmi,
125 Pause,
126 Debug,
127 None,
128}
129
130impl ToArg for WatchdogAction {
131 fn to_arg(&self) -> &str {
132 match self {
133 WatchdogAction::Reset => VAL_RESET,
134 WatchdogAction::Shutdown => VAL_SHUTDOWN,
135 WatchdogAction::PowerOff => VAL_POWEROFF,
136 WatchdogAction::InjectNmi => VAL_INJECT_NMI,
137 WatchdogAction::Pause => VAL_PAUSE,
138 WatchdogAction::Debug => VAL_DEBUG,
139 WatchdogAction::None => VAL_NONE,
140 }
141 }
142}
143
144impl FromStr for WatchdogAction {
145 type Err = String;
146
147 fn from_str(s: &str) -> Result<Self, Self::Err> {
148 match s {
149 VAL_RESET => Ok(Self::Reset),
150 VAL_SHUTDOWN => Ok(Self::Shutdown),
151 VAL_POWEROFF => Ok(Self::PowerOff),
152 VAL_INJECT_NMI => Ok(Self::InjectNmi),
153 VAL_PAUSE => Ok(Self::Pause),
154 VAL_DEBUG => Ok(Self::Debug),
155 VAL_NONE => Ok(Self::None),
156 _ => Err(format!("invalid watchdog action: {s}")),
157 }
158 }
159}
160
161#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
167pub struct Action {
168 reboot: Option<RebootAction>,
169 shutdown: Option<ShutdownAction>,
170 panic: Option<PanicAction>,
171 watchdog: Option<WatchdogAction>,
172}
173
174impl Action {
175 pub fn new() -> Self {
177 Self::default()
178 }
179}
180
181impl ToCommand for Action {
182 fn has_args(&self) -> bool {
183 self.reboot.is_some() || self.shutdown.is_some() || self.panic.is_some() || self.watchdog.is_some()
184 }
185
186 fn command(&self) -> String {
187 ARG_ACTION.to_string()
188 }
189
190 fn to_args(&self) -> Vec<String> {
191 let mut args = vec![];
192 if let Some(action) = &self.reboot {
193 args.push(format!("{}{}", KEY_REBOOT, action.to_arg()));
194 }
195 if let Some(action) = &self.shutdown {
196 args.push(format!("{}{}", KEY_SHUTDOWN, action.to_arg()));
197 }
198 if let Some(action) = &self.panic {
199 args.push(format!("{}{}", KEY_PANIC, action.to_arg()));
200 }
201 if let Some(action) = &self.watchdog {
202 args.push(format!("{}{}", KEY_WATCHDOG, action.to_arg()));
203 }
204 vec![args.join(DELIM_COMMA)]
205 }
206}
207
208impl FromStr for Action {
209 type Err = String;
210
211 fn from_str(s: &str) -> Result<Self, Self::Err> {
212 let mut action = Action::default();
213
214 for part in s.split(DELIM_COMMA) {
215 let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid action option: {part}"))?;
216 match key {
217 "reboot" => action.reboot = Some(value.parse::<RebootAction>()?),
218 "shutdown" => action.shutdown = Some(value.parse::<ShutdownAction>()?),
219 "panic" => action.panic = Some(value.parse::<PanicAction>()?),
220 "watchdog" => action.watchdog = Some(value.parse::<WatchdogAction>()?),
221 other => return Err(format!("unsupported action key: {other}")),
222 }
223 }
224
225 Ok(action)
226 }
227}