blob: 1299431d55e6b74a4e6762e5cdbcd24fe5c50514 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
anyhow::Error,
fidl_fuchsia_bluetooth::{self, Int8},
fidl_fuchsia_bluetooth_control::{AdapterInfo, AdapterState, RemoteDevice},
std::{
fs::{File, OpenOptions},
path::Path,
},
};
/// Macro to help build bluetooth fidl statuses.
/// No Args is a success
/// One Arg is the error type
/// Two Args is the error type & a description
#[macro_export]
macro_rules! bt_fidl_status {
() => {
fidl_fuchsia_bluetooth::Status { error: None }
};
($error_code:ident) => {
fidl_fuchsia_bluetooth::Status {
error: Some(Box::new(fidl_fuchsia_bluetooth::Error {
description: None,
protocol_error_code: 0,
error_code: fidl_fuchsia_bluetooth::ErrorCode::$error_code,
})),
}
};
($error_code:ident, $description:expr) => {
fidl_fuchsia_bluetooth::Status {
error: Some(Box::new(fidl_fuchsia_bluetooth::Error {
description: Some($description.to_string()),
protocol_error_code: 0,
error_code: fidl_fuchsia_bluetooth::ErrorCode::$error_code,
})),
}
};
}
/// Open a file with read and write permissions.
pub fn open_rdwr<P: AsRef<Path>>(path: P) -> Result<File, Error> {
OpenOptions::new().read(true).write(true).open(path).map_err(|e| e.into())
}
/// The following functions allow FIDL types to be cloned. These are currently necessary as the
/// auto-generated binding types do not derive `Clone`.
/// Clone Adapter Info
pub fn clone_host_info(a: &AdapterInfo) -> AdapterInfo {
let state = match a.state {
Some(ref s) => Some(Box::new(clone_host_state(&**s))),
None => None,
};
AdapterInfo {
identifier: a.identifier.clone(),
technology: a.technology.clone(),
address: a.address.clone(),
state: state,
}
}
/// Clone Bluetooth Fidl bool type
pub fn clone_bt_fidl_bool(a: &fidl_fuchsia_bluetooth::Bool) -> fidl_fuchsia_bluetooth::Bool {
fidl_fuchsia_bluetooth::Bool { value: a.value }
}
/// Clone Adapter State
pub fn clone_host_state(a: &AdapterState) -> AdapterState {
let discoverable = match a.discoverable {
Some(ref disc) => Some(Box::new(clone_bt_fidl_bool(disc))),
None => None,
};
let discovering = match a.discovering {
Some(ref disc) => Some(Box::new(clone_bt_fidl_bool(disc))),
None => None,
};
AdapterState {
local_name: a.local_name.clone(),
discovering: discovering,
discoverable: discoverable,
local_service_uuids: a.local_service_uuids.clone(),
}
}
/// Clone RemoteDevice data, as clone is not implemented for FIDL types
pub fn clone_remote_device(d: &RemoteDevice) -> RemoteDevice {
fn copy_option_int8(opt: &Option<Box<Int8>>) -> Option<Box<Int8>> {
match opt {
Some(i) => Some(Box::new(Int8 { value: i.value })),
None => None,
}
}
RemoteDevice {
identifier: d.identifier.clone(),
address: d.address.clone(),
technology: d.technology.clone(),
name: d.name.clone(),
appearance: d.appearance.clone(),
rssi: copy_option_int8(&d.rssi),
tx_power: copy_option_int8(&d.tx_power),
connected: d.connected,
bonded: d.bonded,
service_uuids: d.service_uuids.iter().cloned().collect(),
}
}
pub trait CollectExt {
type Item;
type Err;
/// Collect an iterator of Results into a Result of a Vector. If all results are
/// `Ok`, then return `Ok` of the results. Otherwise return the first `Err` encountered.
/// This method exists primarily to improve type inference and remove the need for manual type
/// ascriptions
fn collect_results(self) -> Result<Vec<Self::Item>, Self::Err>;
}
impl<I, T, E> CollectExt for I
where
I: Iterator<Item = Result<T, E>>,
{
type Item = T;
type Err = E;
fn collect_results(self) -> Result<Vec<Self::Item>, Self::Err> {
self.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn collect_results_all_ok() {
let v: Vec<Result<u64, ()>> = vec![Ok(1), Ok(2), Ok(3)];
assert_eq!(v.into_iter().collect_results(), Ok(vec![1, 2, 3]));
}
#[test]
fn collect_results_returns_first_err() {
let v: Vec<Result<u64, &'static str>> = vec![Ok(1), Err("2"), Err("3")];
assert_eq!(v.into_iter().collect_results(), Err("2"));
}
}