Skip to main content

qemu_command_builder/args/
object.rs

1use crate::parsers::{ARG_OBJECT, DELIM_COMMA};
2use crate::to_command::ToCommand;
3use bon::Builder;
4use proptest_derive::Arbitrary;
5use std::str::FromStr;
6
7/// A generic QEMU `-object typename[,prop=value,...]` definition.
8#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
9pub struct Object {
10    /// The QOM object type name.
11    typename: String,
12    /// Object properties emitted in the order stored.
13    properties: Vec<(String, String)>,
14}
15
16impl Object {
17    pub fn new<S: AsRef<str>>(typename: S) -> Self {
18        Object {
19            typename: typename.as_ref().to_string(),
20            properties: Default::default(),
21        }
22    }
23    pub fn add_prop<S: AsRef<str>>(&mut self, key: S, value: S) -> &mut Self {
24        self.properties.push((key.as_ref().to_string(), value.as_ref().to_string()));
25        self
26    }
27}
28
29impl ToCommand for Object {
30    fn command(&self) -> String {
31        ARG_OBJECT.to_string()
32    }
33    fn to_args(&self) -> Vec<String> {
34        let mut args = vec![self.typename.clone()];
35
36        for (prop_key, prop_value) in &self.properties {
37            args.push(format!("{}={}", prop_key, prop_value));
38        }
39        vec![args.join(DELIM_COMMA)]
40    }
41}
42
43impl FromStr for Object {
44    type Err = String;
45
46    fn from_str(s: &str) -> Result<Self, Self::Err> {
47        let mut parts = s.split(DELIM_COMMA);
48        let typename = parts.next().ok_or_else(|| "empty -object argument".to_string())?.to_string();
49
50        let mut properties = Vec::new();
51        for part in parts {
52            let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid -object property: {part}"))?;
53            properties.push((key.to_string(), value.to_string()));
54        }
55
56        Ok(Self { typename, properties })
57    }
58}