1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::collections::{HashMap, HashSet};
use std::slice::Iter;

use serde::{Deserialize, Serialize};

// A device name can never be longer than 29 bytes. An adv packet is at most
// 31 bytes long. The length and identifier of the length field take 2 bytes.
// That leaves 29 bytes for the name.
const MAX_NAME_LENGTH: usize = 29;

#[derive(Debug, Deserialize, Serialize)]
pub struct ServiceUUIDSequence(Vec<String>);

impl ServiceUUIDSequence {
    pub fn new(vec: Vec<String>) -> ServiceUUIDSequence {
        ServiceUUIDSequence(vec)
    }

    fn get_services_set(&self) -> HashSet<String> {
        self.0.iter().map(String::clone).collect()
    }
}

type ManufacturerData = HashMap<u16, (Vec<u8>, Vec<u8>)>;
type ServiceData = HashMap<String, (Vec<u8>, Vec<u8>)>;

#[derive(Debug, Deserialize, Serialize)]
pub struct BluetoothScanfilter {
    name: Option<String>,
    name_prefix: String,
    services: ServiceUUIDSequence,
    manufacturer_data: Option<ManufacturerData>,
    service_data: Option<ServiceData>,
}

impl BluetoothScanfilter {
    pub fn new(
        name: Option<String>,
        name_prefix: String,
        services: Vec<String>,
        manufacturer_data: Option<ManufacturerData>,
        service_data: Option<ServiceData>,
    ) -> BluetoothScanfilter {
        BluetoothScanfilter {
            name,
            name_prefix,
            services: ServiceUUIDSequence::new(services),
            manufacturer_data,
            service_data,
        }
    }

    pub fn get_name(&self) -> Option<&str> {
        self.name.as_deref()
    }

    pub fn get_name_prefix(&self) -> &str {
        &self.name_prefix
    }

    pub fn get_services(&self) -> &[String] {
        &self.services.0
    }

    pub fn get_manufacturer_data(&self) -> Option<&ManufacturerData> {
        self.manufacturer_data.as_ref()
    }

    pub fn get_service_data(&self) -> Option<&ServiceData> {
        self.service_data.as_ref()
    }

    pub fn is_empty_or_invalid(&self) -> bool {
        (self.name.is_none() &&
            self.name_prefix.is_empty() &&
            self.get_services().is_empty() &&
            self.manufacturer_data.is_none() &&
            self.service_data.is_none()) ||
            self.get_name().unwrap_or("").len() > MAX_NAME_LENGTH ||
            self.name_prefix.len() > MAX_NAME_LENGTH
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct BluetoothScanfilterSequence(Vec<BluetoothScanfilter>);

impl BluetoothScanfilterSequence {
    pub fn new(vec: Vec<BluetoothScanfilter>) -> BluetoothScanfilterSequence {
        BluetoothScanfilterSequence(vec)
    }

    pub fn has_empty_or_invalid_filter(&self) -> bool {
        self.0.iter().any(BluetoothScanfilter::is_empty_or_invalid)
    }

    pub fn iter(&self) -> Iter<BluetoothScanfilter> {
        self.0.iter()
    }

    fn get_services_set(&self) -> HashSet<String> {
        self.iter()
            .flat_map(|filter| filter.services.get_services_set())
            .collect()
    }

    fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RequestDeviceoptions {
    filters: BluetoothScanfilterSequence,
    optional_services: ServiceUUIDSequence,
}

impl RequestDeviceoptions {
    pub fn new(
        filters: BluetoothScanfilterSequence,
        services: ServiceUUIDSequence,
    ) -> RequestDeviceoptions {
        RequestDeviceoptions {
            filters,
            optional_services: services,
        }
    }

    pub fn get_filters(&self) -> &BluetoothScanfilterSequence {
        &self.filters
    }

    pub fn get_services_set(&self) -> HashSet<String> {
        &self.filters.get_services_set() | &self.optional_services.get_services_set()
    }

    pub fn is_accepting_all_devices(&self) -> bool {
        self.filters.is_empty()
    }
}