qemu_command_builder/args/
plugin.rs1use crate::parsers::ARG_PLUGIN;
2use crate::to_command::ToCommand;
3use bon::Builder;
4use proptest_derive::Arbitrary;
5use std::path::PathBuf;
6use std::str::FromStr;
7
8#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
10pub struct Plugin {
11 file: Option<PathBuf>,
13 args: Option<Vec<(String, String)>>,
15}
16
17impl ToCommand for Plugin {
18 fn command(&self) -> String {
19 ARG_PLUGIN.to_string()
20 }
21
22 fn to_args(&self) -> Vec<String> {
23 let mut args = vec![];
24
25 if let Some(file) = &self.file {
26 args.push(format!("file={}", file.display()));
27 }
28 if let Some(argss) = &self.args {
29 for arg in argss {
30 args.push(format!("{}={}", arg.0, arg.1));
31 }
32 }
33 vec![args.join(",")]
34 }
35}
36
37impl FromStr for Plugin {
38 type Err = String;
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 let mut parts = s.split(',');
42 let first = parts.next().ok_or_else(|| "empty -plugin argument".to_string())?;
43
44 let file = if let Some(value) = first.strip_prefix("file=") {
45 Some(PathBuf::from(value))
46 } else if first.contains('=') {
47 return Err(format!("unsupported first -plugin component: {first}"));
48 } else {
49 Some(PathBuf::from(first))
50 };
51
52 let mut args = Vec::new();
53 for part in parts {
54 let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid -plugin option: {part}"))?;
55 args.push((key.to_string(), value.to_string()));
56 }
57
58 Ok(Self {
59 file,
60 args: (!args.is_empty()).then_some(args),
61 })
62 }
63}