bleasy/scanner/
config.rs

1use std::time::Duration;
2use uuid::Uuid;
3
4#[derive(Debug, Clone, Hash, Eq, PartialEq)]
5pub enum Filter {
6    Address(String),
7    Characteristic(Uuid),
8    Name(String),
9    Rssi(i16),
10    Service(Uuid),
11}
12
13#[derive(Default)]
14pub struct ScanConfig {
15    /// Index of the Bluetooth adapter to use. The first found adapter is used by default.
16    pub(crate) adapter_index: usize,
17    /// Filters objects
18    pub(crate) filters: Vec<Filter>,
19    /// Filters the found devices based on device address.
20    pub(crate) address_filter: Option<Box<dyn Fn(&str, &str) -> bool + Send + Sync>>,
21    /// Filters the found devices based on local name.
22    pub(crate) name_filter: Option<Box<dyn Fn(&str, &str) -> bool + Send + Sync>>,
23    /// Filters the found devices based on rssi.
24    pub(crate) rssi_filter: Option<Box<dyn Fn(i16, i16) -> bool + Send + Sync>>,
25    /// Filters the found devices based on service's uuid.
26    pub(crate) service_filter: Option<Box<dyn Fn(&Vec<Uuid>, &Uuid) -> bool + Send + Sync>>,
27    /// Filters the found devices based on characteristics. Requires a connection to the device.
28    pub(crate) characteristics_filter: Option<Box<dyn Fn(&Vec<Uuid>, &Uuid) -> bool + Send + Sync>>,
29    /// Maximum results before the scan is stopped.
30    pub(crate) max_results: Option<usize>,
31    /// The scan is stopped when timeout duration is reached.
32    pub(crate) timeout: Option<Duration>,
33    /// Force disconnect when listen the device is connected.
34    pub(crate) force_disconnect: bool,
35}
36
37impl ScanConfig {
38    /// Index of bluetooth adapter to use
39    #[inline]
40    pub fn adapter_index(mut self, index: usize) -> Self {
41        self.adapter_index = index;
42        self
43    }
44
45    #[inline]
46    pub fn with_filters(mut self, filters: &[Filter]) -> Self {
47        self.filters.extend_from_slice(filters);
48        self
49    }
50
51    /// Filter scanned devices based on the device address
52    #[inline]
53    pub fn filter_by_address(
54        mut self,
55        func: impl Fn(&str, &str) -> bool + Send + Sync + 'static,
56    ) -> Self {
57        self.address_filter = Some(Box::new(func));
58        self
59    }
60
61    /// Filter scanned devices based on the device name
62    #[inline]
63    pub fn filter_by_name(
64        mut self,
65        func: impl Fn(&str, &str) -> bool + Send + Sync + 'static,
66    ) -> Self {
67        self.name_filter = Some(Box::new(func));
68        self
69    }
70
71    #[inline]
72    pub fn filter_by_rssi(
73        mut self,
74        func: impl Fn(i16, i16) -> bool + Send + Sync + 'static,
75    ) -> Self {
76        self.rssi_filter = Some(Box::new(func));
77        self
78    }
79
80    #[inline]
81    pub fn filter_by_service(
82        mut self,
83        func: impl Fn(&Vec<Uuid>, &Uuid) -> bool + Send + Sync + 'static,
84    ) -> Self {
85        self.service_filter = Some(Box::new(func));
86        self
87    }
88
89    /// Filter scanned devices based on available characteristics
90    #[inline]
91    pub fn filter_by_characteristics(
92        mut self,
93        func: impl Fn(&Vec<Uuid>, &Uuid) -> bool + Send + Sync + 'static,
94    ) -> Self {
95        self.characteristics_filter = Some(Box::new(func));
96        self
97    }
98
99    /// Stop the scan after given number of matches
100    #[inline]
101    pub fn stop_after_matches(mut self, max_results: usize) -> Self {
102        self.max_results = Some(max_results);
103        self
104    }
105
106    /// Stop the scan after the first match
107    #[inline]
108    pub fn stop_after_first_match(self) -> Self {
109        self.stop_after_matches(1)
110    }
111
112    /// Stop the scan after given duration
113    #[inline]
114    pub fn stop_after_timeout(mut self, timeout: Duration) -> Self {
115        self.timeout = Some(timeout);
116        self
117    }
118
119    #[inline]
120    pub fn force_disconnect(mut self, force_disconnect: bool) -> Self {
121        self.force_disconnect = force_disconnect;
122        self
123    }
124
125    /// Require that the scanned devices have a name
126    #[inline]
127    pub fn require_name(self) -> Self {
128        if self.name_filter.is_none() {
129            self.filter_by_name(|src, _| !src.is_empty())
130        } else {
131            self
132        }
133    }
134}