Skip to main content

qemu_command_builder/args/
semihosting.rs

1use crate::common::OnOff;
2use crate::parsers::{ARG_SEMIHOSTING_CONFIG, DELIM_COMMA};
3use crate::to_command::{ToArg, ToCommand};
4use bon::Builder;
5use proptest_derive::Arbitrary;
6use std::str::FromStr;
7
8#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Arbitrary)]
9pub enum SemihostingTarget {
10    Native,
11    Gdb,
12    Auto,
13}
14
15impl ToArg for SemihostingTarget {
16    fn to_arg(&self) -> &str {
17        match self {
18            Self::Native => "native",
19            Self::Gdb => "gdb",
20            Self::Auto => "auto",
21        }
22    }
23}
24
25impl FromStr for SemihostingTarget {
26    type Err = String;
27
28    fn from_str(value: &str) -> Result<Self, Self::Err> {
29        match value {
30            "native" => Ok(Self::Native),
31            "gdb" => Ok(Self::Gdb),
32            "auto" => Ok(Self::Auto),
33            _ => Err(format!("invalid semihosting target: {value}")),
34        }
35    }
36}
37
38#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder, Arbitrary)]
39pub struct SemihostingConfig {
40    enable: Option<OnOff>,
41    target: Option<SemihostingTarget>,
42    chardev: Option<String>,
43    userspace: Option<OnOff>,
44    #[builder(default)]
45    args: Vec<String>,
46}
47
48impl ToCommand for SemihostingConfig {
49    fn command(&self) -> String {
50        ARG_SEMIHOSTING_CONFIG.to_string()
51    }
52
53    fn to_args(&self) -> Vec<String> {
54        let mut parts = Vec::new();
55        if let Some(enable) = &self.enable {
56            parts.push(format!("enable={}", enable.to_arg()));
57        }
58        if let Some(target) = &self.target {
59            parts.push(format!("target={}", target.to_arg()));
60        }
61        if let Some(chardev) = &self.chardev {
62            parts.push(format!("chardev={chardev}"));
63        }
64        if let Some(userspace) = &self.userspace {
65            parts.push(format!("userspace={}", userspace.to_arg()));
66        }
67        parts.extend(self.args.iter().map(|arg| format!("arg={arg}")));
68        vec![parts.join(DELIM_COMMA)]
69    }
70}
71
72impl FromStr for SemihostingConfig {
73    type Err = String;
74
75    fn from_str(value: &str) -> Result<Self, Self::Err> {
76        let mut config = Self {
77            enable: None,
78            target: None,
79            chardev: None,
80            userspace: None,
81            args: Vec::new(),
82        };
83        for part in value.split(DELIM_COMMA) {
84            let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid semihosting-config option: {part}"))?;
85            match key {
86                "enable" => config.enable = Some(value.parse::<OnOff>().map_err(|_| format!("invalid enable value: {value}"))?),
87                "target" => config.target = Some(value.parse()?),
88                "chardev" => config.chardev = Some(value.to_string()),
89                "userspace" => config.userspace = Some(value.parse::<OnOff>().map_err(|_| format!("invalid userspace value: {value}"))?),
90                "arg" => config.args.push(value.to_string()),
91                other => return Err(format!("unsupported semihosting-config option: {other}")),
92            }
93        }
94        Ok(config)
95    }
96}