use crate::bss::BssDescription;
use crate::security::SecurityDescriptor;
use anyhow::format_err;
use fidl_fuchsia_wlan_sme as fidl_sme;
use std::collections::HashSet;
#[cfg(target_os = "fuchsia")]
use {anyhow::Context as _, fuchsia_zircon as zx};
#[derive(Debug, Clone, PartialEq)]
pub struct Compatibility {
mutual_security_protocols: HashSet<SecurityDescriptor>,
}
impl Compatibility {
pub fn try_new(
mutual_security_protocols: impl IntoIterator<Item = SecurityDescriptor>,
) -> Option<Self> {
let mut mutual_security_protocols = mutual_security_protocols.into_iter();
let first_security_protocol = mutual_security_protocols.next();
first_security_protocol.map(|first_security_protocol| Compatibility {
mutual_security_protocols: Some(first_security_protocol)
.into_iter()
.chain(mutual_security_protocols)
.collect(),
})
}
pub fn expect_some(
mutual_security_protocols: impl IntoIterator<Item = SecurityDescriptor>,
) -> Option<Self> {
match Compatibility::try_new(mutual_security_protocols) {
Some(compatibility) => Some(compatibility),
None => panic!("compatibility modes imply incompatiblity"),
}
}
pub fn mutual_security_protocols(&self) -> &HashSet<SecurityDescriptor> {
&self.mutual_security_protocols
}
}
impl TryFrom<fidl_sme::Compatibility> for Compatibility {
type Error = ();
fn try_from(compatibility: fidl_sme::Compatibility) -> Result<Self, Self::Error> {
let fidl_sme::Compatibility { mutual_security_protocols } = compatibility;
Compatibility::try_new(mutual_security_protocols.into_iter().map(From::from)).ok_or(())
}
}
impl From<Compatibility> for fidl_sme::Compatibility {
fn from(compatibility: Compatibility) -> Self {
let Compatibility { mutual_security_protocols } = compatibility;
fidl_sme::Compatibility {
mutual_security_protocols: mutual_security_protocols
.into_iter()
.map(From::from)
.collect(),
}
}
}
impl From<Compatibility> for HashSet<SecurityDescriptor> {
fn from(compatibility: Compatibility) -> Self {
compatibility.mutual_security_protocols
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ScanResult {
pub compatibility: Option<Compatibility>,
#[cfg(target_os = "fuchsia")]
pub timestamp: zx::MonotonicTime,
pub bss_description: BssDescription,
}
impl ScanResult {
pub fn is_compatible(&self) -> bool {
self.compatibility.is_some()
}
}
impl From<ScanResult> for fidl_sme::ScanResult {
fn from(scan_result: ScanResult) -> fidl_sme::ScanResult {
let ScanResult {
compatibility,
#[cfg(target_os = "fuchsia")]
timestamp,
bss_description,
} = scan_result;
fidl_sme::ScanResult {
compatibility: compatibility.map(From::from).map(Box::new),
#[cfg(target_os = "fuchsia")]
timestamp_nanos: timestamp.into_nanos(),
#[cfg(not(target_os = "fuchsia"))]
timestamp_nanos: 0,
bss_description: bss_description.into(),
}
}
}
impl TryFrom<fidl_sme::ScanResult> for ScanResult {
type Error = anyhow::Error;
fn try_from(scan_result: fidl_sme::ScanResult) -> Result<ScanResult, Self::Error> {
let fidl_sme::ScanResult { compatibility, timestamp_nanos, bss_description } = scan_result;
Ok(ScanResult {
compatibility: compatibility
.map(|compatibility| *compatibility)
.map(TryFrom::try_from)
.transpose()
.map_err(|_| format_err!("failed to convert FIDL `Compatibility`"))?,
#[cfg(target_os = "fuchsia")]
timestamp: zx::MonotonicTime::from_nanos(timestamp_nanos),
bss_description: bss_description.try_into()?,
})
}
}
#[cfg(target_os = "fuchsia")]
pub fn write_vmo(results: Vec<fidl_sme::ScanResult>) -> Result<fidl::Vmo, anyhow::Error> {
let bytes =
fidl::persist(&fidl_sme::ScanResultVector { results }).context("encoding scan results")?;
let vmo = fidl::Vmo::create(bytes.len() as u64).context("creating VMO for scan results")?;
vmo.write(&bytes, 0).context("writing scan results to VMO")?;
Ok(vmo)
}
#[cfg(target_os = "fuchsia")]
pub fn read_vmo(vmo: fidl::Vmo) -> Result<Vec<fidl_sme::ScanResult>, anyhow::Error> {
let size = vmo.get_content_size().context("getting VMO content size")?;
let bytes = vmo.read_to_vec(0, size).context("reading VMO of scan results")?;
let scan_result_vector =
fidl::unpersist::<fidl_sme::ScanResultVector>(&bytes).context("decoding scan results")?;
Ok(scan_result_vector.results)
}