| // Copyright 2023 Google LLC | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | use crate::{central::ScanResult, client::CharacteristicNotification, types::*}; | 
 |  | 
 | use bt_common::{PeerId, Uuid}; | 
 | use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; | 
 | use futures::{Future, Stream}; | 
 | use futures::future::{Ready, ready}; | 
 | use parking_lot::Mutex; | 
 | use std::collections::HashMap; | 
 | use std::task::Poll; | 
 | use std::sync::Arc; | 
 |  | 
 | #[derive(Default)] | 
 | pub(crate) struct FakeCentral {} | 
 |  | 
 | #[derive(Default)] | 
 | struct FakePeerServiceInner { | 
 |     // Notifier that's used to send out notification. | 
 |     notifiers: HashMap<Handle, UnboundedSender<Result<CharacteristicNotification>>>, | 
 |  | 
 |     // Characteristics to return when `read_characteristic` and `discover_characteristics` are called. | 
 |     characteristics: HashMap<Handle, (Characteristic, Vec<u8>)>, | 
 | } | 
 |  | 
 | #[derive(Clone)] | 
 | pub struct FakePeerService { | 
 |     inner: Arc<Mutex<FakePeerServiceInner>>, | 
 | } | 
 |  | 
 | impl FakePeerService { | 
 |     pub fn new() -> Self { | 
 |         Self { inner: Arc::new(Mutex::new(Default::default())) } | 
 |     } | 
 |  | 
 |     // Adds a characteristic so that it can be returned when discover/read method is | 
 |     // called. | 
 |     // Also triggers sending a characteristic value change notification to be sent. | 
 |     pub fn add_characteristic(&mut self, char: Characteristic, value: Vec<u8>) { | 
 |         let mut lock = self.inner.lock(); | 
 |         let handle = char.handle; | 
 |         lock.characteristics.insert(handle, (char, value.clone())); | 
 |         if let Some(notifier) = lock.notifiers.get_mut(&handle) { | 
 |             notifier.unbounded_send(Ok(CharacteristicNotification { handle, value, maybe_truncated: false })).expect("should succeed"); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl crate::client::PeerService for FakePeerService { | 
 |     type CharacteristicsFut = Ready<Result<Vec<Characteristic>>>; | 
 |     type NotificationStream = UnboundedReceiver<Result<CharacteristicNotification>>; | 
 |     type ReadFut<'a> = Ready<Result<(usize, bool)>>; | 
 |     type WriteFut<'a> = Ready<Result<()>>; | 
 |  | 
 |     fn discover_characteristics(&self, uuid: Option<Uuid>) -> Self::CharacteristicsFut { | 
 |         let lock = self.inner.lock(); | 
 |         let mut result = Vec::new(); | 
 |         for (_handle, (char, _value))in &lock.characteristics { | 
 |             match uuid { | 
 |                 Some(uuid) if uuid == char.uuid => result.push(char.clone()), | 
 |                 None => result.push(char.clone()), | 
 |                 _ => {}, | 
 |             } | 
 |         } | 
 |         ready(Ok(result)) | 
 |     } | 
 |  | 
 |     fn read_characteristic<'a>( | 
 |         &self, | 
 |         handle: &Handle, | 
 |         _offset: u16, | 
 |         buf: &'a mut [u8], | 
 |     ) -> Self::ReadFut<'a> { | 
 |         let read_characteristics = &(*self.inner.lock()).characteristics; | 
 |         let Some((_, value)) = read_characteristics.get(handle) else { | 
 |             return ready(Err(Error::Gatt(GattError::InvalidHandle))); | 
 |         }; | 
 |         buf[..value.len()].copy_from_slice(value.as_slice()); | 
 |         ready(Ok((value.len(), false))) | 
 |     } | 
 |  | 
 |     fn write_characteristic<'a>( | 
 |         &self, | 
 |         _handle: &Handle, | 
 |         _mode: WriteMode, | 
 |         _offset: u16, | 
 |         _buf: &'a [u8], | 
 |     ) -> Self::WriteFut<'a> { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn read_descriptor<'a>( | 
 |         &self, | 
 |         _handle: &Handle, | 
 |         _offset: u16, | 
 |         _buf: &'a mut [u8], | 
 |     ) -> Self::ReadFut<'a> { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn write_descriptor<'a>( | 
 |         &self, | 
 |         _handle: &Handle, | 
 |         _offset: u16, | 
 |         _buf: &'a [u8], | 
 |     ) -> Self::WriteFut<'a> { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn subscribe(&self, handle: &Handle) -> Self::NotificationStream { | 
 |         let (sender, receiver) = unbounded(); | 
 |         (*self.inner.lock()).notifiers.insert(*handle, sender); | 
 |         receiver | 
 |     } | 
 | } | 
 |  | 
 | pub(crate) struct FakeServiceHandle {} | 
 |  | 
 | impl crate::client::PeerServiceHandle for FakeServiceHandle { | 
 |     type PeerServiceT = FakePeerService; | 
 |     type ConnectFut = Ready<Result<Self::PeerServiceT>>; | 
 |  | 
 |     fn uuid(&self) -> Uuid { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn is_primary(&self) -> bool { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn connect(&self) -> Self::ConnectFut { | 
 |         todo!() | 
 |     } | 
 | } | 
 |  | 
 | pub(crate) struct FakeClient {} | 
 |  | 
 | impl crate::Client for FakeClient { | 
 |     type PeerServiceHandleT = FakeServiceHandle; | 
 |     type ServiceResultFut = Ready<Result<Vec<Self::PeerServiceHandleT>>>; | 
 |  | 
 |     fn peer_id(&self) -> PeerId { | 
 |         todo!() | 
 |     } | 
 |  | 
 |     fn find_service(&self, _uuid: Uuid) -> Self::ServiceResultFut { | 
 |         todo!() | 
 |     } | 
 | } | 
 |  | 
 | pub(crate) struct SingleResultStream { | 
 |     result: Option<Result<crate::central::ScanResult>>, | 
 | } | 
 |  | 
 | impl Stream for SingleResultStream { | 
 |     type Item = Result<crate::central::ScanResult>; | 
 |  | 
 |     fn poll_next( | 
 |         self: std::pin::Pin<&mut Self>, | 
 |         _cx: &mut std::task::Context<'_>, | 
 |     ) -> Poll<Option<Self::Item>> { | 
 |         if self.result.is_some() { | 
 |             Poll::Ready(self.get_mut().result.take()) | 
 |         } else { | 
 |             // Never wake up, as if we never find another result | 
 |             Poll::Pending | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | pub(crate) struct ClientConnectFut {} | 
 |  | 
 | impl Future for ClientConnectFut { | 
 |     type Output = Result<FakeClient>; | 
 |  | 
 |     fn poll( | 
 |         self: std::pin::Pin<&mut Self>, | 
 |         _cx: &mut std::task::Context<'_>, | 
 |     ) -> Poll<Self::Output> { | 
 |         todo!() | 
 |     } | 
 | } | 
 |  | 
 | impl crate::Central for FakeCentral { | 
 |     type ScanResultStream = SingleResultStream; | 
 |  | 
 |     type Client = FakeClient; | 
 |  | 
 |     type ClientFut = ClientConnectFut; | 
 |  | 
 |     fn scan(&self, _filters: &[crate::central::ScanFilter]) -> Self::ScanResultStream { | 
 |         SingleResultStream { | 
 |             result: Some(Ok(ScanResult { | 
 |                 id: PeerId(1), | 
 |                 connectable: true, | 
 |                 name: crate::central::PeerName::CompleteName("Marie's Pixel 7 Pro".to_owned()), | 
 |                 advertised: vec![crate::central::AdvertisingDatum::Services(vec![ | 
 |                     Uuid::from_u16(0x1844), | 
 |                 ])], | 
 |             })), | 
 |         } | 
 |     } | 
 |  | 
 |     fn connect(&self, _peer_id: PeerId) -> Self::ClientFut { | 
 |         todo!() | 
 |     } | 
 | } |