fidl_fuchsia_update_installer_ext/
options.rs1use fuchsia_inspect::{self as inspect, ArrayProperty as _};
8use proptest::prelude::*;
9use proptest_derive::Arbitrary;
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12
13#[derive(Clone, Debug, Copy, PartialEq, Arbitrary, Serialize, Deserialize)]
15pub enum Initiator {
16 User,
19
20 Service,
22}
23
24impl Initiator {
25 fn name(&self) -> &'static str {
26 match self {
27 Initiator::User => "User",
28 Initiator::Service => "Service",
29 }
30 }
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Arbitrary, Serialize, Deserialize)]
35pub struct Range {
36 pub offset: u64,
38 pub size: u64,
40}
41
42#[derive(Clone, Debug, PartialEq, Arbitrary, Serialize, Deserialize)]
44pub struct Options {
45 pub initiator: Initiator,
47
48 pub allow_attach_to_existing_attempt: bool,
55
56 pub should_write_recovery: bool,
59
60 pub manifest_range: Option<Range>,
62
63 #[serde(skip)]
65 #[proptest(strategy = "prop::collection::vec(any_header(), 0..2)")]
66 pub manifest_headers: Vec<fidl_fuchsia_net_http::Header>,
67}
68
69fn any_header() -> impl Strategy<Value = fidl_fuchsia_net_http::Header> {
70 (prop::collection::vec(any::<u8>(), 0..10), prop::collection::vec(any::<u8>(), 0..10))
71 .prop_map(|(name, value)| fidl_fuchsia_net_http::Header { name, value })
72}
73
74impl Options {
75 pub fn write_to_inspect(&self, node: &inspect::Node) {
77 let Options {
78 initiator,
79 allow_attach_to_existing_attempt,
80 should_write_recovery,
81 manifest_range,
82 manifest_headers,
83 } = self;
84 node.record_string("initiator", initiator.name());
85 node.record_bool("allow_attach_to_existing_attempt", *allow_attach_to_existing_attempt);
86 node.record_bool("should_write_recovery", *should_write_recovery);
87 if let Some(range) = manifest_range {
88 node.record_child("manifest_range", |range_node| {
89 range_node.record_uint("offset", range.offset);
90 range_node.record_uint("size", range.size);
91 });
92 }
93 if !manifest_headers.is_empty() {
95 let header_names =
96 node.create_string_array("manifest_header_names", manifest_headers.len());
97 for (i, header) in manifest_headers.iter().enumerate() {
98 header_names.set(i, String::from_utf8_lossy(&header.name));
99 }
100 node.record(header_names);
101 }
102 }
103}
104
105#[derive(Error, Debug, PartialEq)]
107pub enum OptionsParseError {
108 #[error("missing initiator")]
110 MissingInitiator,
111}
112
113impl From<fidl_fuchsia_update_installer::Range> for Range {
114 fn from(data: fidl_fuchsia_update_installer::Range) -> Self {
115 Self { offset: data.offset, size: data.size }
116 }
117}
118
119impl From<&Range> for fidl_fuchsia_update_installer::Range {
120 fn from(range: &Range) -> Self {
121 Self { offset: range.offset, size: range.size }
122 }
123}
124
125impl TryFrom<fidl_fuchsia_update_installer::Options> for Options {
126 type Error = OptionsParseError;
127
128 fn try_from(data: fidl_fuchsia_update_installer::Options) -> Result<Self, OptionsParseError> {
129 let initiator =
130 data.initiator.map(|o| o.into()).ok_or(OptionsParseError::MissingInitiator)?;
131
132 let manifest_range = data.manifest_range.map(Range::from);
133 let manifest_headers = data.manifest_headers.unwrap_or_default();
134
135 Ok(Self {
136 initiator,
137 allow_attach_to_existing_attempt: data
138 .allow_attach_to_existing_attempt
139 .unwrap_or(false),
140 should_write_recovery: data.should_write_recovery.unwrap_or(true),
141 manifest_range,
142 manifest_headers,
143 })
144 }
145}
146
147impl From<&Options> for fidl_fuchsia_update_installer::Options {
148 fn from(options: &Options) -> Self {
149 Self {
150 initiator: Some(options.initiator.into()),
151 allow_attach_to_existing_attempt: Some(options.allow_attach_to_existing_attempt),
152 should_write_recovery: Some(options.should_write_recovery),
153 manifest_range: options.manifest_range.as_ref().map(|r| r.into()),
154 manifest_headers: if options.manifest_headers.is_empty() {
155 None
156 } else {
157 Some(options.manifest_headers.clone())
158 },
159 ..Default::default()
160 }
161 }
162}
163
164impl From<Options> for fidl_fuchsia_update_installer::Options {
165 fn from(data: Options) -> Self {
166 (&data).into()
167 }
168}
169
170impl From<fidl_fuchsia_update_installer::Initiator> for Initiator {
171 fn from(fidl_initiator: fidl_fuchsia_update_installer::Initiator) -> Self {
172 match fidl_initiator {
173 fidl_fuchsia_update_installer::Initiator::User => Initiator::User,
174 fidl_fuchsia_update_installer::Initiator::Service => Initiator::Service,
175 }
176 }
177}
178
179impl From<Initiator> for fidl_fuchsia_update_installer::Initiator {
180 fn from(initiator: Initiator) -> Self {
181 match initiator {
182 Initiator::User => fidl_fuchsia_update_installer::Initiator::User,
183 Initiator::Service => fidl_fuchsia_update_installer::Initiator::Service,
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190
191 use super::*;
192
193 proptest! {
194 #[test]
195 fn options_roundtrips_through_fidl(options: Options) {
198 let as_fidl: fidl_fuchsia_update_installer::Options = options.clone().into();
199 prop_assert_eq!(as_fidl.try_into(), Ok(options));
200 }
201
202 #[test]
203 fn fidl_options_sans_initiator_error(options: Options) {
205 let mut as_fidl: fidl_fuchsia_update_installer::Options = options.into();
206 as_fidl.initiator = None;
207 prop_assert_eq!(Options::try_from(as_fidl), Err(OptionsParseError::MissingInitiator));
208 }
209 }
210}