compat_info/
lib.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use schemars::JsonSchema;
5use serde::{Deserialize, Deserializer, Serialize};
6use std::{fmt, io};
7#[derive(Clone, Deserialize, JsonSchema, Serialize, Debug, PartialEq)]
8#[serde(rename_all = "lowercase")]
9pub enum CompatibilityState {
10    /// An error was encountered determining the compatibility status.
11    Error,
12    /// The compatibility information is not present.
13    Absent,
14    ///  ABI revision was not recognized.
15    Unknown,
16    ///  ABI revision it presented is not supported.
17    Unsupported,
18    /// ABI revision is supported
19    #[serde(alias = "OK")]
20    Supported,
21}
22impl fmt::Display for CompatibilityState {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        let trim: &[char] = &['"'];
25        write!(f, "{}", serde_json::to_value(self).unwrap().to_string().trim_matches(trim))
26    }
27}
28impl std::str::FromStr for CompatibilityState {
29    type Err = io::Error;
30    fn from_str(text: &str) -> Result<Self, Self::Err> {
31        serde_json::from_str(&format!("\"{}\"", text.to_lowercase())).map_err(|e| {
32            io::Error::new(
33                io::ErrorKind::InvalidInput,
34                format!("could not convert {text} into CompatibilityState: {e}"),
35            )
36        })
37    }
38}
39impl From<fidl_fuchsia_developer_remotecontrol::CompatibilityState> for CompatibilityState {
40    fn from(value: fidl_fuchsia_developer_remotecontrol::CompatibilityState) -> Self {
41        match value {
42            fidl_fuchsia_developer_remotecontrol::CompatibilityState::Error => Self::Error,
43            fidl_fuchsia_developer_remotecontrol::CompatibilityState::Absent => Self::Absent,
44            fidl_fuchsia_developer_remotecontrol::CompatibilityState::Unknown => Self::Unknown,
45            fidl_fuchsia_developer_remotecontrol::CompatibilityState::Unsupported => {
46                Self::Unsupported
47            }
48            fidl_fuchsia_developer_remotecontrol::CompatibilityState::Supported => Self::Supported,
49            _ => CompatibilityState::Error,
50        }
51    }
52}
53impl Into<fidl_fuchsia_developer_remotecontrol::CompatibilityState> for CompatibilityState {
54    fn into(self) -> fidl_fuchsia_developer_remotecontrol::CompatibilityState {
55        match self {
56            Self::Error => fidl_fuchsia_developer_remotecontrol::CompatibilityState::Error,
57            Self::Absent => fidl_fuchsia_developer_remotecontrol::CompatibilityState::Absent,
58            Self::Unknown => fidl_fuchsia_developer_remotecontrol::CompatibilityState::Unknown,
59            Self::Unsupported => {
60                fidl_fuchsia_developer_remotecontrol::CompatibilityState::Unsupported
61            }
62            Self::Supported => fidl_fuchsia_developer_remotecontrol::CompatibilityState::Supported,
63        }
64    }
65}
66impl From<version_history::AbiRevisionError> for CompatibilityState {
67    fn from(value: version_history::AbiRevisionError) -> Self {
68        match value {
69            version_history::AbiRevisionError::Malformed { .. }
70            | version_history::AbiRevisionError::PlatformMismatch { .. }
71            | version_history::AbiRevisionError::UnstableMismatch { .. }
72            | version_history::AbiRevisionError::TooNew { .. } => Self::Unknown,
73            version_history::AbiRevisionError::Retired { .. }
74            | version_history::AbiRevisionError::Invalid => Self::Unsupported,
75        }
76    }
77}
78
79#[derive(Clone, Debug, PartialEq)]
80pub struct CompatibilityInfo {
81    pub status: CompatibilityState,
82    pub platform_abi: u64,
83    pub message: String,
84}
85
86#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
87pub struct ConnectionInfo {
88    pub ssh_connection: String,
89    // Use the old "compatibility" name for backwards-compatibility
90    #[serde(rename = "compatibility")]
91    pub connect_info: DeviceConnectionInfo,
92}
93
94impl From<fidl_fuchsia_developer_remotecontrol::CompatibilityInfo> for CompatibilityInfo {
95    fn from(value: fidl_fuchsia_developer_remotecontrol::CompatibilityInfo) -> Self {
96        CompatibilityInfo {
97            status: value.state.into(),
98            platform_abi: value.platform_abi,
99            message: value.message,
100        }
101    }
102}
103impl Into<fidl_fuchsia_developer_remotecontrol::CompatibilityInfo> for CompatibilityInfo {
104    fn into(self) -> fidl_fuchsia_developer_remotecontrol::CompatibilityInfo {
105        fidl_fuchsia_developer_remotecontrol::CompatibilityInfo {
106            state: self.status.into(),
107            platform_abi: self.platform_abi,
108            message: self.message,
109        }
110    }
111}
112
113// This struct defines the protocol used by the ssh host-pipe. Most of the fields
114// get placed in the CompatibilityInfo object stored in the Target, but the
115// overnet_id gets kept in the HostPipeChild.
116// We put the overnet_id in here because this allows backwards-compatibility
117// with devices that don't provide the overnet_id.
118#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
119pub struct DeviceConnectionInfo {
120    pub status: CompatibilityState,
121    // This could be serialized as a string in some cases, so handle that case
122    #[serde(deserialize_with = "parse_string_or_u64")]
123    pub platform_abi: u64,
124    pub message: String,
125    pub overnet_id: Option<u64>,
126}
127
128fn parse_string_or_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
129where
130    D: Deserializer<'de>,
131{
132    // use a untagged enum to handle both formats
133    #[derive(Deserialize)]
134    #[serde(untagged)]
135    enum StringNum {
136        String(String),
137        Num(u64),
138    }
139    match StringNum::deserialize(deserializer)? {
140        StringNum::String(s) => s.parse::<u64>().map_err(serde::de::Error::custom),
141        StringNum::Num(n) => Ok(n),
142    }
143}
144
145impl Into<CompatibilityInfo> for DeviceConnectionInfo {
146    fn into(self) -> CompatibilityInfo {
147        CompatibilityInfo {
148            status: self.status,
149            platform_abi: self.platform_abi,
150            message: self.message,
151        }
152    }
153}