qemu_command_builder/args/
semihosting.rs1use 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}