rust/bt-common: Migrate to strongly typed Address Define Address as a strongly typed struct wrapping `[u8; 6]` with convenience helpers and constants to make interactions cleaner and safer. Update crates that currently use Address with the modified version. Update bt-bass to use strongly typed Address instead of using raw bytes. Bug: 542348813 Test: ./presubmit.sh Change-Id: Ie1048a177100196edfeb14252d04bc076df39107 Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/3560
diff --git a/rust/bt-bass/src/client.rs b/rust/bt-bass/src/client.rs index 9532581..1a1122f 100644 --- a/rust/bt-bass/src/client.rs +++ b/rust/bt-bass/src/client.rs
@@ -14,7 +14,7 @@ use parking_lot::Mutex; use bt_bap::types::{BroadcastCode, BroadcastId}; -use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; +use bt_common::core::{Address, AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; use bt_common::generic_audio::metadata_ltv::Metadata; use bt_common::packet_encoding::Decodable; use bt_gatt::client::{CharacteristicNotification, PeerService, ServiceCharacteristic}; @@ -267,7 +267,7 @@ &self, broadcast_id: BroadcastId, address_type: AddressType, - advertiser_address: [u8; ADDRESS_BYTE_SIZE], + advertiser_address: Address, sid: AdvertisingSetId, pa_sync: PaSync, pa_interval: PeriodicAdvertisingInterval, @@ -736,7 +736,7 @@ let op_fut = client.add_broadcast_source( BroadcastId::try_from(0x11).unwrap(), AddressType::Public, - [0x04, 0x10, 0x00, 0x00, 0x00, 0x00], + Address::new([0x04, 0x10, 0x00, 0x00, 0x00, 0x00]), AdvertisingSetId::try_from(1).unwrap(), PaSync::DoNotSync, PeriodicAdvertisingInterval::unknown(), @@ -758,7 +758,7 @@ BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x11, source_address_type: AddressType::Public, - source_address: [1, 2, 3, 4, 5, 6], + source_address: Address::new([1, 2, 3, 4, 5, 6]), source_adv_sid: AdvertisingSetId::try_from(1).unwrap(), broadcast_id: BroadcastId::try_from(0x11).unwrap(), pa_sync_state: PaSyncState::Synced, @@ -800,7 +800,7 @@ BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x11, source_address_type: AddressType::Public, - source_address: [1, 2, 3, 4, 5, 6], + source_address: Address::new([1, 2, 3, 4, 5, 6]), source_adv_sid: AdvertisingSetId::try_from(1).unwrap(), broadcast_id: BroadcastId::try_from(0x11).unwrap(), pa_sync_state: PaSyncState::Synced, @@ -850,7 +850,7 @@ BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x11, source_address_type: AddressType::Public, - source_address: [1, 2, 3, 4, 5, 6], + source_address: Address::new([1, 2, 3, 4, 5, 6]), source_adv_sid: AdvertisingSetId::try_from(1).unwrap(), broadcast_id: BroadcastId::try_from(0x11).unwrap(), pa_sync_state: PaSyncState::Synced, @@ -921,7 +921,7 @@ BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x11, source_address_type: AddressType::Public, - source_address: [1, 2, 3, 4, 5, 6], + source_address: Address::new([1, 2, 3, 4, 5, 6]), source_adv_sid: AdvertisingSetId::try_from(1).unwrap(), broadcast_id: bid, pa_sync_state: PaSyncState::Synced, @@ -964,7 +964,7 @@ BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x01, source_address_type: AddressType::Public, - source_address: [1, 2, 3, 4, 5, 6], + source_address: Address::new([1, 2, 3, 4, 5, 6]), source_adv_sid: AdvertisingSetId::try_from(1).unwrap(), broadcast_id: BroadcastId::try_from(0x030201).unwrap(), pa_sync_state: PaSyncState::Synced,
diff --git a/rust/bt-bass/src/server.rs b/rust/bt-bass/src/server.rs index 0d9f529..29a20b8 100644 --- a/rust/bt-bass/src/server.rs +++ b/rust/bt-bass/src/server.rs
@@ -714,7 +714,7 @@ use assert_matches::assert_matches; use bt_bap::types::BroadcastId; - use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; + use bt_common::core::{Address, AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; use bt_common::generic_audio::metadata_ltv::Metadata; use bt_gatt::test_utils::{FakeServer, FakeServerEvent, FakeTypes}; use bt_gatt::types::GattError; @@ -729,7 +729,7 @@ ReceiveState::new( source_id, AddressType::Public, - [0x01, 0x02, 0x03, 0x04, 0x05, 0x06], + Address::new([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]), AdvertisingSetId::try_from(1).unwrap(), BroadcastId::try_from(0x123456).unwrap(), PaSyncState::NotSynced, @@ -1031,7 +1031,7 @@ // 1. Remote client writes AddSource to Control Point (Handle 1) let add_op = AddSourceOperation::new( AddressType::Public, - [1, 2, 3, 4, 5, 6], + Address::new([1, 2, 3, 4, 5, 6]), AdvertisingSetId::try_from(1).unwrap(), BroadcastId::try_from(0x123456).unwrap(), PaSync::SyncPastAvailable,
diff --git a/rust/bt-bass/src/types.rs b/rust/bt-bass/src/types.rs index bd37c5a..a1c7ebe 100644 --- a/rust/bt-bass/src/types.rs +++ b/rust/bt-bass/src/types.rs
@@ -4,14 +4,13 @@ use bt_bap::types::{BroadcastCode, BroadcastId}; use bt_common::core::ltv::LtValue; -use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; +use bt_common::core::{Address, AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; use bt_common::generic_audio::metadata_ltv::*; use bt_common::packet_encoding::{Decodable, Encodable, Error as PacketError}; use bt_common::{decodable_enum, Uuid}; use bt_gatt::types::GattError; use std::str::FromStr; -pub const ADDRESS_BYTE_SIZE: usize = 6; const NUM_SUBGROUPS_BYTE_SIZE: usize = 1; const PA_SYNC_BYTE_SIZE: usize = 1; const SOURCE_ID_BYTE_SIZE: usize = 1; @@ -158,7 +157,7 @@ pub struct AddSourceOperation { pub(crate) advertiser_address_type: AddressType, // Address in little endian. - pub(crate) advertiser_address: [u8; ADDRESS_BYTE_SIZE], + pub(crate) advertiser_address: Address, pub(crate) advertising_sid: AdvertisingSetId, pub(crate) broadcast_id: BroadcastId, pub(crate) pa_sync: PaSync, @@ -169,7 +168,7 @@ impl AddSourceOperation { const MIN_PACKET_SIZE: usize = ControlPointOpcode::BYTE_SIZE + AddressType::BYTE_SIZE - + ADDRESS_BYTE_SIZE + + Address::BYTE_SIZE + AdvertisingSetId::BYTE_SIZE + BroadcastId::BYTE_SIZE + PA_SYNC_BYTE_SIZE @@ -178,7 +177,7 @@ pub fn new( address_type: AddressType, - advertiser_address: [u8; ADDRESS_BYTE_SIZE], + advertiser_address: Address, advertising_sid: AdvertisingSetId, broadcast_id: BroadcastId, pa_sync: PaSync, @@ -214,8 +213,7 @@ let decode_fn = || { let _ = Self::check_opcode(buf[0])?; let advertiser_address_type = AddressType::try_from(buf[1])?; - let mut advertiser_address = [0; ADDRESS_BYTE_SIZE]; - advertiser_address.clone_from_slice(&buf[2..8]); + let advertiser_address = Address::new(buf[2..8].try_into().unwrap()); let advertising_sid = AdvertisingSetId::try_from(buf[8])?; let broadcast_id = BroadcastId::decode(&buf[9..12]).0?; let pa_sync = PaSync::try_from(buf[12])?; @@ -264,7 +262,7 @@ buf[0] = Self::opcode() as u8; buf[1] = self.advertiser_address_type as u8; - buf[2..8].copy_from_slice(&self.advertiser_address); + buf[2..8].copy_from_slice(self.advertiser_address.as_bytes()); buf[8] = self.advertising_sid.value(); self.broadcast_id.encode(&mut buf[9..12])?; buf[12] = u8::from(self.pa_sync); @@ -757,7 +755,7 @@ pub(crate) source_id: SourceId, pub(crate) source_address_type: AddressType, // Address in little endian. - pub(crate) source_address: [u8; ADDRESS_BYTE_SIZE], + pub(crate) source_address: Address, pub(crate) source_adv_sid: AdvertisingSetId, pub(crate) broadcast_id: BroadcastId, pub(crate) pa_sync_state: PaSyncState, @@ -769,7 +767,7 @@ impl ReceiveState { const MIN_PACKET_SIZE: usize = SOURCE_ID_BYTE_SIZE + AddressType::BYTE_SIZE - + ADDRESS_BYTE_SIZE + + Address::BYTE_SIZE + AdvertisingSetId::BYTE_SIZE + BroadcastId::BYTE_SIZE + PA_SYNC_BYTE_SIZE @@ -779,7 +777,7 @@ pub fn new( source_id: u8, source_address_type: AddressType, - source_address: [u8; ADDRESS_BYTE_SIZE], + source_address: Address, source_adv_sid: AdvertisingSetId, broadcast_id: BroadcastId, pa_sync_state: PaSyncState, @@ -826,8 +824,7 @@ let decode_fn = || { let source_id = buf[0]; let source_address_type = AddressType::try_from(buf[1])?; - let mut source_address = [0; ADDRESS_BYTE_SIZE]; - source_address.clone_from_slice(&buf[2..8]); + let source_address = Address::new(buf[2..8].try_into().unwrap()); let source_adv_sid = AdvertisingSetId::try_from(buf[8])?; let broadcast_id = BroadcastId::decode(&buf[9..12]).0?; let pa_sync_state = PaSyncState::try_from(buf[12])?; @@ -888,7 +885,7 @@ buf[0] = self.source_id; buf[1] = self.source_address_type as u8; - buf[2..8].copy_from_slice(&self.source_address); + buf[2..8].copy_from_slice(self.source_address.as_bytes()); buf[8] = self.source_adv_sid.value(); self.broadcast_id.encode(&mut buf[9..12])?; buf[12] = u8::from(self.pa_sync_state); @@ -913,7 +910,7 @@ // Num_Subgroups and subgroup-related params. SOURCE_ID_BYTE_SIZE + AddressType::BYTE_SIZE - + self.source_address.len() + + Address::BYTE_SIZE + AdvertisingSetId::BYTE_SIZE + self.broadcast_id.encoded_len() + PA_SYNC_BYTE_SIZE @@ -1200,7 +1197,7 @@ // Encoding operation with no subgroups. let op = AddSourceOperation::new( AddressType::Public, - [0x04, 0x10, 0x00, 0x00, 0x00, 0x00], + Address::new([0x04, 0x10, 0x00, 0x00, 0x00, 0x00]), AdvertisingSetId::try_from(1).unwrap(), BroadcastId::try_from(0x11).unwrap(), PaSync::DoNotSync, @@ -1232,7 +1229,7 @@ ])]; let op = AddSourceOperation::new( AddressType::Random, - [0x04, 0x10, 0x00, 0x00, 0x00, 0x00], + Address::new([0x04, 0x10, 0x00, 0x00, 0x00, 0x00]), AdvertisingSetId::try_from(1).unwrap(), BroadcastId::try_from(0x11).unwrap(), PaSync::SyncPastAvailable, @@ -1378,7 +1375,7 @@ let state = BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x01, source_address_type: AddressType::Public, - source_address: [0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A], + source_address: Address::new([0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A]), source_adv_sid: AdvertisingSetId::try_from(0x01).unwrap(), broadcast_id: BroadcastId::try_from(0x00010203).unwrap(), pa_sync_state: PaSyncState::Synced, @@ -1412,7 +1409,7 @@ let state = BroadcastReceiveState::NonEmpty(ReceiveState { source_id: 0x01, source_address_type: AddressType::Random, - source_address: [0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A], + source_address: Address::new([0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A]), source_adv_sid: AdvertisingSetId::try_from(0x01).unwrap(), broadcast_id: BroadcastId::try_from(0x00010203).unwrap(), pa_sync_state: PaSyncState::NotSynced,
diff --git a/rust/bt-broadcast-assistant/src/assistant.rs b/rust/bt-broadcast-assistant/src/assistant.rs index fe6e6a2..b75d5ef 100644 --- a/rust/bt-broadcast-assistant/src/assistant.rs +++ b/rust/bt-broadcast-assistant/src/assistant.rs
@@ -206,7 +206,7 @@ pub fn force_discover_broadcast_source( &self, peer_id: PeerId, - address: [u8; 6], + address: bt_common::core::Address, address_type: bt_common::core::AddressType, advertising_sid: bt_common::core::AdvertisingSetId, ) -> Result<BroadcastSource, Error> { @@ -281,7 +281,7 @@ use std::task::Poll; use bt_bap::types::*; - use bt_common::core::{AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; + use bt_common::core::{Address, AddressType, AdvertisingSetId, PeriodicAdvertisingInterval}; use bt_common::generic_audio::metadata_ltv::Metadata; use bt_gatt::test_utils::{FakeCentral, FakeClient, FakeTypes}; @@ -297,7 +297,7 @@ let (bs, changed) = discovered.merge_broadcast_source_data( &key1, &BroadcastSource::default() - .with_address([1, 2, 3, 4, 5, 6]) + .with_address(Address::new([1, 2, 3, 4, 5, 6])) .with_address_type(AddressType::Public) .with_broadcast_id(bid1), ); @@ -305,7 +305,7 @@ assert_eq!( bs, BroadcastSource { - address: Some([1, 2, 3, 4, 5, 6]), + address: Some(Address::new([1, 2, 3, 4, 5, 6])), address_type: Some(AddressType::Public), broadcast_id: Some(bid1), periodic_advertising_interval: None, @@ -329,7 +329,7 @@ assert_eq!( bs, BroadcastSource { - address: Some([1, 2, 3, 4, 5, 6]), + address: Some(Address::new([1, 2, 3, 4, 5, 6])), address_type: Some(AddressType::Random), broadcast_id: Some(bid1), periodic_advertising_interval: Some(PeriodicAdvertisingInterval(0x0100)), @@ -357,7 +357,7 @@ let (bs, changed) = discovered.merge_broadcast_source_data( &key2, &BroadcastSource::default() - .with_address([1, 2, 3, 4, 5, 6]) + .with_address(Address::new([1, 2, 3, 4, 5, 6])) .with_address_type(AddressType::Public) .with_broadcast_id(bid2), ); @@ -365,7 +365,7 @@ assert_eq!( bs, BroadcastSource { - address: Some([1, 2, 3, 4, 5, 6]), + address: Some(Address::new([1, 2, 3, 4, 5, 6])), address_type: Some(AddressType::Public), broadcast_id: Some(bid2), periodic_advertising_interval: None, @@ -425,7 +425,7 @@ fn force_discover_broadcast_source_test() { let assistant = BroadcastAssistant::<FakeTypes>::new(FakeCentral::new()); let peer_id = PeerId(1); - let address = [1, 2, 3, 4, 5, 6]; + let address = Address::new([1, 2, 3, 4, 5, 6]); let address_type = AddressType::Public; let sid = AdvertisingSetId::try_from(1).unwrap();
diff --git a/rust/bt-broadcast-assistant/src/assistant/event.rs b/rust/bt-broadcast-assistant/src/assistant/event.rs index 2240a36..c679759 100644 --- a/rust/bt-broadcast-assistant/src/assistant/event.rs +++ b/rust/bt-broadcast-assistant/src/assistant/event.rs
@@ -370,7 +370,7 @@ use assert_matches::assert_matches; - use bt_common::core::{AddressType, AdvertisingSetId}; + use bt_common::core::{Address, AddressType, AdvertisingSetId}; use bt_gatt::central::{AdvertisingDatum, PeerName}; use bt_gatt::test_utils::{ FakePeriodicAdvertising, FakeTypes, ScannedResultStream, ScannedResultStreamController, @@ -432,7 +432,7 @@ let _ = stream.broadcast_sources.merge_broadcast_source_data( &(broadcast_source_pid, AdvertisingSetId::try_from(1).unwrap()), &BroadcastSource::default() - .with_address([1, 2, 3, 4, 5, 6]) + .with_address(Address::new([1, 2, 3, 4, 5, 6])) .with_address_type(AddressType::Public), ); @@ -481,7 +481,7 @@ assert_eq!(peer, broadcast_source_pid); assert_eq!(advertising_sid, AdvertisingSetId::try_from(1).unwrap()); assert_eq!(source.periodic_advertising_interval, Some(PeriodicAdvertisingInterval(0x0100))); - assert_eq!(source.address, Some([1, 2, 3, 4, 5, 6])); + assert_eq!(source.address, Some(Address::new([1, 2, 3, 4, 5, 6]))); assert_eq!(source.broadcast_name, Some("Test Broadcast".to_string())); });
diff --git a/rust/bt-broadcast-assistant/src/assistant/peer.rs b/rust/bt-broadcast-assistant/src/assistant/peer.rs index 8c5860d..c4a4d10 100644 --- a/rust/bt-broadcast-assistant/src/assistant/peer.rs +++ b/rust/bt-broadcast-assistant/src/assistant/peer.rs
@@ -206,7 +206,7 @@ use std::collections::HashMap; use std::task::Poll; - use bt_common::core::{AddressType, AdvertisingSetId}; + use bt_common::core::{Address, AddressType, AdvertisingSetId}; use bt_gatt::test_utils::{FakeClient, FakeGetPeerAddr, FakePeerService, FakeTypes}; use bt_gatt::types::{ AttributePermissions, CharacteristicProperties, CharacteristicProperty, Handle, @@ -304,8 +304,11 @@ // Should fail because peer address couldn't be looked up. { - let address_lookup = - StaticPeerAddr::new_for_peer(PeerId(1002), [1, 2, 3, 4, 5, 6], AddressType::Public); + let address_lookup = StaticPeerAddr::new_for_peer( + PeerId(1002), + Address::new([1, 2, 3, 4, 5, 6]), + AddressType::Public, + ); let fut = peer.add_broadcast_source( PeerId(1001), AdvertisingSetId::try_from(1).unwrap(), @@ -320,8 +323,11 @@ // Should fail because not enough information. { - let address_lookup = - StaticPeerAddr::new_for_peer(PeerId(1001), [1, 2, 3, 4, 5, 6], AddressType::Public); + let address_lookup = StaticPeerAddr::new_for_peer( + PeerId(1001), + Address::new([1, 2, 3, 4, 5, 6]), + AddressType::Public, + ); let fut = peer.add_broadcast_source( PeerId(1001), AdvertisingSetId::try_from(1).unwrap(),
diff --git a/rust/bt-broadcast-assistant/src/debug.rs b/rust/bt-broadcast-assistant/src/debug.rs index b9d933c..032cd44 100644 --- a/rust/bt-broadcast-assistant/src/debug.rs +++ b/rust/bt-broadcast-assistant/src/debug.rs
@@ -9,9 +9,9 @@ #[cfg(any(test, feature = "debug"))] use bt_common::core::ltv::LtValue; -#[cfg(any(test, feature = "debug"))] -use bt_common::core::AddressType; use bt_common::core::AdvertisingSetId; +#[cfg(any(test, feature = "debug"))] +use bt_common::core::{Address, AddressType}; use bt_common::debug_command::CommandRunner; use bt_common::debug_command::CommandSet; use bt_common::gen_commandset; @@ -133,14 +133,8 @@ #[cfg(any(test, feature = "debug"))] /// Returns the bd address in little endian ordering. -pub fn parse_bd_addr(input: &str) -> Result<[u8; 6], String> { - let mut tokens: Vec<u8> = - input.split(':').map(|t| u8::from_str_radix(t, 16)).filter_map(Result::ok).collect(); - if tokens.len() != 6 { - return Err(format!("failed to parse bd address from {input}")); - } - tokens.reverse(); - tokens.try_into().map_err(|e| format!("{e:?}")) +pub fn parse_bd_addr(input: &str) -> Result<Address, String> { + input.parse::<Address>().map_err(|e| format!("{e:?}")) } fn parse_broadcast_id(input: &str) -> Result<BroadcastId, String> { @@ -550,7 +544,7 @@ fn test_parse_bd_addr() { assert_eq!( parse_bd_addr("3c:80:f1:ed:32:2c").expect("should be ok"), - [0x2c, 0x32, 0xed, 0xf1, 0x80, 0x3c] + Address::new([0x2c, 0x32, 0xed, 0xf1, 0x80, 0x3c]) ); // Address with 5 parts is invalid. let _ = parse_bd_addr("3c:80:f1:ed:32").expect_err("should fail");
diff --git a/rust/bt-broadcast-assistant/src/types.rs b/rust/bt-broadcast-assistant/src/types.rs index e6d77d4..021d86b 100644 --- a/rust/bt-broadcast-assistant/src/types.rs +++ b/rust/bt-broadcast-assistant/src/types.rs
@@ -33,7 +33,7 @@ self.broadcast_id.is_some() && self.endpoint.is_some() } - pub fn with_address(&mut self, address: [u8; 6]) -> &mut Self { + pub fn with_address(&mut self, address: Address) -> &mut Self { self.address = Some(address); self }
diff --git a/rust/bt-common/src/core.rs b/rust/bt-common/src/core.rs index 8076264..91ec9dc 100644 --- a/rust/bt-common/src/core.rs +++ b/rust/bt-common/src/core.rs
@@ -11,7 +11,58 @@ /// Bluetooth Device Address that uniquely identifies the device /// to another Bluetooth device. /// See Core spec v5.3 Vol 2, Part B section 1.2. -pub type Address = [u8; 6]; +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Address([u8; 6]); + +impl Address { + pub const BYTE_SIZE: usize = 6; + + pub const fn new(bytes: [u8; 6]) -> Self { + Self(bytes) + } + + pub const fn as_bytes(&self) -> &[u8; 6] { + &self.0 + } +} + +impl From<[u8; 6]> for Address { + fn from(bytes: [u8; 6]) -> Self { + Self(bytes) + } +} + +impl std::fmt::Display for Address { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + self.0[5], self.0[4], self.0[3], self.0[2], self.0[1], self.0[0] + ) + } +} + +impl FromStr for Address { + type Err = PacketError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 6 { + return Err(PacketError::InvalidParameter(format!("invalid address format: {s}"))); + } + let mut bytes = [0u8; 6]; + for (i, part) in parts.iter().enumerate() { + if part.is_empty() { + return Err(PacketError::InvalidParameter(format!("invalid address format: {s}"))); + } + let byte = u8::from_str_radix(part, 16).map_err(|_| { + PacketError::InvalidParameter(format!("invalid byte in address: {part}")) + })?; + bytes[5 - i] = byte; + } + Ok(Self(bytes)) + } +} /// See Core spec v5.3 Vol 3, Part C section 15.1.1. #[repr(u8)] @@ -331,4 +382,29 @@ assert_eq!(AdvertisingSetId::try_from(0x10), Err(PacketError::OutOfRange)); assert_eq!(AdvertisingSetId::try_from(0xFF), Err(PacketError::OutOfRange)); } + + #[test] + fn address_display() { + let addr = Address::new([0x2C, 0x32, 0xED, 0xF1, 0x80, 0x3C]); + assert_eq!(addr.to_string(), "3C:80:F1:ED:32:2C"); + } + + #[test] + fn address_from_str_success() { + let addr = Address::from_str("3C:80:F1:ED:32:2C").expect("valid address"); + assert_eq!(addr.as_bytes(), &[0x2C, 0x32, 0xED, 0xF1, 0x80, 0x3C]); + + let lowercase = Address::from_str("3c:80:f1:ed:32:2c").expect("valid address"); + assert_eq!(lowercase, addr); + } + + #[test] + fn address_from_str_failure() { + assert!(Address::from_str("3c:80:f1:ed:32").is_err()); + assert!(Address::from_str("3c:80:f1::32:2c").is_err()); + assert!(Address::from_str(":80:f1:ed:32:2c").is_err()); + assert!(Address::from_str("3c:80:f1:ed:32:").is_err()); + assert!(Address::from_str("3c.80.f1.ed.32.2c").is_err()); + assert!(Address::from_str("3c:80:f1:ed:32:gg").is_err()); + } }
diff --git a/rust/bt-gatt/src/test_utils.rs b/rust/bt-gatt/src/test_utils.rs index c31ffab..858362b 100644 --- a/rust/bt-gatt/src/test_utils.rs +++ b/rust/bt-gatt/src/test_utils.rs
@@ -299,17 +299,8 @@ impl GetPeerAddr for FakeGetPeerAddr { async fn get_peer_address(&self, peer_id: PeerId) -> Result<(Address, AddressType)> { - Ok(( - [ - peer_id.0 as u8, - ((peer_id.0 >> 8) & 0xff) as u8, - ((peer_id.0 >> 16) & 0xff) as u8, - ((peer_id.0 >> 24) & 0xff) as u8, - ((peer_id.0 >> 32) & 0xff) as u8, - ((peer_id.0 >> 48) & 0xff) as u8, - ], - AddressType::Public, - )) + let bytes: [u8; 6] = peer_id.0.to_le_bytes()[..6].try_into().unwrap(); + Ok((Address::new(bytes), AddressType::Public)) } }