1use fidl_fuchsia_bluetooth as fidl_bt;
6use fidl_fuchsia_bluetooth_bredr::{
7 self as fidl_bredr, ProfileDescriptor, ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST,
8 ATTR_SERVICE_CLASS_ID_LIST,
9};
10use fidl_table_validation::ValidFidlTable;
11#[cfg(target_os = "fuchsia")]
12use fuchsia_inspect as inspect;
13#[cfg(target_os = "fuchsia")]
14use fuchsia_inspect_derive::{AttachError, Inspect, Unit};
15use std::cmp::min;
16use std::collections::HashSet;
17
18use crate::assigned_numbers::constants::SERVICE_CLASS_UUIDS;
19use crate::assigned_numbers::AssignedNumber;
20use crate::error::Error;
21use crate::types::Uuid;
22
23#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
25pub struct Psm(u16);
26
27impl Psm {
28 pub const RFCOMM: Self = Self(fidl_bredr::PSM_RFCOMM);
30 pub const HID_CONTROL: Self = Self(fidl_bredr::PSM_HID_CONTROL);
31 pub const HID_INTERRUPT: Self = Self(fidl_bredr::PSM_HID_INTERRUPT);
32 pub const AVDTP: Self = Self(fidl_bredr::PSM_AVDTP);
33 pub const AVCTP: Self = Self(fidl_bredr::PSM_AVCTP);
34 pub const AVCTP_BROWSE: Self = Self(fidl_bredr::PSM_AVCTP_BROWSE);
35 pub const DYNAMIC: Self = Self(fidl_bredr::PSM_DYNAMIC);
36
37 pub fn new(value: u16) -> Self {
38 Self(value)
39 }
40}
41
42impl From<Psm> for u16 {
43 fn from(src: Psm) -> u16 {
44 src.0
45 }
46}
47
48pub fn elem_to_profile_descriptor(elem: &fidl_bredr::DataElement) -> Option<ProfileDescriptor> {
51 if let fidl_bredr::DataElement::Sequence(seq) = elem {
52 if seq.len() != 2 {
53 return None;
54 }
55
56 if seq[0].is_none() {
57 return None;
58 }
59 let profile_id = match **seq[0].as_ref().expect("not none") {
60 fidl_bredr::DataElement::Uuid(uuid) => {
61 let uuid: Uuid = uuid.into();
62 match uuid.try_into() {
63 Err(_) => return None,
64 Ok(profile_id) => profile_id,
65 }
66 }
67 _ => return None,
68 };
69
70 if seq[1].is_none() {
71 return None;
72 }
73 let [major_version, minor_version] = match **seq[1].as_ref().expect("not none") {
74 fidl_bredr::DataElement::Uint16(val) => val.to_be_bytes(),
75 _ => return None,
76 };
77 return Some(ProfileDescriptor {
78 profile_id: Some(profile_id),
79 major_version: Some(major_version),
80 minor_version: Some(minor_version),
81 ..Default::default()
82 });
83 }
84 None
85}
86
87pub fn find_profile_descriptors(
92 attributes: &[fidl_bredr::Attribute],
93) -> Result<Vec<ProfileDescriptor>, Error> {
94 let attr = attributes
95 .iter()
96 .find(|a| a.id == Some(ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST))
97 .ok_or_else(|| Error::profile("missing profile descriptor"))?;
98
99 let Some(fidl_bredr::DataElement::Sequence(profiles)) = &attr.element else {
100 return Err(Error::profile("attribute element is invalidly formatted"));
101 };
102 let mut result = Vec::new();
103 for elem in profiles {
104 let elem = elem.as_ref().ok_or_else(|| Error::profile("null DataElement in sequence"))?;
105 result.push(
106 elem_to_profile_descriptor(&*elem)
107 .ok_or_else(|| Error::profile("couldn't convert to a ProfileDescriptor"))?,
108 );
109 }
110 if result.is_empty() {
111 Err(Error::profile("no profile descriptor found"))
112 } else {
113 Ok(result)
114 }
115}
116
117pub fn profile_descriptor_to_assigned(profile_desc: &ProfileDescriptor) -> Option<AssignedNumber> {
118 let Some(id) = profile_desc.profile_id else {
119 return None;
120 };
121 SERVICE_CLASS_UUIDS.iter().find(|scn| id.into_primitive() == scn.number).cloned()
122}
123
124pub fn psm_from_protocol(protocol: &Vec<ProtocolDescriptor>) -> Option<Psm> {
127 for descriptor in protocol {
128 if descriptor.protocol == fidl_bredr::ProtocolIdentifier::L2Cap {
129 if descriptor.params.len() != 1 {
130 return None;
131 }
132
133 if let DataElement::Uint16(psm) = descriptor.params[0] {
134 return Some(Psm::new(psm));
135 }
136 return None;
137 }
138 }
139 None
140}
141
142pub fn find_service_classes(
144 attributes: &[fidl_fuchsia_bluetooth_bredr::Attribute],
145) -> Vec<AssignedNumber> {
146 let attr = match attributes.iter().find(|a| a.id == Some(ATTR_SERVICE_CLASS_ID_LIST)) {
147 None => return vec![],
148 Some(attr) => attr,
149 };
150 if let Some(fidl_fuchsia_bluetooth_bredr::DataElement::Sequence(elems)) = &attr.element {
151 let uuids: Vec<Uuid> = elems
152 .iter()
153 .filter_map(|e| {
154 e.as_ref().and_then(|e| {
155 if let fidl_fuchsia_bluetooth_bredr::DataElement::Uuid(uuid) = **e {
156 Some(uuid.into())
157 } else {
158 None
159 }
160 })
161 })
162 .collect();
163 SERVICE_CLASS_UUIDS
164 .iter()
165 .filter(|scn| uuids.contains(&Uuid::new16(scn.number)))
166 .cloned()
167 .collect()
168 } else {
169 return vec![];
170 }
171}
172
173pub fn combine_security_requirements(
178 reqs: &SecurityRequirements,
179 other: &SecurityRequirements,
180) -> SecurityRequirements {
181 let authentication_required =
182 match (reqs.authentication_required, other.authentication_required) {
183 (Some(true), _) | (_, Some(true)) => Some(true),
184 (Some(x), None) | (None, Some(x)) => Some(x),
185 _ => None,
186 };
187 let secure_connections_required =
188 match (reqs.secure_connections_required, other.secure_connections_required) {
189 (Some(true), _) | (_, Some(true)) => Some(true),
190 (Some(x), None) | (None, Some(x)) => Some(x),
191 _ => None,
192 };
193 SecurityRequirements { authentication_required, secure_connections_required }
194}
195
196pub fn combine_channel_parameters(
202 params: &ChannelParameters,
203 other: &ChannelParameters,
204) -> ChannelParameters {
205 let channel_mode = match (params.channel_mode, other.channel_mode) {
206 (Some(fidl_bt::ChannelMode::Basic), _) | (_, Some(fidl_bt::ChannelMode::Basic)) => {
207 Some(fidl_bt::ChannelMode::Basic)
208 }
209 (Some(x), None) | (None, Some(x)) => Some(x),
210 _ => None,
211 };
212 let max_rx_sdu_size = match (params.max_rx_sdu_size, other.max_rx_sdu_size) {
213 (Some(rx1), Some(rx2)) => Some(min(rx1, rx2)),
214 (Some(x), None) | (None, Some(x)) => Some(x),
215 _ => None,
216 };
217 let security_requirements = match (¶ms.security_requirements, &other.security_requirements)
218 {
219 (Some(reqs1), Some(reqs2)) => Some(combine_security_requirements(reqs1, reqs2)),
220 (Some(reqs), _) | (_, Some(reqs)) => Some(reqs.clone()),
221 _ => None,
222 };
223 ChannelParameters { channel_mode, max_rx_sdu_size, security_requirements }
224}
225
226#[derive(Clone, Debug, PartialEq)]
231pub enum DataElement {
232 Int8(i8),
233 Int16(i16),
234 Int32(i32),
235 Int64(i64),
236 Uint8(u8),
237 Uint16(u16),
238 Uint32(u32),
239 Uint64(u64),
240 Str(Vec<u8>),
241 Url(String),
242 Uuid(fidl_bt::Uuid),
243 Bool(bool),
244 Sequence(Vec<Box<DataElement>>),
245 Alternatives(Vec<Box<DataElement>>),
246}
247
248impl TryFrom<&fidl_bredr::DataElement> for DataElement {
249 type Error = Error;
250
251 fn try_from(src: &fidl_bredr::DataElement) -> Result<DataElement, Error> {
252 use fidl_bredr::DataElement as fDataElement;
253 let element = match src {
254 fDataElement::Int8(x) => DataElement::Int8(*x),
255 fDataElement::Int16(x) => DataElement::Int16(*x),
256 fDataElement::Int32(x) => DataElement::Int32(*x),
257 fDataElement::Int64(x) => DataElement::Int64(*x),
258 fDataElement::Uint8(x) => DataElement::Uint8(*x),
259 fDataElement::Uint16(x) => DataElement::Uint16(*x),
260 fDataElement::Uint32(x) => DataElement::Uint32(*x),
261 fDataElement::Uint64(x) => DataElement::Uint64(*x),
262 fDataElement::Str(v) => DataElement::Str(v.clone()),
264 fDataElement::Url(s) => DataElement::Url(s.to_string()),
265 fDataElement::Uuid(uuid) => DataElement::Uuid(uuid.clone()),
266 fDataElement::B(b) => DataElement::Bool(*b),
267 fDataElement::Sequence(x) => {
268 let mapped = x
269 .into_iter()
270 .filter_map(|opt| {
271 opt.as_ref().map(|t| match DataElement::try_from(&**t) {
272 Ok(elem) => Ok(Box::new(elem)),
273 Err(err) => Err(err),
274 })
275 })
276 .collect::<Result<Vec<_>, Error>>()?;
277 DataElement::Sequence(mapped)
278 }
279 fDataElement::Alternatives(x) => {
280 let mapped = x
281 .into_iter()
282 .filter_map(|opt| {
283 opt.as_ref().map(|t| match DataElement::try_from(&**t) {
284 Ok(elem) => Ok(Box::new(elem)),
285 Err(err) => Err(err),
286 })
287 })
288 .collect::<Result<Vec<_>, Error>>()?;
289 DataElement::Alternatives(mapped)
290 }
291 _ => return Err(Error::conversion("Unknown DataElement type")),
292 };
293 Ok(element)
294 }
295}
296
297impl From<&DataElement> for fidl_bredr::DataElement {
298 fn from(src: &DataElement) -> fidl_bredr::DataElement {
299 use fidl_bredr::DataElement as fDataElement;
300 match src {
301 DataElement::Int8(x) => fDataElement::Int8(*x),
302 DataElement::Int16(x) => fDataElement::Int16(*x),
303 DataElement::Int32(x) => fDataElement::Int32(*x),
304 DataElement::Int64(x) => fDataElement::Int64(*x),
305 DataElement::Uint8(x) => fDataElement::Uint8(*x),
306 DataElement::Uint16(x) => fDataElement::Uint16(*x),
307 DataElement::Uint32(x) => fDataElement::Uint32(*x),
308 DataElement::Uint64(x) => fDataElement::Uint64(*x),
309 DataElement::Str(v) => fDataElement::Str(v.clone()),
310 DataElement::Url(s) => fDataElement::Url(s.to_string()),
311 DataElement::Uuid(uuid) => fDataElement::Uuid(uuid.clone()),
312 DataElement::Bool(b) => fDataElement::B(*b),
313 DataElement::Sequence(x) => {
314 let mapped = x
315 .into_iter()
316 .map(|t| Some(Box::new(fDataElement::from(&**t))))
317 .collect::<Vec<_>>();
318 fDataElement::Sequence(mapped)
319 }
320 DataElement::Alternatives(x) => {
321 let mapped = x
322 .into_iter()
323 .map(|t| Some(Box::new(fDataElement::from(&**t))))
324 .collect::<Vec<_>>();
325 fDataElement::Alternatives(mapped)
326 }
327 }
328 }
329}
330
331#[derive(Debug, PartialEq)]
332pub struct DataElementConversionError {
333 pub data_element: DataElement,
334}
335
336macro_rules! generate_data_element_conversion {
338 ($variant: ident, $type: ty) => {
339 impl TryFrom<DataElement> for $type {
340 type Error = DataElementConversionError;
341
342 fn try_from(data_element: DataElement) -> Result<$type, DataElementConversionError> {
343 match data_element {
344 DataElement::$variant(x) => Ok(x),
345 _ => Err(DataElementConversionError { data_element }),
346 }
347 }
348 }
349
350 impl From<$type> for DataElement {
351 fn from(x: $type) -> DataElement {
352 DataElement::$variant(x)
353 }
354 }
355 };
356}
357
358generate_data_element_conversion!(Int8, i8);
360generate_data_element_conversion!(Int16, i16);
361generate_data_element_conversion!(Int32, i32);
362generate_data_element_conversion!(Int64, i64);
363generate_data_element_conversion!(Uint8, u8);
364generate_data_element_conversion!(Uint16, u16);
365generate_data_element_conversion!(Uint32, u32);
366generate_data_element_conversion!(Uint64, u64);
367generate_data_element_conversion!(Str, Vec<u8>);
368generate_data_element_conversion!(Uuid, fidl_bt::Uuid);
369generate_data_element_conversion!(Url, String);
370generate_data_element_conversion!(Bool, bool);
371
372#[derive(Clone, Debug, PartialEq)]
377pub struct ProtocolDescriptor {
378 pub protocol: fidl_bredr::ProtocolIdentifier,
379 pub params: Vec<DataElement>,
380}
381
382impl TryFrom<&fidl_bredr::ProtocolDescriptor> for ProtocolDescriptor {
383 type Error = Error;
384
385 fn try_from(src: &fidl_bredr::ProtocolDescriptor) -> Result<ProtocolDescriptor, Self::Error> {
386 let Some(protocol) = src.protocol else {
387 return Err(Error::missing("Missing ProtocolDescriptor.protocol"));
388 };
389 let params = src.params.as_ref().map_or(Ok(vec![]), |elems| {
390 elems
391 .into_iter()
392 .map(|elem| DataElement::try_from(elem))
393 .collect::<Result<Vec<DataElement>, Error>>()
394 })?;
395 Ok(ProtocolDescriptor { protocol, params })
396 }
397}
398
399impl From<&ProtocolDescriptor> for fidl_bredr::ProtocolDescriptor {
400 fn from(src: &ProtocolDescriptor) -> fidl_bredr::ProtocolDescriptor {
401 let params = src.params.iter().map(|elem| fidl_bredr::DataElement::from(elem)).collect();
402 fidl_bredr::ProtocolDescriptor {
403 protocol: Some(src.protocol),
404 params: Some(params),
405 ..Default::default()
406 }
407 }
408}
409
410pub fn l2cap_connect_parameters(
411 psm: Psm,
412 mode: fidl_bt::ChannelMode,
413) -> fidl_bredr::ConnectParameters {
414 fidl_bredr::ConnectParameters::L2cap(fidl_bredr::L2capParameters {
415 psm: Some(psm.into()),
416 parameters: Some(fidl_bt::ChannelParameters {
417 channel_mode: Some(mode),
418 ..fidl_bt::ChannelParameters::default()
419 }),
420 ..fidl_bredr::L2capParameters::default()
421 })
422}
423
424#[derive(Clone, Debug, PartialEq)]
429pub struct Attribute {
430 pub id: u16,
431 pub element: DataElement,
432}
433
434impl TryFrom<&fidl_bredr::Attribute> for Attribute {
435 type Error = Error;
436
437 fn try_from(src: &fidl_bredr::Attribute) -> Result<Attribute, Self::Error> {
438 let Some(id) = src.id else {
439 return Err(Error::missing("Attribute.id"));
440 };
441 let Some(element) = src.element.as_ref() else {
442 return Err(Error::missing("Attribute.element"));
443 };
444 let element = DataElement::try_from(element)?;
445 Ok(Attribute { id, element })
446 }
447}
448
449impl From<&Attribute> for fidl_bredr::Attribute {
450 fn from(src: &Attribute) -> fidl_bredr::Attribute {
451 fidl_bredr::Attribute {
452 id: Some(src.id),
453 element: Some(fidl_bredr::DataElement::from(&src.element)),
454 ..Default::default()
455 }
456 }
457}
458
459#[derive(Clone, Debug, PartialEq)]
464pub struct Information {
465 pub language: String,
466 pub name: Option<String>,
467 pub description: Option<String>,
468 pub provider: Option<String>,
469}
470
471impl TryFrom<&fidl_bredr::Information> for Information {
472 type Error = Error;
473
474 fn try_from(src: &fidl_bredr::Information) -> Result<Information, Self::Error> {
475 let language = match src.language.as_ref().map(String::as_str) {
476 None | Some("") => return Err(Error::missing("bredr.Information.language")),
477 Some(l) => l.to_string(),
478 };
479
480 Ok(Information {
481 language,
482 name: src.name.clone(),
483 description: src.description.clone(),
484 provider: src.provider.clone(),
485 })
486 }
487}
488
489impl TryFrom<&Information> for fidl_bredr::Information {
490 type Error = Error;
491
492 fn try_from(src: &Information) -> Result<fidl_bredr::Information, Self::Error> {
493 if src.language.is_empty() {
494 return Err(Error::missing("Information.language"));
495 }
496
497 Ok(fidl_bredr::Information {
498 language: Some(src.language.clone()),
499 name: src.name.clone(),
500 description: src.description.clone(),
501 provider: src.provider.clone(),
502 ..Default::default()
503 })
504 }
505}
506
507#[derive(Clone, Debug, Default, PartialEq)]
512pub struct ServiceDefinition {
513 pub service_class_uuids: Vec<Uuid>,
514 pub protocol_descriptor_list: Vec<ProtocolDescriptor>,
515 pub additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>>,
516 pub profile_descriptors: Vec<fidl_bredr::ProfileDescriptor>,
517 pub information: Vec<Information>,
518 pub additional_attributes: Vec<Attribute>,
519}
520
521impl ServiceDefinition {
522 pub fn try_into_fidl(this: &Vec<Self>) -> Result<Vec<fidl_bredr::ServiceDefinition>, Error> {
523 this.iter().map(fidl_bredr::ServiceDefinition::try_from).collect::<Result<Vec<_>, _>>()
524 }
525
526 pub fn try_from_fidl(src: &Vec<fidl_bredr::ServiceDefinition>) -> Result<Vec<Self>, Error> {
527 src.iter().map(Self::try_from).collect::<Result<Vec<_>, _>>()
528 }
529
530 pub fn primary_psm(&self) -> Option<Psm> {
532 psm_from_protocol(&self.protocol_descriptor_list)
533 }
534
535 pub fn additional_psms(&self) -> HashSet<Psm> {
537 self.additional_protocol_descriptor_lists
538 .iter()
539 .filter_map(|protocol| psm_from_protocol(protocol))
540 .collect()
541 }
542
543 pub fn goep_l2cap_psm(&self) -> Option<Psm> {
545 const GOEP_L2CAP_PSM_ATTRIBUTE: u16 = 0x0200;
546 let Some(attribute) =
547 self.additional_attributes.iter().find(|attr| attr.id == GOEP_L2CAP_PSM_ATTRIBUTE)
548 else {
549 return None;
550 };
551
552 let DataElement::Uint16(psm) = attribute.element else {
553 return None;
554 };
555
556 Some(Psm::new(psm))
557 }
558
559 pub fn psm_set(&self) -> HashSet<Psm> {
564 let mut psms = self.additional_psms();
565 if let Some(psm) = self.primary_psm() {
566 let _ = psms.insert(psm);
567 }
568 if let Some(psm) = self.goep_l2cap_psm() {
569 let _ = psms.insert(psm);
570 }
571
572 psms
573 }
574}
575
576impl TryFrom<&fidl_bredr::ServiceDefinition> for ServiceDefinition {
577 type Error = Error;
578
579 fn try_from(src: &fidl_bredr::ServiceDefinition) -> Result<ServiceDefinition, Self::Error> {
580 let service_class_uuids = match &src.service_class_uuids {
581 Some(uuids) if !uuids.is_empty() => uuids.iter().map(Uuid::from).collect(),
582 _ => {
583 return Err(Error::conversion(
584 "bredr.ServiceDefinition.service_class_uuids is empty",
585 ))
586 }
587 };
588
589 let protocol_descriptor_list: Vec<ProtocolDescriptor> =
590 src.protocol_descriptor_list.as_ref().map_or(Ok(vec![]), |p| {
591 p.into_iter()
592 .map(|d| ProtocolDescriptor::try_from(d))
593 .collect::<Result<Vec<ProtocolDescriptor>, Error>>()
594 })?;
595 let additional_protocol_descriptor_lists: Vec<Vec<ProtocolDescriptor>> =
596 src.additional_protocol_descriptor_lists.as_ref().map_or(Ok(vec![]), |desc_lists| {
597 desc_lists
598 .into_iter()
599 .map(|desc_list| {
600 desc_list
601 .into_iter()
602 .map(|d| ProtocolDescriptor::try_from(d))
603 .collect::<Result<Vec<ProtocolDescriptor>, Error>>()
604 })
605 .collect::<Result<Vec<Vec<ProtocolDescriptor>>, Error>>()
606 })?;
607 let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
608 src.profile_descriptors.clone().unwrap_or(vec![]);
609 let information: Result<Vec<Information>, Error> =
610 src.information.as_ref().map_or(Ok(vec![]), |infos| {
611 infos.into_iter().map(|i| Information::try_from(i)).collect()
612 });
613 let additional_attributes: Vec<Attribute> =
614 src.additional_attributes.as_ref().map_or(Ok(vec![]), |attrs| {
615 attrs
616 .into_iter()
617 .map(|a| Attribute::try_from(a))
618 .collect::<Result<Vec<Attribute>, Error>>()
619 })?;
620
621 Ok(ServiceDefinition {
622 service_class_uuids,
623 protocol_descriptor_list,
624 additional_protocol_descriptor_lists,
625 profile_descriptors,
626 information: information?,
627 additional_attributes,
628 })
629 }
630}
631
632impl TryFrom<&ServiceDefinition> for fidl_bredr::ServiceDefinition {
633 type Error = Error;
634
635 fn try_from(src: &ServiceDefinition) -> Result<fidl_bredr::ServiceDefinition, Self::Error> {
636 if src.service_class_uuids.is_empty() {
637 return Err(Error::conversion("ServiceDefinitions.service_class_uuids is empty"));
638 }
639 let service_class_uuids = src.service_class_uuids.iter().map(fidl_bt::Uuid::from).collect();
640
641 let protocol_descriptor_list: Vec<fidl_bredr::ProtocolDescriptor> = src
642 .protocol_descriptor_list
643 .iter()
644 .map(|d| fidl_bredr::ProtocolDescriptor::from(d))
645 .collect();
646 let additional_protocol_descriptor_lists: Vec<Vec<fidl_bredr::ProtocolDescriptor>> = src
647 .additional_protocol_descriptor_lists
648 .iter()
649 .map(|desc_list| {
650 desc_list.into_iter().map(|d| fidl_bredr::ProtocolDescriptor::from(d)).collect()
651 })
652 .collect();
653 let profile_descriptors: Vec<fidl_bredr::ProfileDescriptor> =
654 src.profile_descriptors.clone();
655 let information: Result<Vec<fidl_bredr::Information>, Error> =
656 src.information.iter().map(|i| fidl_bredr::Information::try_from(i)).collect();
657 let additional_attributes: Vec<fidl_bredr::Attribute> =
658 src.additional_attributes.iter().map(|a| fidl_bredr::Attribute::from(a)).collect();
659
660 Ok(fidl_bredr::ServiceDefinition {
661 service_class_uuids: Some(service_class_uuids),
662 protocol_descriptor_list: Some(protocol_descriptor_list),
663 additional_protocol_descriptor_lists: Some(additional_protocol_descriptor_lists),
664 profile_descriptors: Some(profile_descriptors),
665 information: Some(information?),
666 additional_attributes: Some(additional_attributes),
667 ..Default::default()
668 })
669 }
670}
671
672#[derive(Clone, Debug, Default, PartialEq)]
677pub struct SecurityRequirements {
678 pub authentication_required: Option<bool>,
679 pub secure_connections_required: Option<bool>,
680}
681
682impl From<&fidl_bt::SecurityRequirements> for SecurityRequirements {
683 fn from(src: &fidl_bt::SecurityRequirements) -> SecurityRequirements {
684 SecurityRequirements {
685 authentication_required: src.authentication_required,
686 secure_connections_required: src.secure_connections_required,
687 }
688 }
689}
690
691impl From<&SecurityRequirements> for fidl_bt::SecurityRequirements {
692 fn from(src: &SecurityRequirements) -> fidl_bt::SecurityRequirements {
693 fidl_bt::SecurityRequirements {
694 authentication_required: src.authentication_required,
695 secure_connections_required: src.secure_connections_required,
696 ..Default::default()
697 }
698 }
699}
700
701const MIN_RX_SDU_SIZE: u16 = 48;
704
705#[derive(Clone, Debug, Default, PartialEq)]
711pub struct ChannelParameters {
712 pub channel_mode: Option<fidl_bt::ChannelMode>,
713 pub max_rx_sdu_size: Option<u16>,
714 pub security_requirements: Option<SecurityRequirements>,
715}
716
717impl TryFrom<&fidl_bt::ChannelParameters> for ChannelParameters {
718 type Error = Error;
719
720 fn try_from(src: &fidl_bt::ChannelParameters) -> Result<ChannelParameters, Self::Error> {
721 if let Some(size) = src.max_rx_packet_size {
722 if size < MIN_RX_SDU_SIZE {
723 return Err(Error::conversion(format!(
724 "bredr.ChannelParameters.max_rx_sdu_size is too small: {size}"
725 )));
726 }
727 }
728
729 Ok(ChannelParameters {
730 channel_mode: src.channel_mode,
731 max_rx_sdu_size: src.max_rx_packet_size,
732 security_requirements: src
733 .security_requirements
734 .as_ref()
735 .map(SecurityRequirements::from),
736 })
737 }
738}
739
740impl TryFrom<&ChannelParameters> for fidl_bt::ChannelParameters {
741 type Error = Error;
742
743 fn try_from(src: &ChannelParameters) -> Result<fidl_bt::ChannelParameters, Self::Error> {
744 if let Some(size) = src.max_rx_sdu_size {
745 if size < MIN_RX_SDU_SIZE {
746 return Err(Error::conversion(format!(
747 "ChannelParameters.max_rx_sdu_size is too small: {size}"
748 )));
749 }
750 }
751
752 Ok(fidl_bt::ChannelParameters {
753 channel_mode: src.channel_mode,
754 max_rx_packet_size: src.max_rx_sdu_size,
755 security_requirements: src
756 .security_requirements
757 .as_ref()
758 .map(fidl_bt::SecurityRequirements::from),
759 ..Default::default()
760 })
761 }
762}
763
764#[derive(Debug, Clone, ValidFidlTable, PartialEq)]
765#[fidl_table_src(fidl_bredr::ScoConnectionParameters)]
766pub struct ValidScoConnectionParameters {
767 pub parameter_set: fidl_bredr::HfpParameterSet,
768 pub air_coding_format: fidl_bt::AssignedCodingFormat,
769 pub air_frame_size: u16,
770 pub io_bandwidth: u32,
771 pub io_coding_format: fidl_bt::AssignedCodingFormat,
772 pub io_frame_size: u16,
773 #[fidl_field_type(optional)]
774 pub io_pcm_data_format: Option<fidl_fuchsia_hardware_audio::SampleFormat>,
775 #[fidl_field_type(optional)]
776 pub io_pcm_sample_payload_msb_position: Option<u8>,
777 pub path: fidl_bredr::DataPath,
778}
779
780#[cfg(target_os = "fuchsia")]
781impl Unit for ValidScoConnectionParameters {
782 type Data = inspect::Node;
783 fn inspect_create(&self, parent: &inspect::Node, name: impl AsRef<str>) -> Self::Data {
784 let mut node = parent.create_child(name.as_ref());
785 self.inspect_update(&mut node);
786 node
787 }
788
789 fn inspect_update(&self, data: &mut Self::Data) {
790 data.record_string("parameter_set", &format!("{:?}", self.parameter_set));
791 data.record_string("air_coding_format", &format!("{:?}", self.air_coding_format));
792 data.record_uint("air_frame_size", self.air_frame_size.into());
793 data.record_uint("io_bandwidth", self.io_bandwidth.into());
794 data.record_string("io_coding_format", &format!("{:?}", self.io_coding_format));
795 data.record_uint("io_frame_size", self.io_frame_size.into());
796 if let Some(io_pcm_data_format) = &self.io_pcm_data_format {
797 data.record_string("io_pcm_data_format", &format!("{:?}", io_pcm_data_format));
798 }
799 if let Some(io_pcm_sample_payload_msb_position) = &self.io_pcm_sample_payload_msb_position {
800 data.record_uint(
801 "io_pcm_sample_payload_msb_position",
802 (*io_pcm_sample_payload_msb_position).into(),
803 );
804 }
805 data.record_string("path", &format!("{:?}", self.path));
806 }
807}
808
809#[cfg(target_os = "fuchsia")]
810impl Inspect for &mut ValidScoConnectionParameters {
811 fn iattach(self, parent: &inspect::Node, name: impl AsRef<str>) -> Result<(), AttachError> {
812 parent.record(self.inspect_create(parent, name));
814 Ok(())
815 }
816}
817
818#[cfg(test)]
819mod tests {
820 use super::*;
821 use diagnostics_assertions::assert_data_tree;
822
823 #[test]
824 fn test_find_descriptors_fails_with_no_descriptors() {
825 assert!(find_profile_descriptors(&[]).is_err());
826
827 let mut attributes = vec![fidl_bredr::Attribute {
828 id: Some(0x3001),
829 element: Some(fidl_bredr::DataElement::Uint32(0xF00FC0DE)),
830 ..Default::default()
831 }];
832
833 assert!(find_profile_descriptors(&attributes).is_err());
834
835 attributes.push(fidl_bredr::Attribute {
837 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
838 element: Some(fidl_bredr::DataElement::Uint32(0xABADC0DE)),
839 ..Default::default()
840 });
841
842 assert!(find_profile_descriptors(&attributes).is_err());
843
844 attributes[1].element = Some(fidl_bredr::DataElement::Sequence(vec![]));
846
847 assert!(find_profile_descriptors(&attributes).is_err());
848 }
849
850 #[test]
851 fn test_find_descriptors_returns_descriptors() {
852 let attributes = vec![fidl_bredr::Attribute {
853 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
854 element: Some(fidl_bredr::DataElement::Sequence(vec![
855 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
856 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
857 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
858 ]))),
859 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
860 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
861 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
862 ]))),
863 ])),
864 ..Default::default()
865 }];
866
867 let result = find_profile_descriptors(&attributes);
868 assert!(result.is_ok());
869 let result = result.expect("result");
870 assert_eq!(2, result.len());
871
872 assert_eq!(
873 fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
874 result[0].profile_id.unwrap()
875 );
876 assert_eq!(1, result[0].major_version.unwrap());
877 assert_eq!(3, result[0].minor_version.unwrap());
878 }
879
880 #[test]
881 fn test_find_service_classes_attribute_missing() {
882 assert_eq!(find_service_classes(&[]), Vec::new());
883 let attributes = vec![fidl_bredr::Attribute {
884 id: Some(fidl_bredr::ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST),
885 element: Some(fidl_bredr::DataElement::Sequence(vec![
886 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
887 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
888 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
889 ]))),
890 Some(Box::new(fidl_bredr::DataElement::Sequence(vec![
891 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x113A).into()))),
892 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0302))),
893 ]))),
894 ])),
895 ..Default::default()
896 }];
897 assert_eq!(find_service_classes(&attributes), Vec::new());
898 }
899
900 #[test]
901 fn test_find_service_classes_wrong_type() {
902 let attributes = vec![fidl_bredr::Attribute {
903 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
904 element: Some(fidl_bredr::DataElement::Uint32(0xc0defae5u32)),
905 ..Default::default()
906 }];
907 assert_eq!(find_service_classes(&attributes), Vec::new());
908 }
909
910 #[test]
911 fn test_find_service_classes_returns_known_classes() {
912 let attribute = fidl_bredr::Attribute {
913 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
914 element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
915 fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()),
916 ))])),
917 ..Default::default()
918 };
919
920 let result = find_service_classes(&[attribute]);
921 assert_eq!(1, result.len());
922 let assigned_num = result.first().unwrap();
923 assert_eq!(0x1101, assigned_num.number); assert_eq!("SerialPort", assigned_num.name);
925
926 let unknown_uuids = fidl_bredr::Attribute {
927 id: Some(fidl_bredr::ATTR_SERVICE_CLASS_ID_LIST),
928 element: Some(fidl_bredr::DataElement::Sequence(vec![
929 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
930 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0xc0de).into()))),
931 ])),
932 ..Default::default()
933 };
934
935 let result = find_service_classes(&[unknown_uuids]);
937 assert_eq!(1, result.len());
938 let assigned_num = result.first().unwrap();
939 assert_eq!(0x1101, assigned_num.number); assert_eq!("SerialPort", assigned_num.name);
941 }
942
943 #[test]
944 fn test_psm_from_protocol() {
945 let empty = vec![];
946 assert_eq!(None, psm_from_protocol(&empty));
947
948 let no_psm = vec![ProtocolDescriptor {
949 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
950 params: vec![],
951 }];
952 assert_eq!(None, psm_from_protocol(&no_psm));
953
954 let psm = Psm::new(10);
955 let valid_psm = vec![ProtocolDescriptor {
956 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
957 params: vec![DataElement::Uint16(psm.into())],
958 }];
959 assert_eq!(Some(psm), psm_from_protocol(&valid_psm));
960
961 let rfcomm = vec![
962 ProtocolDescriptor {
963 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
964 params: vec![], },
966 ProtocolDescriptor {
967 protocol: fidl_bredr::ProtocolIdentifier::Rfcomm,
968 params: vec![DataElement::Uint8(10)], },
970 ];
971 assert_eq!(None, psm_from_protocol(&rfcomm));
972 }
973
974 #[test]
975 fn test_elem_to_profile_descriptor_works() {
976 let element = fidl_bredr::DataElement::Sequence(vec![
977 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
978 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
979 ]);
980
981 let descriptor =
982 elem_to_profile_descriptor(&element).expect("descriptor should be returned");
983
984 assert_eq!(
985 fidl_bredr::ServiceClassProfileIdentifier::SerialPort,
986 descriptor.profile_id.unwrap()
987 );
988 assert_eq!(1, descriptor.major_version.unwrap());
989 assert_eq!(3, descriptor.minor_version.unwrap());
990 }
991
992 #[test]
993 fn test_elem_to_profile_descriptor_wrong_element_types() {
994 let element = fidl_bredr::DataElement::Sequence(vec![
995 Some(Box::new(fidl_bredr::DataElement::Uint16(0x1101))),
996 Some(Box::new(fidl_bredr::DataElement::Uint16(0x0103))),
997 ]);
998 assert!(elem_to_profile_descriptor(&element).is_none());
999
1000 let element = fidl_bredr::DataElement::Sequence(vec![
1001 Some(Box::new(fidl_bredr::DataElement::Uuid(Uuid::new16(0x1101).into()))),
1002 Some(Box::new(fidl_bredr::DataElement::Uint32(0x0103))),
1003 ]);
1004 assert!(elem_to_profile_descriptor(&element).is_none());
1005
1006 let element = fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1007 fidl_bredr::DataElement::Uint32(0x0103),
1008 ))]);
1009 assert!(elem_to_profile_descriptor(&element).is_none());
1010
1011 let element = fidl_bredr::DataElement::Sequence(vec![None]);
1012 assert!(elem_to_profile_descriptor(&element).is_none());
1013
1014 let element = fidl_bredr::DataElement::Uint32(0xDEADC0DE);
1015 assert!(elem_to_profile_descriptor(&element).is_none());
1016 }
1017
1018 #[test]
1019 fn test_invalid_information_fails_gracefully() {
1020 let empty_language = "".to_string();
1021
1022 let invalid_local = Information {
1023 language: empty_language.clone(),
1024 name: None,
1025 description: None,
1026 provider: None,
1027 };
1028 let fidl = fidl_bredr::Information::try_from(&invalid_local);
1029 assert!(fidl.is_err());
1030
1031 let local = Information::try_from(&fidl_bredr::Information::default());
1033 assert!(local.is_err());
1034
1035 let empty_lang_fidl =
1036 fidl_bredr::Information { language: Some(empty_language), ..Default::default() };
1037 let local = Information::try_from(&empty_lang_fidl);
1038 assert!(local.is_err());
1039 }
1040
1041 #[test]
1042 fn get_psm_from_empty_service_definition() {
1043 let def = ServiceDefinition {
1044 service_class_uuids: vec![Uuid::new32(1234)],
1045 protocol_descriptor_list: vec![],
1046 additional_protocol_descriptor_lists: vec![],
1047 profile_descriptors: vec![],
1048 information: vec![],
1049 additional_attributes: vec![],
1050 };
1051
1052 assert_eq!(def.primary_psm(), None);
1053 assert_eq!(def.additional_psms(), HashSet::new());
1054 assert_eq!(def.psm_set(), HashSet::new());
1055 }
1056
1057 #[test]
1058 fn test_get_psm_from_service_definition() {
1059 let uuid = Uuid::new32(1234);
1060 let psm1 = Psm(10);
1061 let psm2 = Psm(12);
1062 let psm3 = Psm(4000);
1063 let mut def = ServiceDefinition {
1064 service_class_uuids: vec![uuid],
1065 protocol_descriptor_list: vec![ProtocolDescriptor {
1066 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1067 params: vec![DataElement::Uint16(psm1.into())],
1068 }],
1069 additional_protocol_descriptor_lists: vec![],
1070 profile_descriptors: vec![],
1071 information: vec![],
1072 additional_attributes: vec![],
1073 };
1074
1075 assert_eq!(def.primary_psm(), Some(psm1));
1077 assert_eq!(def.additional_psms(), HashSet::new());
1078 assert_eq!(def.psm_set(), HashSet::from([psm1]));
1079
1080 def.additional_protocol_descriptor_lists = vec![
1081 vec![ProtocolDescriptor {
1082 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1083 params: vec![DataElement::Uint16(psm2.into())],
1084 }],
1085 vec![ProtocolDescriptor {
1086 protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1087 params: vec![DataElement::Uint16(0x0103)],
1088 }],
1089 ];
1090
1091 assert_eq!(def.primary_psm(), Some(psm1));
1093 assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1094 assert_eq!(def.psm_set(), HashSet::from([psm1, psm2]));
1095
1096 def.additional_attributes =
1098 vec![Attribute { id: 0x0200, element: DataElement::Uint16(psm3.into()) }];
1099 assert_eq!(def.primary_psm(), Some(psm1));
1100 assert_eq!(def.additional_psms(), HashSet::from([psm2]));
1101 assert_eq!(def.goep_l2cap_psm(), Some(psm3));
1102 assert_eq!(def.psm_set(), HashSet::from([psm1, psm2, psm3]));
1103 }
1104
1105 #[test]
1106 fn test_service_definition_conversions() {
1107 let uuid = fidl_bt::Uuid { value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] };
1108 let prof_descs = vec![ProfileDescriptor {
1109 profile_id: Some(fidl_bredr::ServiceClassProfileIdentifier::AvRemoteControl),
1110 major_version: Some(1),
1111 minor_version: Some(6),
1112 ..Default::default()
1113 }];
1114 let language = "en".to_string();
1115 let name = "foobar".to_string();
1116 let description = "fake".to_string();
1117 let provider = "random".to_string();
1118 let attribute_id = 0x3001;
1119 let attribute_value = 0xF00FC0DE;
1120
1121 let local = ServiceDefinition {
1122 service_class_uuids: vec![uuid.into()],
1123 protocol_descriptor_list: vec![ProtocolDescriptor {
1124 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1125 params: vec![DataElement::Uint16(10)],
1126 }],
1127 additional_protocol_descriptor_lists: vec![
1128 vec![ProtocolDescriptor {
1129 protocol: fidl_bredr::ProtocolIdentifier::L2Cap,
1130 params: vec![DataElement::Uint16(12)],
1131 }],
1132 vec![ProtocolDescriptor {
1133 protocol: fidl_bredr::ProtocolIdentifier::Avdtp,
1134 params: vec![DataElement::Uint16(3)],
1135 }],
1136 ],
1137 profile_descriptors: prof_descs.clone(),
1138 information: vec![Information {
1139 language: language.clone(),
1140 name: Some(name.clone()),
1141 description: Some(description.clone()),
1142 provider: Some(provider.clone()),
1143 }],
1144 additional_attributes: vec![Attribute {
1145 id: attribute_id,
1146 element: DataElement::Sequence(vec![Box::new(DataElement::Uint32(
1147 attribute_value,
1148 ))]),
1149 }],
1150 };
1151
1152 let fidl = fidl_bredr::ServiceDefinition {
1153 service_class_uuids: Some(vec![uuid]),
1154 protocol_descriptor_list: Some(vec![fidl_bredr::ProtocolDescriptor {
1155 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1156 params: Some(vec![fidl_bredr::DataElement::Uint16(10)]),
1157 ..Default::default()
1158 }]),
1159 additional_protocol_descriptor_lists: Some(vec![
1160 vec![fidl_bredr::ProtocolDescriptor {
1161 protocol: Some(fidl_bredr::ProtocolIdentifier::L2Cap),
1162 params: Some(vec![fidl_bredr::DataElement::Uint16(12)]),
1163 ..Default::default()
1164 }],
1165 vec![fidl_bredr::ProtocolDescriptor {
1166 protocol: Some(fidl_bredr::ProtocolIdentifier::Avdtp),
1167 params: Some(vec![fidl_bredr::DataElement::Uint16(3)]),
1168 ..Default::default()
1169 }],
1170 ]),
1171 profile_descriptors: Some(prof_descs.clone()),
1172 information: Some(vec![fidl_bredr::Information {
1173 language: Some(language.clone()),
1174 name: Some(name.clone()),
1175 description: Some(description.clone()),
1176 provider: Some(provider.clone()),
1177 ..Default::default()
1178 }]),
1179 additional_attributes: Some(vec![fidl_bredr::Attribute {
1180 id: Some(attribute_id),
1181 element: Some(fidl_bredr::DataElement::Sequence(vec![Some(Box::new(
1182 fidl_bredr::DataElement::Uint32(attribute_value),
1183 ))])),
1184 ..Default::default()
1185 }]),
1186 ..Default::default()
1187 };
1188
1189 let local_to_fidl: fidl_bredr::ServiceDefinition =
1191 fidl_bredr::ServiceDefinition::try_from(&local).expect("should work");
1192 assert_eq!(local_to_fidl, fidl);
1193
1194 let fidl_to_local: ServiceDefinition =
1196 ServiceDefinition::try_from(&fidl).expect("should work");
1197 assert_eq!(fidl_to_local, local);
1198 }
1199
1200 #[test]
1201 fn test_invalid_service_definition_fails_gracefully() {
1202 let no_uuids_fidl = fidl_bredr::ServiceDefinition::default();
1203 let fidl_to_local = ServiceDefinition::try_from(&no_uuids_fidl);
1204 assert!(fidl_to_local.is_err());
1205
1206 let empty_uuids_fidl = fidl_bredr::ServiceDefinition {
1207 service_class_uuids: Some(vec![]),
1208 ..Default::default()
1209 };
1210 let fidl_to_local = ServiceDefinition::try_from(&empty_uuids_fidl);
1211 assert!(fidl_to_local.is_err());
1212 }
1213
1214 #[test]
1215 fn test_channel_parameters_conversions() {
1216 let channel_mode = Some(fidl_bt::ChannelMode::EnhancedRetransmission);
1217 let max_rx_sdu_size = Some(MIN_RX_SDU_SIZE);
1218
1219 let local =
1220 ChannelParameters { channel_mode, max_rx_sdu_size, security_requirements: None };
1221 let fidl = fidl_bt::ChannelParameters {
1222 channel_mode,
1223 max_rx_packet_size: max_rx_sdu_size,
1224 ..Default::default()
1225 };
1226
1227 let local_to_fidl =
1228 fidl_bt::ChannelParameters::try_from(&local).expect("conversion should work");
1229 assert_eq!(local_to_fidl, fidl);
1230
1231 let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1232 assert_eq!(fidl_to_local, local);
1233
1234 let fidl = fidl_bt::ChannelParameters::default();
1236 let expected = ChannelParameters {
1237 channel_mode: None,
1238 max_rx_sdu_size: None,
1239 security_requirements: None,
1240 };
1241
1242 let fidl_to_local = ChannelParameters::try_from(&fidl).expect("conversion should work");
1243 assert_eq!(fidl_to_local, expected);
1244 }
1245
1246 #[test]
1247 fn test_invalid_channel_parameters_fails_gracefully() {
1248 let too_small_sdu = Some(MIN_RX_SDU_SIZE - 1);
1249 let local = ChannelParameters {
1250 channel_mode: None,
1251 max_rx_sdu_size: too_small_sdu,
1252 security_requirements: None,
1253 };
1254 let fidl =
1255 fidl_bt::ChannelParameters { max_rx_packet_size: too_small_sdu, ..Default::default() };
1256
1257 let local_to_fidl = fidl_bt::ChannelParameters::try_from(&local);
1258 assert!(local_to_fidl.is_err());
1259
1260 let fidl_to_local = ChannelParameters::try_from(&fidl);
1261 assert!(fidl_to_local.is_err());
1262 }
1263
1264 #[test]
1265 fn test_security_requirements_conversions() {
1266 let authentication_required = Some(false);
1267 let secure_connections_required = Some(true);
1268
1269 let local = SecurityRequirements { authentication_required, secure_connections_required };
1270 let fidl = fidl_bt::SecurityRequirements {
1271 authentication_required,
1272 secure_connections_required,
1273 ..Default::default()
1274 };
1275
1276 let local_to_fidl = fidl_bt::SecurityRequirements::from(&local);
1277 assert_eq!(local_to_fidl, fidl);
1278
1279 let fidl_to_local = SecurityRequirements::from(&fidl);
1280 assert_eq!(fidl_to_local, local);
1281 }
1282
1283 #[test]
1284 fn test_combine_security_requirements() {
1285 let req1 = SecurityRequirements {
1286 authentication_required: None,
1287 secure_connections_required: None,
1288 };
1289 let req2 = SecurityRequirements {
1290 authentication_required: None,
1291 secure_connections_required: None,
1292 };
1293 let expected = SecurityRequirements {
1294 authentication_required: None,
1295 secure_connections_required: None,
1296 };
1297 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1298
1299 let req1 = SecurityRequirements {
1300 authentication_required: Some(true),
1301 secure_connections_required: None,
1302 };
1303 let req2 = SecurityRequirements {
1304 authentication_required: None,
1305 secure_connections_required: Some(true),
1306 };
1307 let expected = SecurityRequirements {
1308 authentication_required: Some(true),
1309 secure_connections_required: Some(true),
1310 };
1311 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1312
1313 let req1 = SecurityRequirements {
1314 authentication_required: Some(false),
1315 secure_connections_required: Some(true),
1316 };
1317 let req2 = SecurityRequirements {
1318 authentication_required: None,
1319 secure_connections_required: Some(true),
1320 };
1321 let expected = SecurityRequirements {
1322 authentication_required: Some(false),
1323 secure_connections_required: Some(true),
1324 };
1325 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1326
1327 let req1 = SecurityRequirements {
1328 authentication_required: Some(true),
1329 secure_connections_required: Some(false),
1330 };
1331 let req2 = SecurityRequirements {
1332 authentication_required: Some(false),
1333 secure_connections_required: Some(true),
1334 };
1335 let expected = SecurityRequirements {
1336 authentication_required: Some(true),
1337 secure_connections_required: Some(true),
1338 };
1339 assert_eq!(combine_security_requirements(&req1, &req2), expected);
1340 }
1341
1342 #[test]
1343 fn test_combine_channel_parameters() {
1344 let p1 = ChannelParameters::default();
1345 let p2 = ChannelParameters::default();
1346 let expected = ChannelParameters::default();
1347 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1348
1349 let p1 = ChannelParameters {
1350 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1351 max_rx_sdu_size: None,
1352 security_requirements: None,
1353 };
1354 let p2 = ChannelParameters {
1355 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1356 max_rx_sdu_size: Some(70),
1357 security_requirements: None,
1358 };
1359 let expected = ChannelParameters {
1360 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1361 max_rx_sdu_size: Some(70),
1362 security_requirements: None,
1363 };
1364 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1365
1366 let empty_seq_reqs = SecurityRequirements::default();
1367 let p1 = ChannelParameters {
1368 channel_mode: None,
1369 max_rx_sdu_size: Some(75),
1370 security_requirements: Some(empty_seq_reqs.clone()),
1371 };
1372 let p2 = ChannelParameters {
1373 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1374 max_rx_sdu_size: None,
1375 security_requirements: None,
1376 };
1377 let expected = ChannelParameters {
1378 channel_mode: Some(fidl_bt::ChannelMode::EnhancedRetransmission),
1379 max_rx_sdu_size: Some(75),
1380 security_requirements: Some(empty_seq_reqs),
1381 };
1382 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1383
1384 let reqs1 = SecurityRequirements {
1385 authentication_required: Some(true),
1386 secure_connections_required: None,
1387 };
1388 let reqs2 = SecurityRequirements {
1389 authentication_required: Some(false),
1390 secure_connections_required: Some(false),
1391 };
1392 let combined_reqs = combine_security_requirements(&reqs1, &reqs2);
1393 let p1 = ChannelParameters {
1394 channel_mode: None,
1395 max_rx_sdu_size: Some(90),
1396 security_requirements: Some(reqs1),
1397 };
1398 let p2 = ChannelParameters {
1399 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1400 max_rx_sdu_size: Some(70),
1401 security_requirements: Some(reqs2),
1402 };
1403 let expected = ChannelParameters {
1404 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1405 max_rx_sdu_size: Some(70),
1406 security_requirements: Some(combined_reqs),
1407 };
1408 assert_eq!(combine_channel_parameters(&p1, &p2), expected);
1409 }
1410
1411 #[test]
1412 fn local_sco_parameters_inspect_tree() {
1413 let inspect = inspect::Inspector::default();
1414 assert_data_tree!(inspect, root: {});
1415
1416 let params = fidl_bredr::ScoConnectionParameters {
1417 parameter_set: Some(fidl_bredr::HfpParameterSet::D1),
1418 air_coding_format: Some(fidl_bt::AssignedCodingFormat::Cvsd),
1419 air_frame_size: Some(60),
1420 io_bandwidth: Some(16000),
1421 io_coding_format: Some(fidl_bt::AssignedCodingFormat::LinearPcm),
1422 io_frame_size: Some(16),
1423 io_pcm_data_format: Some(fidl_fuchsia_hardware_audio::SampleFormat::PcmSigned),
1424 io_pcm_sample_payload_msb_position: Some(1),
1425 path: Some(fidl_bredr::DataPath::Offload),
1426 ..Default::default()
1427 };
1428
1429 let mut local: ValidScoConnectionParameters = params.try_into().expect("can convert");
1430 assert_data_tree!(inspect, root: {});
1431
1432 let _ = local.iattach(&inspect.root(), "state").expect("can attach inspect");
1433 assert_data_tree!(inspect, root: {
1434 state: {
1435 parameter_set: "D1",
1436 air_coding_format: "Cvsd",
1437 air_frame_size: 60u64,
1438 io_bandwidth: 16000u64,
1439 io_coding_format: "LinearPcm",
1440 io_frame_size: 16u64,
1441 io_pcm_data_format: "PcmSigned",
1442 io_pcm_sample_payload_msb_position: 1u64,
1443 path: "Offload",
1444 }
1445 });
1446 }
1447
1448 #[test]
1449 fn data_element_primitve_conversions() {
1450 type Result<T> = std::result::Result<T, DataElementConversionError>;
1451
1452 let rust_u8 = 8u8;
1453 let data_element_uint8 = DataElement::Uint8(8u8);
1454 let data_element_uint8_into: DataElement = rust_u8.into();
1455 let rust_u8_ok: Result<u8> = data_element_uint8.clone().try_into();
1456 let rust_u8_err: Result<u16> = data_element_uint8.clone().try_into();
1457 assert_eq!(data_element_uint8_into, data_element_uint8);
1458 assert_eq!(rust_u8_ok, Ok(rust_u8));
1459 assert_eq!(
1460 rust_u8_err,
1461 Err(DataElementConversionError { data_element: data_element_uint8 })
1462 );
1463
1464 let rust_i8 = 9i8;
1465 let data_element_int8 = DataElement::Int8(9i8);
1466 let data_element_int8_into: DataElement = rust_i8.into();
1467 let rust_i8_ok: Result<i8> = data_element_int8.clone().try_into();
1468 let rust_i8_err: Result<u16> = data_element_int8.clone().try_into();
1469 assert_eq!(data_element_int8_into, data_element_int8);
1470 assert_eq!(rust_i8_ok, Ok(rust_i8));
1471 assert_eq!(
1472 rust_i8_err,
1473 Err(DataElementConversionError { data_element: data_element_int8 })
1474 );
1475
1476 let rust_u16 = 16u16;
1477 let data_element_uint16 = DataElement::Uint16(16u16);
1478 let data_element_uint16_into: DataElement = rust_u16.into();
1479 let rust_u16_ok: Result<u16> = data_element_uint16.clone().try_into();
1480 let rust_u16_err: Result<i16> = data_element_uint16.clone().try_into();
1481 assert_eq!(data_element_uint16_into, data_element_uint16);
1482 assert_eq!(rust_u16_ok, Ok(rust_u16));
1483 assert_eq!(
1484 rust_u16_err,
1485 Err(DataElementConversionError { data_element: data_element_uint16 })
1486 );
1487
1488 let rust_i16 = 17i16;
1489 let data_element_int16 = DataElement::Int16(17i16);
1490 let data_element_int16_into: DataElement = rust_i16.into();
1491 let rust_i16_ok: Result<i16> = data_element_int16.clone().try_into();
1492 let rust_i16_err: Result<u16> = data_element_int16.clone().try_into();
1493 assert_eq!(data_element_int16_into, data_element_int16);
1494 assert_eq!(rust_i16_ok, Ok(rust_i16));
1495 assert_eq!(
1496 rust_i16_err,
1497 Err(DataElementConversionError { data_element: data_element_int16 })
1498 );
1499
1500 let rust_u32 = 32u32;
1501 let data_element_uint32 = DataElement::Uint32(32u32);
1502 let data_element_uint32_into: DataElement = rust_u32.into();
1503 let rust_u32_ok: Result<u32> = data_element_uint32.clone().try_into();
1504 let rust_u32_err: Result<u16> = data_element_uint32.clone().try_into();
1505 assert_eq!(data_element_uint32_into, data_element_uint32);
1506 assert_eq!(rust_u32_ok, Ok(rust_u32));
1507 assert_eq!(
1508 rust_u32_err,
1509 Err(DataElementConversionError { data_element: data_element_uint32 })
1510 );
1511
1512 let rust_i32 = 33i32;
1513 let data_element_int32 = DataElement::Int32(33i32);
1514 let data_element_int32_into: DataElement = rust_i32.into();
1515 let rust_i32_ok: Result<i32> = data_element_int32.clone().try_into();
1516 let rust_i32_err: Result<u16> = data_element_int32.clone().try_into();
1517 assert_eq!(data_element_int32_into, data_element_int32);
1518 assert_eq!(rust_i32_ok, Ok(rust_i32));
1519 assert_eq!(
1520 rust_i32_err,
1521 Err(DataElementConversionError { data_element: data_element_int32 })
1522 );
1523
1524 let rust_u64 = 64u64;
1525 let data_element_uint64 = DataElement::Uint64(64u64);
1526 let data_element_uint64_into: DataElement = rust_u64.into();
1527 let rust_u64_ok: Result<u64> = data_element_uint64.clone().try_into();
1528 let rust_u64_err: Result<u16> = data_element_uint64.clone().try_into();
1529 assert_eq!(data_element_uint64_into, data_element_uint64);
1530 assert_eq!(rust_u64_ok, Ok(rust_u64));
1531 assert_eq!(
1532 rust_u64_err,
1533 Err(DataElementConversionError { data_element: data_element_uint64 })
1534 );
1535
1536 let rust_i64 = 65i64;
1537 let data_element_int64 = DataElement::Int64(65i64);
1538 let data_element_int64_into: DataElement = rust_i64.into();
1539 let rust_i64_ok: Result<i64> = data_element_int64.clone().try_into();
1540 let rust_i64_err: Result<u16> = data_element_int64.clone().try_into();
1541 assert_eq!(data_element_int64_into, data_element_int64);
1542 assert_eq!(rust_i64_ok, Ok(rust_i64));
1543 assert_eq!(
1544 rust_i64_err,
1545 Err(DataElementConversionError { data_element: data_element_int64 })
1546 );
1547
1548 let rust_vec = "ABC".as_bytes().to_vec();
1549 let data_element_str = DataElement::Str("ABC".as_bytes().to_vec());
1550 let data_element_str_into: DataElement = rust_vec.clone().into();
1551 let rust_vec_ok: Result<Vec<u8>> = data_element_str.clone().try_into();
1552 let rust_vec_err: Result<u16> = data_element_str.clone().try_into();
1553 assert_eq!(data_element_str_into, data_element_str);
1554 assert_eq!(rust_vec_ok, Ok(rust_vec));
1555 assert_eq!(
1556 rust_vec_err,
1557 Err(DataElementConversionError { data_element: data_element_str })
1558 );
1559
1560 let rust_uuid: fidl_bt::Uuid = Uuid::new16(0x1101).into();
1561 let data_element_uuid = DataElement::Uuid(Uuid::new16(0x1101).into());
1562 let data_element_uuid_into: DataElement = rust_uuid.clone().into();
1563 let rust_uuid_ok: Result<fidl_bt::Uuid> = data_element_uuid.clone().try_into();
1564 let rust_uuid_err: Result<u16> = data_element_uuid.clone().try_into();
1565 assert_eq!(data_element_uuid_into, data_element_uuid);
1566 assert_eq!(rust_uuid_ok, Ok(rust_uuid));
1567 assert_eq!(
1568 rust_uuid_err,
1569 Err(DataElementConversionError { data_element: data_element_uuid })
1570 );
1571
1572 let rust_string = String::from("ABC");
1573 let data_element_url = DataElement::Url(String::from("ABC"));
1574 let data_element_url_into: DataElement = rust_string.clone().into();
1575 let rust_string_ok: Result<String> = data_element_url.clone().try_into();
1576 let rust_string_err: Result<u16> = data_element_url.clone().try_into();
1577 assert_eq!(data_element_url_into, data_element_url);
1578 assert_eq!(rust_string_ok, Ok(rust_string));
1579 assert_eq!(
1580 rust_string_err,
1581 Err(DataElementConversionError { data_element: data_element_url })
1582 );
1583
1584 let rust_bool = true;
1585 let data_element_bool = DataElement::Bool(true);
1586 let data_element_bool_into: DataElement = rust_bool.into();
1587 let rust_bool_ok: Result<bool> = data_element_bool.clone().try_into();
1588 let rust_bool_err: Result<u16> = data_element_bool.clone().try_into();
1589 assert_eq!(data_element_bool_into, data_element_bool);
1590 assert_eq!(rust_bool_ok, Ok(rust_bool));
1591 assert_eq!(
1592 rust_bool_err,
1593 Err(DataElementConversionError { data_element: data_element_bool })
1594 );
1595 }
1596}