use crate::types::DeviceId;
use tokio::sync::oneshot;
use uuid::Uuid;
#[derive(Debug)]
pub enum PeripheralEvent {
AdapterStateChanged { powered: bool },
SubscriptionChanged {
client_id: DeviceId,
char_uuid: Uuid,
subscribed: bool,
},
ReadRequest {
client_id: DeviceId,
service_uuid: Uuid,
char_uuid: Uuid,
offset: u16,
responder: ReadResponder,
},
WriteRequest {
client_id: DeviceId,
service_uuid: Uuid,
char_uuid: Uuid,
value: Vec<u8>,
responder: Option<WriteResponder>,
},
}
pub(crate) type ReadResponseTx = oneshot::Sender<Result<Vec<u8>, ()>>;
pub(crate) type WriteResponseTx = oneshot::Sender<bool>;
#[derive(Debug)]
struct ResponderInner<T: Send + Clone + 'static> {
tx: Option<oneshot::Sender<T>>,
error_value: T,
}
impl<T: Send + Clone + 'static> ResponderInner<T> {
fn new(tx: oneshot::Sender<T>, error_value: T) -> Self {
Self {
tx: Some(tx),
error_value,
}
}
fn send(&mut self, value: T) {
if let Some(tx) = self.tx.take() {
let _ = tx.send(value);
}
}
}
impl<T: Send + Clone + 'static> Drop for ResponderInner<T> {
fn drop(&mut self) {
if let Some(tx) = self.tx.take() {
let _ = tx.send(self.error_value.clone());
}
}
}
#[derive(Debug)]
pub struct ReadResponder(ResponderInner<Result<Vec<u8>, ()>>);
impl ReadResponder {
#[allow(dead_code)]
pub(crate) fn new(tx: ReadResponseTx) -> Self {
Self(ResponderInner::new(tx, Err(())))
}
pub fn respond(mut self, value: Vec<u8>) {
self.0.send(Ok(value));
}
pub fn error(mut self) {
self.0.send(Err(()));
}
}
#[derive(Debug)]
pub struct WriteResponder(ResponderInner<bool>);
impl WriteResponder {
#[allow(dead_code)]
pub(crate) fn new(tx: WriteResponseTx) -> Self {
Self(ResponderInner::new(tx, false))
}
pub fn success(mut self) {
self.0.send(true);
}
pub fn error(mut self) {
self.0.send(false);
}
}
#[derive(Debug, Clone)]
pub struct AdvertisingConfig {
pub local_name: String,
pub service_uuids: Vec<Uuid>,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_read_responder_respond() {
let (tx, rx) = oneshot::channel();
let responder = ReadResponder::new(tx);
responder.respond(b"hello".to_vec());
assert_eq!(rx.await.unwrap().unwrap(), b"hello");
}
#[tokio::test]
async fn test_read_responder_error() {
let (tx, rx) = oneshot::channel();
let responder = ReadResponder::new(tx);
responder.error();
assert!(rx.await.unwrap().is_err());
}
#[tokio::test]
async fn test_read_responder_drop_sends_error() {
let (tx, rx) = oneshot::channel();
{
let _responder = ReadResponder::new(tx);
}
assert!(
rx.await.unwrap().is_err(),
"drop must send error automatically"
);
}
#[tokio::test]
async fn test_read_responder_respond_empty() {
let (tx, rx) = oneshot::channel();
let responder = ReadResponder::new(tx);
responder.respond(vec![]);
assert_eq!(rx.await.unwrap().unwrap(), Vec::<u8>::new());
}
#[tokio::test]
async fn test_write_responder_success() {
let (tx, rx) = oneshot::channel();
let responder = WriteResponder::new(tx);
responder.success();
assert!(rx.await.unwrap());
}
#[tokio::test]
async fn test_write_responder_error() {
let (tx, rx) = oneshot::channel();
let responder = WriteResponder::new(tx);
responder.error();
assert!(!rx.await.unwrap());
}
#[tokio::test]
async fn test_write_responder_drop_sends_error() {
let (tx, rx) = oneshot::channel();
{
let _responder = WriteResponder::new(tx);
}
assert!(!rx.await.unwrap(), "drop must send false");
}
#[tokio::test]
async fn test_read_responder_consumed_once() {
let (tx, rx) = oneshot::channel();
let responder = ReadResponder::new(tx);
responder.respond(b"data".to_vec());
let result = rx.await.unwrap();
assert!(result.is_ok());
}
#[tokio::test]
async fn test_write_responder_consumed_once() {
let (tx, rx) = oneshot::channel();
let responder = WriteResponder::new(tx);
responder.success();
let result = rx.await.unwrap();
assert!(result);
}
}