Skip to main content

bluetooth_rust/
lib.rs

1#![deny(missing_docs)]
2#![deny(clippy::missing_docs_in_private_items)]
3#![warn(unused_extern_crates)]
4
5//! This library is intended to eventually be a cross-platform bluetooth handling platform
6//! Android portions adapted from <https://github.com/wuwbobo2021/android-bluetooth-serial-rs>
7
8#[cfg(target_os = "android")]
9use std::sync::Arc;
10#[cfg(target_os = "android")]
11use std::sync::Mutex;
12#[cfg(target_os = "android")]
13mod android;
14#[cfg(target_os = "android")]
15pub use android::Bluetooth;
16#[cfg(target_os = "android")]
17pub use android::Java;
18#[cfg(target_os = "android")]
19use winit::platform::android::activity::AndroidApp;
20
21#[cfg(target_os = "linux")]
22mod linux;
23
24#[cfg(target_os = "windows")]
25mod windows;
26
27mod bluetooth_uuid;
28pub use bluetooth_uuid::BluetoothUuid;
29
30/// Commands issued to the library
31#[derive(Debug, serde::Deserialize, serde::Serialize)]
32pub enum BluetoothCommand {
33    /// Detect all bluetooth adapters present on the system
34    DetectAdapters,
35    /// Find out how many bluetooth adapters are detected
36    QueryNumAdapters,
37}
38
39/// Messages that can be sent specifically to the app user hosting the bluetooth controls
40pub enum MessageToBluetoothHost {
41    /// The passkey used for pairing devices
42    DisplayPasskey(u32, tokio::sync::mpsc::Sender<ResponseToPasskey>),
43    /// The passkey to confirm for pairing
44    ConfirmPasskey(u32, tokio::sync::mpsc::Sender<ResponseToPasskey>),
45    /// Cancal the passkey display
46    CancelDisplayPasskey,
47}
48
49#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
50/// Messages that are send directly from the bluetooth host
51pub enum MessageFromBluetoothHost {
52    /// A response about the active pairing passkey
53    PasskeyMessage(ResponseToPasskey),
54}
55
56#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
57/// The user response to a bluetooth passkey
58pub enum ResponseToPasskey {
59    /// The passkey is accepted
60    Yes,
61    /// The passkey is not accepted
62    No,
63    /// The process is canceled by the user
64    Cancel,
65    /// Waiting on the user to decide
66    Waiting,
67}
68
69/// Responses issued by the library
70pub enum BluetoothResponse {
71    /// The number of bluetooth adapters detected
72    Adapters(usize),
73}
74
75/// Settings for an rfcomm profile
76#[derive(Clone)]
77pub struct BluetoothRfcommProfileSettings {
78    /// The uuid for the profile
79    pub uuid: String,
80    /// User readable name for the profile
81    pub name: Option<String>,
82    /// The service uuid for the profile (can be the same as service)
83    pub service_uuid: Option<String>,
84    /// The channel to use
85    pub channel: Option<u16>,
86    /// PSM number used for UUIDS and SDP (if applicable)
87    pub psm: Option<u16>,
88    /// Is authentication required for a connection
89    pub authenticate: Option<bool>,
90    /// Is authorization required for a connection
91    pub authorize: Option<bool>,
92    /// For client profiles, This will force connection of the channel when a remote device is connected
93    pub auto_connect: Option<bool>,
94    /// manual SDP record
95    pub sdp_record: Option<String>,
96    /// SDP version
97    pub sdp_version: Option<u16>,
98    /// SDP profile features
99    pub sdp_features: Option<u16>,
100}
101
102/// Settings for an rfcomm profile
103#[derive(Clone)]
104pub struct BluetoothL2capProfileSettings {
105    /// The uuid for the profile
106    pub uuid: String,
107    /// User readable name for the profile
108    pub name: Option<String>,
109    /// The service uuid for the profile (can be the same as service)
110    pub service_uuid: Option<String>,
111    /// The channel to use
112    pub channel: Option<u16>,
113    /// PSM number used for UUIDS and SDP (if applicable)
114    pub psm: Option<u16>,
115    /// Is authentication required for a connection
116    pub authenticate: Option<bool>,
117    /// Is authorization required for a connection
118    pub authorize: Option<bool>,
119    /// For client profiles, This will force connection of the channel when a remote device is connected
120    pub auto_connect: Option<bool>,
121    /// manual SDP record
122    pub sdp_record: Option<String>,
123    /// SDP version
124    pub sdp_version: Option<u16>,
125    /// SDP profile features
126    pub sdp_features: Option<u16>,
127}
128
129/// The trait that implements managing when bluetooth discovery is enabled
130#[enum_dispatch::enum_dispatch]
131pub trait BluetoothDiscoveryTrait {}
132
133/// The trait for the object that manages bluetooth discovery
134#[enum_dispatch::enum_dispatch(BluetoothDiscoveryTrait)]
135pub enum BluetoothDiscovery {
136    /// The android version
137    #[cfg(target_os = "android")]
138    Android(android::BluetoothDiscovery),
139    /// Linux bluez library implementation
140    #[cfg(target_os = "linux")]
141    Bluez(linux::BluetoothDiscovery),
142    /// Windows implementation
143    #[cfg(target_os = "windows")]
144    Windows(windows::BluetoothDiscovery),
145}
146
147/// The address of a bluetooth adapter
148pub enum BluetoothAdapterAddress {
149    /// The address in string form
150    String(String),
151    /// The address in byte form
152    Byte([u8; 6]),
153}
154
155/// Common async functionality for the bluetooth adapter
156#[enum_dispatch::enum_dispatch]
157#[async_trait::async_trait]
158pub trait AsyncBluetoothAdapterTrait {
159    /// Attempt to register a new rfcomm profile
160    async fn register_rfcomm_profile(
161        &self,
162        settings: BluetoothRfcommProfileSettings,
163    ) -> Result<BluetoothRfcommProfileAsync, String>;
164    /// Attempt to register a new l2cap profile
165    async fn register_l2cap_profile(
166        &self,
167        settings: BluetoothL2capProfileSettings,
168    ) -> Result<BluetoothL2capProfileAsync, String>;
169    ///Get a list of paired bluetooth devices
170    fn get_paired_devices(&self) -> Option<Vec<BluetoothDevice>>;
171    /// Start discovery of bluetooth devices. Run this and drop the result to cancel discovery
172    fn start_discovery(&self) -> BluetoothDiscovery;
173    /// Get the mac addresses of all bluetooth adapters for the system
174    async fn addresses(&self) -> Vec<BluetoothAdapterAddress>;
175    /// Set the discoverable property
176    async fn set_discoverable(&self, d: bool) -> Result<(), ()>;
177}
178
179/// Common sync functionality for the bluetooth adapter
180#[enum_dispatch::enum_dispatch]
181pub trait SyncBluetoothAdapterTrait {
182    /// Attempt to register a new rfcomm profile
183    fn register_rfcomm_profile(
184        &self,
185        settings: BluetoothRfcommProfileSettings,
186    ) -> Result<BluetoothRfcommProfileSync, String>;
187    /// Attempt to register a new lc2ap profile
188    fn register_l2cap_profile(
189        &self,
190        settings: BluetoothL2capProfileSettings,
191    ) -> Result<BluetoothL2capProfileAsync, String>;
192    ///Get a list of paired bluetooth devices
193    fn get_paired_devices(&self) -> Option<Vec<BluetoothDevice>>;
194    /// Start discovery of bluetooth devices. Run this and drop the result to cancel discovery
195    fn start_discovery(&self) -> BluetoothDiscovery;
196    /// Get the mac addresses of all bluetooth adapters for the system
197    fn addresses(&self) -> Vec<BluetoothAdapterAddress>;
198    /// Set the discoverable property
199    fn set_discoverable(&self, d: bool) -> Result<(), ()>;
200}
201
202/// Common functionality for the bluetooth adapter
203#[enum_dispatch::enum_dispatch]
204pub trait BluetoothAdapterTrait {
205    /// Returns Some when the async interface is supported
206    fn supports_async(&self) -> Option<&dyn AsyncBluetoothAdapterTrait>;
207    /// Returns Some when the sync interface is supported
208    fn supports_sync(&self) -> Option<&dyn SyncBluetoothAdapterTrait>;
209}
210
211/// The pairing status of a bluetooth device
212pub enum PairingStatus {
213    /// The device is not paired
214    NotPaired,
215    /// The device is in the pairing process
216    Pairing,
217    /// The device is paired
218    Paired,
219    /// The status is unknown or invalid
220    Unknown,
221}
222
223/// The trait that all bluetooth devices must implement
224#[enum_dispatch::enum_dispatch]
225pub trait BluetoothDeviceTrait {
226    /// Get all known uuids for this device
227    fn get_uuids(&mut self) -> Result<Vec<BluetoothUuid>, std::io::Error>;
228
229    /// Retrieve the device name
230    fn get_name(&self) -> Result<String, std::io::Error>;
231
232    /// Retrieve the device address
233    fn get_address(&mut self) -> Result<String, std::io::Error>;
234
235    /// Retrieve the device pairing status
236    fn get_pair_state(&self) -> Result<PairingStatus, std::io::Error>;
237
238    /// Attempt to get an rfcomm socket for the given uuid and security setting
239    fn get_rfcomm_socket(
240        &mut self,
241        uuid: BluetoothUuid,
242        is_secure: bool,
243    ) -> Result<BluetoothSocket, String>;
244
245    /// Attempt to get an l2cap socket for the given uuid and security setting
246    fn get_l2cap_socket(
247        &mut self,
248        uuid: BluetoothUuid,
249        is_secure: bool,
250    ) -> Result<BluetoothSocket, String>;
251
252    /// Run the service discovery protocol
253    fn run_sdp(&mut self);
254}
255
256/// A bluetooth device
257#[enum_dispatch::enum_dispatch(BluetoothDeviceTrait)]
258pub enum BluetoothDevice {
259    /// Bluetooth device on android
260    #[cfg(target_os = "android")]
261    Android(android::BluetoothDevice),
262    /// Bluetooth device on linux using the bluez library
263    #[cfg(target_os = "linux")]
264    Bluez(linux::LinuxBluetoothDevice),
265    /// Bluetooth device on Windows
266    #[cfg(target_os = "windows")]
267    Windows(windows::BluetoothDevice),
268}
269
270/// Represents a bluetooth adapter that communicates to bluetooth devices
271#[enum_dispatch::enum_dispatch(BluetoothAdapterTrait)]
272pub enum BluetoothAdapter {
273    /// The bluetooth adapter for android systems
274    #[cfg(target_os = "android")]
275    Android(android::Bluetooth),
276    /// On linux, bluetooth adapter using the bluez library
277    #[cfg(target_os = "linux")]
278    Bluez(linux::BluetoothHandler),
279    /// On Windows, bluetooth adapter using the windows crate
280    #[cfg(target_os = "windows")]
281    Windows(windows::BluetoothHandler),
282}
283
284/// A builder for `BluetoothAdapter`
285pub struct BluetoothAdapterBuilder {
286    /// The androidapp object
287    #[cfg(target_os = "android")]
288    app: Option<AndroidApp>,
289    /// The sender to send messages to the bluetooth host
290    s: Option<tokio::sync::mpsc::Sender<MessageToBluetoothHost>>,
291}
292
293impl Default for BluetoothAdapterBuilder {
294    fn default() -> Self {
295        Self::new()
296    }
297}
298
299impl BluetoothAdapterBuilder {
300    /// Construct a new self
301    pub fn new() -> Self {
302        Self {
303            #[cfg(target_os = "android")]
304            app: None,
305            s: None,
306        }
307    }
308
309    /// Put the required `AndroidApp` object into the builder
310    #[cfg(target_os = "android")]
311    pub fn with_android_app(&mut self, app: AndroidApp) {
312        self.app = Some(app);
313    }
314
315    /// Add the sender to the builder
316    pub fn with_sender(&mut self, s: tokio::sync::mpsc::Sender<MessageToBluetoothHost>) {
317        self.s = Some(s);
318    }
319
320    /// Do the build
321    pub fn build(self) -> Result<BluetoothAdapter, String> {
322        #[cfg(target_os = "android")]
323        {
324            return Ok(BluetoothAdapter::Android(android::Bluetooth::new(
325                self.app.unwrap(),
326            )));
327        }
328        Err("No synchronous builders available".to_string())
329    }
330
331    /// Do the build
332    pub async fn async_build(self) -> Result<BluetoothAdapter, String> {
333        #[cfg(target_os = "android")]
334        {
335            return self.build();
336        }
337        #[cfg(target_os = "linux")]
338        {
339            return Ok(BluetoothAdapter::Bluez(
340                linux::BluetoothHandler::new(self.s.unwrap()).await?,
341            ));
342        }
343        #[cfg(target_os = "windows")]
344        {
345            return Ok(BluetoothAdapter::Windows(
346                windows::BluetoothHandler::new(self.s.unwrap()).await?,
347            ));
348        }
349        Err("No async builders available".to_string())
350    }
351}
352
353/// An active stream for bluetooth communications
354pub enum BluetoothStream {
355    /// On linux, a stream using the bluez library
356    #[cfg(target_os = "linux")]
357    Bluez(std::pin::Pin<Box<bluer::rfcomm::Stream>>),
358    /// Android code for a bluetooth stream
359    #[cfg(target_os = "android")]
360    Android(android::RfcommStream),
361    /// Windows RFCOMM stream
362    #[cfg(target_os = "windows")]
363    Windows(windows::WindowsRfcommStream),
364}
365
366macro_rules! pin_match {
367    ($this:expr, $s:ident => $body:expr) => {
368        match $this.get_mut() {
369            #[cfg(target_os = "linux")]
370            BluetoothStream::Bluez($s) => $body,
371
372            #[cfg(target_os = "android")]
373            BluetoothStream::Android($s) => $body,
374
375            #[cfg(target_os = "windows")]
376            BluetoothStream::Windows($s) => $body,
377        }
378    };
379}
380
381impl tokio::io::AsyncWrite for BluetoothStream {
382    fn poll_write(
383        self: std::pin::Pin<&mut Self>,
384        cx: &mut std::task::Context<'_>,
385        buf: &[u8],
386    ) -> std::task::Poll<std::io::Result<usize>> {
387        pin_match!(self, s => {
388            // SAFETY: we delegate to inner stream directly
389            tokio::io::AsyncWrite::poll_write(std::pin::Pin::new(s), cx, buf)
390        })
391    }
392
393    fn poll_flush(
394        self: std::pin::Pin<&mut Self>,
395        cx: &mut std::task::Context<'_>,
396    ) -> std::task::Poll<std::io::Result<()>> {
397        pin_match!(self, s => {
398            tokio::io::AsyncWrite::poll_flush(std::pin::Pin::new(s), cx)
399        })
400    }
401
402    fn poll_shutdown(
403        self: std::pin::Pin<&mut Self>,
404        cx: &mut std::task::Context<'_>,
405    ) -> std::task::Poll<std::io::Result<()>> {
406        pin_match!(self, s => {
407            tokio::io::AsyncWrite::poll_shutdown(std::pin::Pin::new(s), cx)
408        })
409    }
410}
411
412impl tokio::io::AsyncRead for BluetoothStream {
413    fn poll_read(
414        self: std::pin::Pin<&mut Self>,
415        cx: &mut std::task::Context<'_>,
416        buf: &mut tokio::io::ReadBuf<'_>,
417    ) -> std::task::Poll<std::io::Result<()>> {
418        pin_match!(self, s => {
419            tokio::io::AsyncRead::poll_read(std::pin::Pin::new(s), cx, buf)
420        })
421    }
422}
423
424impl BluetoothStream {
425    /// Used to check to see if the object supports async read, and then use the functionality
426    pub fn supports_async_read(&mut self) -> Option<&mut dyn tokio::io::AsyncRead> {
427        match self {
428            #[cfg(target_os = "linux")]
429            BluetoothStream::Bluez(pin) => Some(pin),
430            #[cfg(target_os = "android")]
431            BluetoothStream::Android(_pin) => None,
432            #[cfg(target_os = "windows")]
433            BluetoothStream::Windows(_pin) => None,
434        }
435    }
436
437    /// Used to check to see if the object supports async write, and then use the functionality
438    pub fn supports_async_write(&mut self) -> Option<&mut dyn tokio::io::AsyncWrite> {
439        match self {
440            #[cfg(target_os = "linux")]
441            BluetoothStream::Bluez(pin) => Some(pin),
442            #[cfg(target_os = "android")]
443            BluetoothStream::Android(_pin) => None,
444            #[cfg(target_os = "windows")]
445            BluetoothStream::Windows(_pin) => None,
446        }
447    }
448
449    /// Used to try to use synchronous read functionality
450    pub fn supports_sync_read(&mut self) -> Option<&mut dyn std::io::Read> {
451        match self {
452            #[cfg(target_os = "linux")]
453            BluetoothStream::Bluez(_pin) => None,
454            #[cfg(target_os = "android")]
455            BluetoothStream::Android(pin) => Some(pin),
456            #[cfg(target_os = "windows")]
457            BluetoothStream::Windows(pin) => Some(pin),
458        }
459    }
460
461    /// Used to try to use synchronous write functionality
462    pub fn supports_sync_write(&mut self) -> Option<&mut dyn std::io::Write> {
463        match self {
464            #[cfg(target_os = "linux")]
465            BluetoothStream::Bluez(_pin) => None,
466            #[cfg(target_os = "android")]
467            BluetoothStream::Android(pin) => Some(pin),
468            #[cfg(target_os = "windows")]
469            BluetoothStream::Windows(pin) => Some(pin),
470        }
471    }
472}
473
474/// The trait for bluetooth rfcomm objects that can be connected or accepted
475#[async_trait::async_trait]
476#[enum_dispatch::enum_dispatch]
477pub trait BluetoothRfcommConnectableAsyncTrait {
478    /// Accept a connection from a bluetooth peer
479    async fn accept(self) -> Result<BluetoothStream, String>;
480}
481
482/// A bluetooth profile for rfcomm channels
483#[enum_dispatch::enum_dispatch(BluetoothRfcommConnectableAsyncTrait)]
484pub enum BluetoothRfcommConnectableAsync {
485    /// The android object for the profile
486    #[cfg(target_os = "android")]
487    Android(android::BluetoothRfcommConnectable),
488    /// The bluez library in linux is responsible for the profile
489    #[cfg(target_os = "linux")]
490    Bluez(bluer::rfcomm::ConnectRequest),
491    /// Windows RFCOMM connectable
492    #[cfg(target_os = "windows")]
493    Windows(windows::BluetoothRfcommConnectable),
494}
495
496/// The trait for bluetooth rfcomm objects that can be connected or accepted
497#[enum_dispatch::enum_dispatch]
498pub trait BluetoothRfcommConnectableSyncTrait {
499    /// Accept a connection from a bluetooth peer
500    fn accept(self, timeout: std::time::Duration) -> Result<BluetoothStream, String>;
501}
502
503/// A bluetooth profile for rfcomm channels
504#[enum_dispatch::enum_dispatch(BluetoothRfcommConnectableSyncTrait)]
505pub enum BluetoothRfcommConnectableSync {
506    /// The android object for the profile
507    #[cfg(target_os = "android")]
508    Android(android::BluetoothRfcommConnectable),
509}
510
511/// The trait for bluetooth rfcomm objects that can be connected or accepted
512#[enum_dispatch::enum_dispatch]
513pub trait BluetoothL2capConnectableAsyncTrait {
514    /// Accept a connection from a bluetooth peer
515    async fn accept(self) -> Result<BluetoothStream, String>;
516}
517
518/// A bluetooth profile for rfcomm channels
519#[enum_dispatch::enum_dispatch(BluetoothL2capConnectableTrait)]
520pub enum BluetoothL2capConnectableAsync {
521    /// The android object for the profile
522    #[cfg(target_os = "android")]
523    Android(android::BluetoothRfcommConnectable),
524    /// The bluez library in linux is responsible for the profile
525    #[cfg(target_os = "linux")]
526    Bluez(bluer::rfcomm::ConnectRequest),
527}
528
529/// The trait for bluetooth rfcomm objects that can be connected or accepted
530#[enum_dispatch::enum_dispatch]
531pub trait BluetoothL2capConnectableSyncTrait {
532    /// Accept a connection from a bluetooth peer
533    fn accept(self, timeout: std::time::Duration) -> Result<BluetoothStream, String>;
534}
535
536/// A bluetooth profile for rfcomm channels
537#[enum_dispatch::enum_dispatch(BluetoothL2capConnectableSyncTrait)]
538pub enum BluetoothL2capConnectableSync {
539    /// The android object for the profile
540    #[cfg(target_os = "android")]
541    Android(android::BluetoothRfcommConnectable),
542}
543
544/// Allows building an object to connect to bluetooth devices
545#[enum_dispatch::enum_dispatch]
546pub trait BluetoothRfcommProfileAsyncTrait {
547    /// Get an object in order to accept a connection from or connect to a bluetooth peer
548    async fn connectable(&mut self) -> Result<BluetoothRfcommConnectableAsync, String>;
549}
550
551/// Allows building an object to connect to bluetooth devices
552#[enum_dispatch::enum_dispatch]
553pub trait BluetoothRfcommProfileSyncTrait {
554    /// Get an object in order to accept a connection from or connect to a bluetooth peer
555    fn connectable(&mut self) -> Result<BluetoothRfcommConnectableSync, String>;
556}
557
558/// A bluetooth profile for rfcomm channels
559#[enum_dispatch::enum_dispatch(BluetoothRfcommProfileAsyncTrait)]
560pub enum BluetoothRfcommProfileAsync {
561    /// The bluez library in linux is responsible for the profile
562    #[cfg(target_os = "linux")]
563    Bluez(bluer::rfcomm::ProfileHandle),
564    /// Windows RFCOMM profile
565    #[cfg(target_os = "windows")]
566    Windows(windows::BluetoothRfcommProfile),
567    /// A dummy handler
568    Dummy(Dummy),
569}
570
571/// A bluetooth profile for rfcomm channels
572#[enum_dispatch::enum_dispatch(BluetoothRfcommProfileSyncTrait)]
573pub enum BluetoothRfcommProfileSync {
574    /// Android rfcomm profile
575    #[cfg(target_os = "android")]
576    Android(android::BluetoothRfcommProfile),
577    /// A dummy handler
578    Dummy(Dummy),
579}
580
581/// A bluetooth profile for rfcomm channels
582#[enum_dispatch::enum_dispatch(BluetoothL2capProfileAsyncTrait)]
583pub enum BluetoothL2capProfileAsync {
584    /// The bluez library in linux is responsible for the profile
585    #[cfg(target_os = "linux")]
586    Bluez(bluer::rfcomm::ProfileHandle),
587    /// A dummy handler
588    Dummy(Dummy),
589}
590
591/// A bluetooth profile for rfcomm channels
592#[enum_dispatch::enum_dispatch(BluetoothL2capProfileSyncTrait)]
593pub enum BluetoothL2capProfileSync {
594    /// Android rfcomm profile
595    #[cfg(target_os = "android")]
596    Android(android::BluetoothRfcommProfile),
597    /// A dummy handler
598    Dummy(Dummy),
599}
600
601/// A dummy struct for ensuring enums are not empty
602pub struct Dummy {}
603
604impl BluetoothRfcommProfileSyncTrait for Dummy {
605    fn connectable(&mut self) -> Result<BluetoothRfcommConnectableSync, String> {
606        unimplemented!()
607    }
608}
609
610impl BluetoothRfcommProfileAsyncTrait for Dummy {
611    async fn connectable(&mut self) -> Result<BluetoothRfcommConnectableAsync, String> {
612        unimplemented!()
613    }
614}
615
616/// The common functions for all bluetooth rfcomm sockets
617#[enum_dispatch::enum_dispatch]
618pub trait BluetoothSocketTrait {
619    /// Is the socket connected
620    fn is_connected(&self) -> Result<bool, std::io::Error>;
621    /// connect the socket
622    fn connect(&mut self) -> Result<(), std::io::Error>;
623}
624
625impl<'a> std::io::Read for BluetoothSocket<'a> {
626    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
627        match self {
628            #[cfg(target_os = "android")]
629            BluetoothSocket::Android(a) => a.read(buf),
630            #[cfg(target_os = "linux")]
631            BluetoothSocket::Bluez(b) => b.read(buf),
632            #[cfg(target_os = "windows")]
633            BluetoothSocket::Windows(w) => w.read(buf),
634        }
635    }
636}
637
638impl<'a> std::io::Write for BluetoothSocket<'a> {
639    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
640        match self {
641            #[cfg(target_os = "android")]
642            BluetoothSocket::Android(a) => a.write(buf),
643            #[cfg(target_os = "linux")]
644            BluetoothSocket::Bluez(b) => b.write(buf),
645            #[cfg(target_os = "windows")]
646            BluetoothSocket::Windows(w) => w.write(buf),
647        }
648    }
649
650    fn flush(&mut self) -> std::io::Result<()> {
651        match self {
652            #[cfg(target_os = "android")]
653            BluetoothSocket::Android(a) => a.flush(),
654            #[cfg(target_os = "linux")]
655            BluetoothSocket::Bluez(b) => b.flush(),
656            #[cfg(target_os = "windows")]
657            BluetoothSocket::Windows(w) => w.flush(),
658        }
659    }
660}
661
662/// A bluetooth rfcomm socket
663#[enum_dispatch::enum_dispatch(BluetoothSocketTrait)]
664pub enum BluetoothSocket<'a> {
665    /// The android based rfcomm socket
666    #[cfg(target_os = "android")]
667    Android(&'a mut android::BluetoothSocket),
668    /// Linux using bluez library
669    #[cfg(target_os = "linux")]
670    Bluez(&'a mut linux::BluetoothRfcommSocket),
671    /// Windows bluetooth socket
672    #[cfg(target_os = "windows")]
673    Windows(&'a mut windows::BluetoothRfcommSocket),
674}