qemu_command_builder/args/
addfs.rs1use crate::parsers::ARG_ADD_FD;
2use std::str::FromStr;
3
4use bon::Builder;
5use proptest_derive::Arbitrary;
6
7use crate::parsers::DELIM_COMMA;
8use crate::shell_string::ShellString;
9use crate::to_command::ToCommand;
10
11const KEY_FD: &str = "fd=";
12const KEY_SET: &str = "set=";
13const KEY_OPAQUE: &str = "opaque=";
14
15#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
17pub struct AddFd {
18 pub fd: usize,
22 pub set: usize,
25 pub opaque: Option<ShellString>,
28}
29
30impl AddFd {
31 pub fn new(fd: usize, set: usize) -> Self {
33 Self { fd, set, opaque: None }
34 }
35}
36
37impl ToCommand for AddFd {
38 fn command(&self) -> String {
39 ARG_ADD_FD.to_string()
40 }
41
42 fn to_args(&self) -> Vec<String> {
43 let mut args = vec![format!("{}{}", KEY_FD, self.fd)];
44 args.push(format!("{}{}", KEY_SET, self.set));
45 if let Some(opaque) = &self.opaque {
46 args.push(format!("{}{}", KEY_OPAQUE, opaque.as_ref()));
47 }
48
49 vec![args.join(DELIM_COMMA)]
50 }
51}
52
53impl FromStr for AddFd {
54 type Err = String;
55
56 fn from_str(s: &str) -> Result<Self, Self::Err> {
57 let mut fd = None;
58 let mut set = None;
59 let mut opaque = None;
60
61 for part in s.split(DELIM_COMMA) {
62 let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid add-fd option: {part}"))?;
63 match key {
64 "fd" => fd = Some(value.parse::<usize>().map_err(|e| e.to_string())?),
65 "set" => set = Some(value.parse::<usize>().map_err(|e| e.to_string())?),
66 "opaque" => opaque = Some(ShellString::from_str(value)?),
67 other => return Err(format!("unsupported add-fd option: {other}")),
68 }
69 }
70
71 Ok(AddFd {
72 fd: fd.ok_or_else(|| "missing fd= for -add-fd".to_string())?,
73 set: set.ok_or_else(|| "missing set= for -add-fd".to_string())?,
74 opaque,
75 })
76 }
77}