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) -> bool + Send + Sync>>,
21    /// Filters the found devices based on local name.
22    pub(crate) name_filter: Option<Box<dyn Fn(&str) -> bool + Send + Sync>>,
23    /// Filters the found devices based on rssi.
24    pub(crate) rssi_filter: Option<Box<dyn Fn(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>) -> 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) -> 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(mut self, func: impl Fn(&str) -> bool + Send + Sync + 'static) -> Self {
64        self.name_filter = Some(Box::new(func));
65        self
66    }
67
68    #[inline]
69    pub fn filter_by_rssi(mut self, func: impl Fn(i16) -> bool + Send + Sync + 'static) -> Self {
70        self.rssi_filter = Some(Box::new(func));
71        self
72    }
73
74    #[inline]
75    pub fn filter_by_service(
76        mut self,
77        func: impl Fn(&Vec<Uuid>, &Uuid) -> bool + Send + Sync + 'static,
78    ) -> Self {
79        self.service_filter = Some(Box::new(func));
80        self
81    }
82
83    /// Filter scanned devices based on available characteristics
84    #[inline]
85    pub fn filter_by_characteristics(
86        mut self,
87        func: impl Fn(&Vec<Uuid>) -> bool + Send + Sync + 'static,
88    ) -> Self {
89        self.characteristics_filter = Some(Box::new(func));
90        self
91    }
92
93    /// Stop the scan after given number of matches
94    #[inline]
95    pub fn stop_after_matches(mut self, max_results: usize) -> Self {
96        self.max_results = Some(max_results);
97        self
98    }
99
100    /// Stop the scan after the first match
101    #[inline]
102    pub fn stop_after_first_match(self) -> Self {
103        self.stop_after_matches(1)
104    }
105
106    /// Stop the scan after given duration
107    #[inline]
108    pub fn stop_after_timeout(mut self, timeout: Duration) -> Self {
109        self.timeout = Some(timeout);
110        self
111    }
112
113    #[inline]
114    pub fn force_disconnect(mut self, force_disconnect: bool) -> Self {
115        self.force_disconnect = force_disconnect;
116        self
117    }
118
119    /// Require that the scanned devices have a name
120    #[inline]
121    pub fn require_name(self) -> Self {
122        if self.name_filter.is_none() {
123            self.filter_by_name(|src| !src.is_empty())
124        } else {
125            self
126        }
127    }
128}