qemu_command_builder/args/
compact.rs1use crate::parsers::ARG_COMPAT;
2use std::str::FromStr;
3
4use bon::Builder;
5use proptest_derive::Arbitrary;
6
7use crate::parsers::DELIM_COMMA;
8use crate::to_command::ToArg;
9use crate::to_command::ToCommand;
10
11#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Arbitrary)]
13pub enum AcceptRejectCrash {
14 Accept,
15 Reject,
16 Crash,
17}
18
19impl ToArg for AcceptRejectCrash {
20 fn to_arg(&self) -> &str {
21 match self {
22 AcceptRejectCrash::Accept => "accept",
23 AcceptRejectCrash::Reject => "reject",
24 AcceptRejectCrash::Crash => "crash",
25 }
26 }
27}
28
29#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Arbitrary)]
31pub enum AcceptHide {
32 Accept,
33 Hide,
34}
35impl ToArg for AcceptHide {
36 fn to_arg(&self) -> &str {
37 match self {
38 AcceptHide::Accept => "accept",
39 AcceptHide::Hide => "hide",
40 }
41 }
42}
43#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder, Arbitrary)]
45pub struct DeprecatedInput {
46 deprecated_input: AcceptRejectCrash,
47 deprecated_output: AcceptHide,
48}
49
50#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder, Arbitrary)]
52pub struct UnstableInput {
53 unstable_input: AcceptRejectCrash,
54 unstable_output: AcceptHide,
55}
56
57#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Arbitrary)]
59pub enum Compact {
60 DeprecatedInput(DeprecatedInput),
61 UnstableInput(UnstableInput),
62}
63
64impl ToCommand for Compact {
65 fn command(&self) -> String {
66 ARG_COMPAT.to_string()
67 }
68
69 fn to_args(&self) -> Vec<String> {
70 match self {
71 Compact::DeprecatedInput(deprecated_input) => {
72 let mut args = vec![];
73 args.push(format!("deprecated-input={}", deprecated_input.deprecated_input.to_arg()));
74 args.push(format!("deprecated-output={}", deprecated_input.deprecated_output.to_arg()));
75 vec![args.join(DELIM_COMMA)]
76 }
77 Compact::UnstableInput(unstable_input) => {
78 let mut args = vec![];
79 args.push(format!("unstable-input={}", unstable_input.unstable_input.to_arg()));
80 args.push(format!("unstable-output={}", unstable_input.unstable_output.to_arg()));
81 vec![args.join(DELIM_COMMA)]
82 }
83 }
84 }
85}
86
87impl FromStr for Compact {
88 type Err = String;
89
90 fn from_str(s: &str) -> Result<Self, Self::Err> {
91 let mut deprecated_input = None;
92 let mut deprecated_output = None;
93 let mut unstable_input = None;
94 let mut unstable_output = None;
95
96 for part in s.split(DELIM_COMMA).filter(|part| !part.is_empty()) {
97 let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid -compat option: {part}"))?;
98 match key {
99 "deprecated-input" => {
100 deprecated_input = Some(parse_accept_reject_crash(value)?);
101 }
102 "deprecated-output" => {
103 deprecated_output = Some(parse_accept_hide(value)?);
104 }
105 "unstable-input" => {
106 unstable_input = Some(parse_accept_reject_crash(value)?);
107 }
108 "unstable-output" => {
109 unstable_output = Some(parse_accept_hide(value)?);
110 }
111 other => return Err(format!("unsupported -compat option: {other}")),
112 }
113 }
114
115 match (deprecated_input, deprecated_output, unstable_input, unstable_output) {
116 (Some(input), Some(output), None, None) => Ok(Self::DeprecatedInput(DeprecatedInput {
117 deprecated_input: input,
118 deprecated_output: output,
119 })),
120 (None, None, Some(input), Some(output)) => Ok(Self::UnstableInput(UnstableInput {
121 unstable_input: input,
122 unstable_output: output,
123 })),
124 (Some(_), None, None, None) | (None, Some(_), None, None) => Err("both deprecated-input and deprecated-output are required together".to_string()),
125 (None, None, Some(_), None) | (None, None, None, Some(_)) => Err("both unstable-input and unstable-output are required together".to_string()),
126 (None, None, None, None) => Err("empty -compat argument".to_string()),
127 _ => Err("cannot mix deprecated-* and unstable-* compat policies in one Compact value".to_string()),
128 }
129 }
130}
131
132fn parse_accept_reject_crash(value: &str) -> Result<AcceptRejectCrash, String> {
133 match value {
134 "accept" => Ok(AcceptRejectCrash::Accept),
135 "reject" => Ok(AcceptRejectCrash::Reject),
136 "crash" => Ok(AcceptRejectCrash::Crash),
137 _ => Err(format!("invalid compat input policy: {value}")),
138 }
139}
140
141fn parse_accept_hide(value: &str) -> Result<AcceptHide, String> {
142 match value {
143 "accept" => Ok(AcceptHide::Accept),
144 "hide" => Ok(AcceptHide::Hide),
145 _ => Err(format!("invalid compat output policy: {value}")),
146 }
147}