shutdown_shim/
reboot_reasons.rs1use fidl::marker::SourceBreaking;
6use fidl_fuchsia_hardware_power_statecontrol as fpower;
7
8#[derive(Debug, PartialEq, PartialOrd, Clone)]
13pub struct RebootReasons(pub Vec<fpower::RebootReason2>);
14
15impl RebootReasons {
16 pub fn new(reason: fpower::RebootReason2) -> Self {
18 Self(vec![reason])
19 }
20
21 pub(crate) fn from_deprecated(reason: &fpower::RebootReason) -> Self {
26 let reason = match reason {
27 fpower::RebootReason::UserRequest => fpower::RebootReason2::UserRequest,
28 fpower::RebootReason::SystemUpdate => fpower::RebootReason2::SystemUpdate,
29 fpower::RebootReason::RetrySystemUpdate => fpower::RebootReason2::RetrySystemUpdate,
30 fpower::RebootReason::HighTemperature => fpower::RebootReason2::HighTemperature,
31 fpower::RebootReason::FactoryDataReset => fpower::RebootReason2::FactoryDataReset,
32 fpower::RebootReason::SessionFailure => fpower::RebootReason2::SessionFailure,
33 fpower::RebootReason::SysmgrFailure => fpower::RebootReason2::SysmgrFailure,
34 fpower::RebootReason::CriticalComponentFailure => {
35 fpower::RebootReason2::CriticalComponentFailure
36 }
37 fpower::RebootReason::ZbiSwap => fpower::RebootReason2::ZbiSwap,
38 fpower::RebootReason::OutOfMemory => fpower::RebootReason2::OutOfMemory,
39 };
40 Self::new(reason)
41 }
42
43 pub(crate) fn to_deprecated(&self) -> fpower::RebootReason {
53 enum FoldState {
54 Direct(fpower::RebootReason),
55 Indirect(fpower::RebootReason),
56 None,
57 }
58 let state = self.0.iter().fold(FoldState::None, |state, reason| {
59 match (&state, &reason) {
60 (FoldState::Direct(_), _) => state,
62 (_, fpower::RebootReason2::UserRequest) => {
64 FoldState::Direct(fpower::RebootReason::UserRequest)
65 }
66 (_, fpower::RebootReason2::SystemUpdate) => {
67 FoldState::Direct(fpower::RebootReason::SystemUpdate)
68 }
69 (_, fpower::RebootReason2::RetrySystemUpdate) => {
70 FoldState::Direct(fpower::RebootReason::RetrySystemUpdate)
71 }
72 (_, fpower::RebootReason2::HighTemperature) => {
73 FoldState::Direct(fpower::RebootReason::HighTemperature)
74 }
75 (_, fpower::RebootReason2::FactoryDataReset) => {
76 FoldState::Direct(fpower::RebootReason::FactoryDataReset)
77 }
78 (_, fpower::RebootReason2::SessionFailure) => {
79 FoldState::Direct(fpower::RebootReason::SessionFailure)
80 }
81 (_, fpower::RebootReason2::SysmgrFailure) => {
82 FoldState::Direct(fpower::RebootReason::SysmgrFailure)
83 }
84 (_, fpower::RebootReason2::CriticalComponentFailure) => {
85 FoldState::Direct(fpower::RebootReason::CriticalComponentFailure)
86 }
87 (_, fpower::RebootReason2::ZbiSwap) => {
88 FoldState::Direct(fpower::RebootReason::ZbiSwap)
89 }
90 (_, fpower::RebootReason2::OutOfMemory) => {
91 FoldState::Direct(fpower::RebootReason::OutOfMemory)
92 }
93 (FoldState::Indirect(_), fpower::RebootReason2::NetstackMigration) => state,
96 (FoldState::None, fpower::RebootReason2::NetstackMigration) => {
98 FoldState::Indirect(fpower::RebootReason::SystemUpdate)
99 }
100 (_, fpower::RebootReason2::__SourceBreaking { unknown_ordinal: _ }) => {
101 unreachable!()
102 }
103 }
104 });
105 match state {
106 FoldState::Direct(reason) | FoldState::Indirect(reason) => reason,
107 FoldState::None => {
108 unreachable!("RebootReasons is guaranteed to have at least 1 reason.")
109 }
110 }
111 }
112}
113
114impl AsRef<Vec<fpower::RebootReason2>> for RebootReasons {
115 fn as_ref(&self) -> &Vec<fpower::RebootReason2> {
116 &self.0
117 }
118}
119
120impl From<RebootReasons> for fpower::RebootOptions {
121 fn from(RebootReasons(reasons): RebootReasons) -> Self {
122 fpower::RebootOptions { reasons: Some(reasons), __source_breaking: SourceBreaking }
123 }
124}
125
126#[derive(Debug, PartialEq)]
128pub enum InvalidRebootOptions {
129 NoReasons,
131}
132
133impl TryFrom<fpower::RebootOptions> for RebootReasons {
134 type Error = InvalidRebootOptions;
135 fn try_from(options: fpower::RebootOptions) -> Result<Self, Self::Error> {
136 let fpower::RebootOptions { reasons, __source_breaking } = options;
137 if let Some(reasons) = reasons {
138 if !reasons.is_empty() {
139 return Ok(RebootReasons(reasons));
140 }
141 }
142
143 Err(InvalidRebootOptions::NoReasons)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use test_case::test_case;
151
152 #[test_case(None => Err(InvalidRebootOptions::NoReasons); "no_reasons")]
153 #[test_case(Some(vec![]) => Err(InvalidRebootOptions::NoReasons); "empty_reasons")]
154 #[test_case(Some(vec![fpower::RebootReason2::UserRequest]) => Ok(()); "success")]
155 fn reboot_reasons(
156 reasons: Option<Vec<fpower::RebootReason2>>,
157 ) -> Result<(), InvalidRebootOptions> {
158 let options = fpower::RebootOptions { reasons, __source_breaking: SourceBreaking };
159 RebootReasons::try_from(options).map(|_reasons| {})
160 }
161
162 #[test_case(
163 vec![fpower::RebootReason2::UserRequest, fpower::RebootReason2::SystemUpdate] =>
164 fpower::RebootReason::UserRequest;
165 "prefer_first_a")]
166 #[test_case(
167 vec![fpower::RebootReason2::SystemUpdate, fpower::RebootReason2::UserRequest] =>
168 fpower::RebootReason::SystemUpdate;
169 "prefer_first_b")]
170 #[test_case(
171 vec![fpower::RebootReason2::NetstackMigration, fpower::RebootReason2::UserRequest] =>
172 fpower::RebootReason::UserRequest;
173 "prefer_direct")]
174 #[test_case(
175 vec![fpower::RebootReason2::NetstackMigration] =>
176 fpower::RebootReason::SystemUpdate;
177 "netstack_migration")]
178 fn reasons_to_deprecated(reasons: Vec<fpower::RebootReason2>) -> fpower::RebootReason {
179 let options =
180 fpower::RebootOptions { reasons: Some(reasons), __source_breaking: SourceBreaking };
181 RebootReasons::try_from(options).unwrap().to_deprecated()
182 }
183}