From 3ed5aac78236041d8ca5fe82c094a8f55a2f34e3 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 24 Apr 2024 04:21:57 +0200 Subject: [PATCH 1/5] chore: Use `objc2` in `corebluetooth` platform `bool` is safe to use in `msg_send!`/`msg_send_id!` calls --- Cargo.toml | 4 +- src/corebluetooth/central_delegate.rs | 91 +++++++++++------------ src/corebluetooth/framework.rs | 83 +++++++++++++-------- src/corebluetooth/internal.rs | 81 ++++++++++---------- src/corebluetooth/utils/core_bluetooth.rs | 26 ++++--- src/corebluetooth/utils/mod.rs | 9 ++- src/corebluetooth/utils/nsstring.rs | 24 ++---- src/lib.rs | 6 -- 8 files changed, 167 insertions(+), 157 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8897c430..8077af0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,8 +46,8 @@ once_cell = "1.19.0" jni-utils = "0.1.1" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -cocoa = "0.25.0" -objc = "0.2.7" +objc2 = "0.5.1" +objc2-foundation = { version = "0.2.0", features = ["NSArray", "NSData", "NSDictionary", "NSError", "NSString", "NSUUID", "NSValue"] } libc = "0.2.151" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/src/corebluetooth/central_delegate.rs b/src/corebluetooth/central_delegate.rs index bf3dfe67..f30d2316 100644 --- a/src/corebluetooth/central_delegate.rs +++ b/src/corebluetooth/central_delegate.rs @@ -22,21 +22,17 @@ use super::{ core_bluetooth::{cbuuid_to_uuid, characteristic_debug, peripheral_debug, service_debug}, nsdata_to_vec, nsstring::nsstring_to_string, - nsuuid_to_uuid, + nsuuid_to_uuid, StrongPtr, }, }; -use cocoa::base::{id, nil}; use futures::channel::mpsc::{self, Receiver, Sender}; use futures::sink::SinkExt; use libc::c_void; use log::{error, trace}; -use objc::{ - class, - declare::ClassDecl, - rc::StrongPtr, - runtime::{Class, Object, Protocol, Sel}, +use objc2::runtime::{ + AnyClass as Class, AnyObject as Object, AnyProtocol as Protocol, ClassBuilder, Sel, }; -use objc::{msg_send, sel, sel_impl}; +use objc2::{class, msg_send, sel}; use std::convert::TryInto; use std::{ collections::HashMap, @@ -294,8 +290,12 @@ impl Debug for CentralDelegateEvent { } pub mod CentralDelegate { + use objc2::runtime::AnyObject; + use objc2_foundation::{NSDictionary, NSString}; + use crate::corebluetooth::{ - framework::ns::number_as_i64, utils::core_bluetooth::descriptor_debug, + framework::ns::number_as_i64, + utils::{core_bluetooth::descriptor_debug, id, nil}, }; use super::*; @@ -327,50 +327,50 @@ pub mod CentralDelegate { trace!("delegate_class"); static REGISTER_DELEGATE_CLASS: Once = Once::new(); REGISTER_DELEGATE_CLASS.call_once(|| { - let mut decl = ClassDecl::new("BtlePlugCentralManagerDelegate", class!(NSObject)).unwrap(); + let mut decl = ClassBuilder::new("BtlePlugCentralManagerDelegate", class!(NSObject)).unwrap(); decl.add_protocol(Protocol::get("CBCentralManagerDelegate").unwrap()); decl.add_ivar::<*mut c_void>(DELEGATE_SENDER_IVAR); /* crossbeam_channel::Sender* */ unsafe { // Initialization decl.add_method(sel!(initWithSender:), - delegate_init as extern fn(&mut Object, Sel, *mut c_void) -> id); + delegate_init as extern fn(_, _, _) -> _); // CentralManager Events decl.add_method(sel!(centralManagerDidUpdateState:), - delegate_centralmanagerdidupdatestate as extern fn(&mut Object, Sel, id)); + delegate_centralmanagerdidupdatestate as extern fn(_, _, _)); // decl.add_method(sel!(centralManager:willRestoreState:), - // delegate_centralmanager_willrestorestate as extern fn(&mut Object, Sel, id, id)); + // delegate_centralmanager_willrestorestate as extern fn(_, _, _, _)); decl.add_method(sel!(centralManager:didConnectPeripheral:), - delegate_centralmanager_didconnectperipheral as extern fn(&mut Object, Sel, id, id)); + delegate_centralmanager_didconnectperipheral as extern fn(_, _, _, _)); decl.add_method(sel!(centralManager:didDisconnectPeripheral:error:), - delegate_centralmanager_diddisconnectperipheral_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_centralmanager_diddisconnectperipheral_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(centralManager:didFailToConnectPeripheral:error:), - delegate_centralmanager_didfailtoconnectperipheral_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_centralmanager_didfailtoconnectperipheral_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(centralManager:didDiscoverPeripheral:advertisementData:RSSI:), - delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi as extern fn(&mut Object, Sel, id, id, id, id)); + delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi as extern fn(_, _, _, _, _, _)); // Peripheral events decl.add_method(sel!(peripheral:didDiscoverServices:), - delegate_peripheral_diddiscoverservices as extern fn(&mut Object, Sel, id, id)); + delegate_peripheral_diddiscoverservices as extern fn(_, _, _, _)); decl.add_method(sel!(peripheral:didDiscoverIncludedServicesForService:error:), - delegate_peripheral_diddiscoverincludedservicesforservice_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_diddiscoverincludedservicesforservice_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didDiscoverCharacteristicsForService:error:), - delegate_peripheral_diddiscovercharacteristicsforservice_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_diddiscovercharacteristicsforservice_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didDiscoverDescriptorsForCharacteristic:error:), - delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didUpdateValueForCharacteristic:error:), - delegate_peripheral_didupdatevalueforcharacteristic_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didupdatevalueforcharacteristic_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didUpdateNotificationStateForCharacteristic:error:), - delegate_peripheral_didupdatenotificationstateforcharacteristic_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didupdatenotificationstateforcharacteristic_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didWriteValueForCharacteristic:error:), - delegate_peripheral_didwritevalueforcharacteristic_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didwritevalueforcharacteristic_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didReadRSSI:error:), - delegate_peripheral_didreadrssi_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didreadrssi_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didUpdateValueForDescriptor:error:), - delegate_peripheral_didupdatevaluefordescriptor_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didupdatevaluefordescriptor_error as extern fn(_, _, _, _, _)); decl.add_method(sel!(peripheral:didWriteValueForDescriptor:error:), - delegate_peripheral_didwritevaluefordescriptor_error as extern fn(&mut Object, Sel, id, id, id)); + delegate_peripheral_didwritevaluefordescriptor_error as extern fn(_, _, _, _, _)); } decl.register(); @@ -417,7 +417,7 @@ pub mod CentralDelegate { // dropped? Not quite sure how delegate lifetime works here. unsafe { trace!("Storing off ivars!"); - delegate.set_ivar(DELEGATE_SENDER_IVAR, sender); + *delegate.get_mut_ivar(DELEGATE_SENDER_IVAR) = sender; } delegate } @@ -511,7 +511,7 @@ pub mod CentralDelegate { _cmd: Sel, _central: id, peripheral: id, - adv_data: id, + adv_data: &NSDictionary, rssi: id, ) { trace!( @@ -519,7 +519,7 @@ pub mod CentralDelegate { peripheral_debug(peripheral) ); - let held_peripheral = unsafe { StrongPtr::retain(peripheral) }; + let held_peripheral = unsafe { StrongPtr::retain(peripheral as *mut _).unwrap() }; send_delegate_event( delegate, CentralDelegateEvent::DiscoveredPeripheral { @@ -531,10 +531,9 @@ pub mod CentralDelegate { let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); - let manufacturer_data = ns::dictionary_objectforkey(adv_data, unsafe { - cb::ADVERTISEMENT_DATA_MANUFACTURER_DATA_KEY - }); - if manufacturer_data != nil { + let manufacturer_data = + adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_MANUFACTURER_DATA_KEY }); + if let Some(manufacturer_data) = manufacturer_data { // manufacturer_data: NSData let length = ns::data_length(manufacturer_data); if length >= 2 { @@ -553,10 +552,9 @@ pub mod CentralDelegate { ); } } - let service_data = ns::dictionary_objectforkey(adv_data, unsafe { - cb::ADVERTISEMENT_DATA_SERVICE_DATA_KEY - }); - if service_data != nil { + + let service_data = adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_SERVICE_DATA_KEY }); + if let Some(service_data) = service_data { // service_data: [CBUUID, NSData] let uuids = ns::dictionary_allkeys(service_data); let mut result = HashMap::new(); @@ -577,10 +575,8 @@ pub mod CentralDelegate { ); } - let services = ns::dictionary_objectforkey(adv_data, unsafe { - cb::ADVERTISEMENT_DATA_SERVICE_UUIDS_KEY - }); - if services != nil { + let services = adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_SERVICE_UUIDS_KEY }); + if let Some(services) = services { // services: [CBUUID] let mut service_uuids = Vec::new(); for i in 0..ns::array_count(services) { @@ -629,10 +625,7 @@ pub mod CentralDelegate { // Create the map entry we'll need to export. let uuid = cbuuid_to_uuid(cb::attribute_uuid(s)); - let held_service; - unsafe { - held_service = StrongPtr::retain(s); - } + let held_service = unsafe { StrongPtr::retain(s).unwrap() }; service_map.insert(uuid, held_service); } let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); @@ -689,7 +682,7 @@ pub mod CentralDelegate { cb::peripheral_discoverdescriptorsforcharacteristic(peripheral, c); // Create the map entry we'll need to export. let uuid = cbuuid_to_uuid(cb::attribute_uuid(c)); - let held_char = unsafe { StrongPtr::retain(c) }; + let held_char = unsafe { StrongPtr::retain(c).unwrap() }; characteristics.insert(uuid, held_char); } let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); @@ -725,7 +718,7 @@ pub mod CentralDelegate { let d = ns::array_objectatindex(descs, i); // Create the map entry we'll need to export. let uuid = cbuuid_to_uuid(cb::attribute_uuid(d)); - let held_desc = unsafe { StrongPtr::retain(d) }; + let held_desc = unsafe { StrongPtr::retain(d).unwrap() }; descriptors.insert(uuid, held_desc); } let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); @@ -811,7 +804,7 @@ pub mod CentralDelegate { let service = cb::characteristic_service(characteristic); let service_uuid = cbuuid_to_uuid(cb::attribute_uuid(service)); let characteristic_uuid = cbuuid_to_uuid(cb::attribute_uuid(characteristic)); - if cb::characteristic_isnotifying(characteristic) == objc::runtime::YES { + if cb::characteristic_isnotifying(characteristic) { send_delegate_event( delegate, CentralDelegateEvent::CharacteristicSubscribed { diff --git a/src/corebluetooth/framework.rs b/src/corebluetooth/framework.rs index 2efa110b..15c04336 100644 --- a/src/corebluetooth/framework.rs +++ b/src/corebluetooth/framework.rs @@ -16,48 +16,60 @@ // This file may not be copied, modified, or distributed except // according to those terms. -use cocoa::{ - base::{id, nil}, - foundation::{NSArray, NSData, NSDictionary, NSString, NSUInteger}, -}; -use objc::runtime::BOOL; -use objc::{class, msg_send, sel, sel_impl}; -use std::os::raw::{c_char, c_int, c_uint}; +use super::utils::{id, nil}; +use objc2::encode::{Encode, Encoding}; +use objc2::rc::Id; +use objc2::{class, msg_send}; +use objc2_foundation::{NSArray, NSDictionary, NSInteger, NSString, NSUInteger}; +use std::os::raw::{c_char, c_int, c_uint, c_void}; +use std::ptr; pub mod ns { + use objc2::runtime::AnyObject; + use super::*; // NSNumber - pub fn number_withbool(value: BOOL) -> id { + pub fn number_withbool(value: bool) -> id { unsafe { msg_send![class!(NSNumber), numberWithBool: value] } } pub fn number_as_i64(value: id) -> i64 { unsafe { - let i: cocoa::foundation::NSInteger = msg_send![&*value, integerValue]; + let i: NSInteger = msg_send![&*value, integerValue]; i as i64 } } // NSArray - pub fn array_count(nsarray: impl NSArray) -> NSUInteger { - unsafe { nsarray.count() } + pub fn array_count(nsarray: id /* NSArray* */) -> NSUInteger { + let nsarray: &NSArray = unsafe { &*nsarray.cast() }; + nsarray.count() } - pub fn array_objectatindex(nsarray: impl NSArray, index: NSUInteger) -> id { - unsafe { nsarray.objectAtIndex(index) } + pub fn array_objectatindex( + nsarray: id, /* NSArray* */ + index: NSUInteger, + ) -> *mut AnyObject { + let nsarray: &NSArray = unsafe { &*nsarray.cast() }; + unsafe { Id::into_raw(nsarray.objectAtIndex(index)).cast() } } // NSDictionary - pub fn dictionary_allkeys(nsdict: impl NSDictionary) -> id /* NSArray* */ { - unsafe { nsdict.allKeys() } + pub fn dictionary_allkeys(nsdict: id /* NSDictionary* */) -> id /* NSArray* */ { + let nsdict: &NSDictionary = unsafe { &*nsdict.cast() }; + unsafe { Id::into_raw(nsdict.allKeys()).cast() } } - pub fn dictionary_objectforkey(nsdict: impl NSDictionary, key: id) -> id { - unsafe { nsdict.objectForKey_(key) } + pub fn dictionary_objectforkey(nsdict: id /* NSDictionary* */, key: id) -> id { + let nsdict: &NSDictionary = unsafe { &*nsdict.cast() }; + match unsafe { nsdict.objectForKey(&*key) } { + Some(obj) => Id::into_raw(obj).cast(), + None => ptr::null_mut(), + } } // NSMutableDictionary : NSDictionary @@ -78,12 +90,13 @@ pub mod ns { } } - pub fn data_length(nsdata: impl NSData) -> NSUInteger { - unsafe { nsdata.length() } + pub fn data_length(nsdata: id /* NSData* */) -> NSUInteger { + unsafe { msg_send![nsdata, length] } } pub fn data_bytes(nsdata: id) -> *const u8 { - unsafe { msg_send![nsdata, bytes] } + let bytes: *const c_void = unsafe { msg_send![nsdata, bytes] }; + bytes.cast() } // NSUUID @@ -106,6 +119,9 @@ pub mod ns { } pub mod cb { + use objc2::msg_send_id; + use objc2::runtime::AnyObject; + use super::*; use std::ffi::CString; @@ -132,11 +148,11 @@ pub mod cb { #[link(name = "CoreBluetooth", kind = "framework")] extern "C" { - pub static CBAdvertisementDataManufacturerDataKey: id; - pub static CBAdvertisementDataServiceDataKey: id; - pub static CBAdvertisementDataServiceUUIDsKey: id; + pub static CBAdvertisementDataManufacturerDataKey: &'static NSString; + pub static CBAdvertisementDataServiceDataKey: &'static NSString; + pub static CBAdvertisementDataServiceUUIDsKey: &'static NSString; - pub static CBCentralManagerScanOptionAllowDuplicatesKey: id; + pub static CBCentralManagerScanOptionAllowDuplicatesKey: &'static NSString; } } @@ -148,6 +164,7 @@ pub mod cb { unsafe { let cbcentralmanager: id = msg_send![class!(CBCentralManager), alloc]; let queue = dispatch_queue_create(label.as_ptr(), DISPATCH_QUEUE_SERIAL); + let queue: id = queue.cast(); msg_send![cbcentralmanager, initWithDelegate:delegate queue:queue] } @@ -195,6 +212,10 @@ pub mod cb { AllowedAlways = 3, } + unsafe impl Encode for CBManagerAuthorization { + const ENCODING: Encoding = i64::ENCODING; + } + // CBPeer pub fn peer_identifier(cbpeer: id) -> id /* NSUUID* */ { @@ -216,6 +237,10 @@ pub mod cb { Disconnecting = 3, } + unsafe impl Encode for CBPeripheralState { + const ENCODING: Encoding = i64::ENCODING; + } + pub fn peripheral_state(cbperipheral: id) -> CBPeripheralState { unsafe { msg_send![cbperipheral, state] } } @@ -267,7 +292,7 @@ pub mod cb { pub fn peripheral_setnotifyvalue_forcharacteristic( cbperipheral: id, - value: BOOL, + value: bool, characteristic: id, /* CBCharacteristic* */ ) { unsafe { msg_send![cbperipheral, setNotifyValue:value forCharacteristic:characteristic] } @@ -312,7 +337,7 @@ pub mod cb { // CBService : CBAttribute - pub fn service_isprimary(cbservice: id) -> BOOL { + pub fn service_isprimary(cbservice: id) -> bool { unsafe { msg_send![cbservice, isPrimary] } } @@ -326,7 +351,7 @@ pub mod cb { // CBCharacteristic : CBAttribute - pub fn characteristic_isnotifying(cbcharacteristic: id) -> BOOL { + pub fn characteristic_isnotifying(cbcharacteristic: id) -> bool { unsafe { msg_send![cbcharacteristic, isNotifying] } } @@ -368,8 +393,8 @@ pub mod cb { unsafe { msg_send![cbuuid, UUIDString] } } - pub fn uuid_uuidwithstring(s: impl NSString) -> id /* CBUUID */ { - unsafe { msg_send![class!(CBUUID), UUIDWithString: s] } + pub fn uuid_uuidwithstring(s: &NSString) -> Id /* CBUUID */ { + unsafe { msg_send_id![class!(CBUUID), UUIDWithString: s] } } // CBCentralManagerScanOption...Key diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index c3dd3eef..d6050435 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -17,25 +17,20 @@ use super::{ future::{BtlePlugFuture, BtlePlugFutureStateShared}, utils::{ core_bluetooth::{cbuuid_to_uuid, uuid_to_cbuuid}, + id, nil, nsstring::nsstring_to_string, - nsuuid_to_uuid, + nsuuid_to_uuid, StrongPtr, }, }; -use crate::api::{ - bleuuid::uuid_from_u16, CharPropFlags, Characteristic, Descriptor, ScanFilter, Service, - WriteType, -}; +use crate::api::{CharPropFlags, Characteristic, Descriptor, ScanFilter, Service, WriteType}; use crate::Error; -use cocoa::{ - base::{id, nil}, - foundation::NSArray, -}; use futures::channel::mpsc::{self, Receiver, Sender}; use futures::select; use futures::sink::SinkExt; use futures::stream::{Fuse, StreamExt}; use log::{error, trace, warn}; -use objc::{rc::StrongPtr, runtime::YES}; +use objc2::rc::Id; +use objc2_foundation::NSArray; use std::{ collections::{BTreeSet, HashMap, VecDeque}, fmt::{self, Debug, Formatter}, @@ -54,7 +49,7 @@ struct CBDescriptor { impl CBDescriptor { pub fn new(descriptor: StrongPtr) -> Self { - let uuid = cbuuid_to_uuid(cb::attribute_uuid(*descriptor)); + let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*descriptor)); Self { descriptor, uuid, @@ -92,13 +87,13 @@ impl Debug for CBCharacteristic { impl CBCharacteristic { pub fn new(characteristic: StrongPtr) -> Self { - let properties = CBCharacteristic::form_flags(*characteristic); - let uuid = cbuuid_to_uuid(cb::attribute_uuid(*characteristic)); - let descriptors_arr = cb::characteristic_descriptors(*characteristic); + let properties = CBCharacteristic::form_flags(&*characteristic); + let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*characteristic)); + let descriptors_arr = cb::characteristic_descriptors(&*characteristic); let mut descriptors = HashMap::new(); for i in 0..ns::array_count(descriptors_arr) { let d = ns::array_objectatindex(descriptors_arr, i); - let descriptor = CBDescriptor::new(unsafe { StrongPtr::retain(d) }); + let descriptor = CBDescriptor::new(unsafe { StrongPtr::retain(d).unwrap() }); descriptors.insert(descriptor.uuid, descriptor); } Self { @@ -278,7 +273,7 @@ impl CBPeripheral { .iter() .map(|(&service_uuid, service)| Service { uuid: service_uuid, - primary: cb::service_isprimary(*service.cbservice) != objc::runtime::NO, + primary: cb::service_isprimary(&*service.cbservice), characteristics: service .characteristics .iter() @@ -435,9 +430,9 @@ impl CoreBluetoothInternal { // Pretty sure these come preallocated? unsafe { let (delegate, delegate_receiver) = CentralDelegate::delegate(); - let delegate = StrongPtr::new(delegate); + let delegate = StrongPtr::from_raw(delegate as *mut _).unwrap(); Self { - manager: StrongPtr::new(cb::centralmanager(*delegate)), + manager: StrongPtr::from_raw(cb::centralmanager(&*delegate) as *mut _).unwrap(), peripherals: HashMap::new(), delegate_receiver: delegate_receiver.fuse(), event_sender, @@ -513,8 +508,8 @@ impl CoreBluetoothInternal { } async fn on_discovered_peripheral(&mut self, peripheral: StrongPtr) { - let uuid = nsuuid_to_uuid(cb::peer_identifier(*peripheral)); - let name = nsstring_to_string(cb::peripheral_name(*peripheral)); + let uuid = nsuuid_to_uuid(cb::peer_identifier(&*peripheral)); + let name = nsstring_to_string(cb::peripheral_name(&*peripheral)); if self.peripherals.contains_key(&uuid) { if let Some(name) = name { self.dispatch_event(CoreBluetoothEvent::DeviceUpdated { uuid, name }) @@ -772,7 +767,7 @@ impl CoreBluetoothInternal { if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) { trace!("Connecting peripheral!"); p.connected_future_state = Some(fut); - cb::centralmanager_connectperipheral(*self.manager, *p.peripheral); + cb::centralmanager_connectperipheral(&*self.manager, &*p.peripheral); } } @@ -781,13 +776,13 @@ impl CoreBluetoothInternal { if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) { trace!("Disconnecting peripheral!"); p.disconnected_future_state = Some(fut); - cb::centralmanager_cancelperipheralconnection(*self.manager, *p.peripheral); + cb::centralmanager_cancelperipheralconnection(&*self.manager, &*p.peripheral); } } fn is_connected(&mut self, peripheral_uuid: Uuid, fut: CoreBluetoothReplyStateShared) { if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) { - let state = cb::peripheral_state(*p.peripheral); + let state = cb::peripheral_state(&*p.peripheral); trace!("Connected state {:?} ", state); fut.lock() .unwrap() @@ -810,9 +805,9 @@ impl CoreBluetoothInternal { { trace!("Writing value! With kind {:?}", kind); cb::peripheral_writevalue_forcharacteristic( - *peripheral.peripheral, + &*peripheral.peripheral, ns::data(&data), - *characteristic.characteristic, + &*characteristic.characteristic, match kind { WriteType::WithResponse => 0, WriteType::WithoutResponse => 1, @@ -843,8 +838,8 @@ impl CoreBluetoothInternal { { trace!("Reading value!"); cb::peripheral_readvalue_forcharacteristic( - *peripheral.peripheral, - *characteristic.characteristic, + &*peripheral.peripheral, + &*characteristic.characteristic, ); characteristic.read_future_state.push_front(fut); } @@ -865,9 +860,9 @@ impl CoreBluetoothInternal { { trace!("Setting subscribe!"); cb::peripheral_setnotifyvalue_forcharacteristic( - *peripheral.peripheral, - objc::runtime::YES, - *characteristic.characteristic, + &*peripheral.peripheral, + true, + &*characteristic.characteristic, ); characteristic.subscribe_future_state.push_front(fut); } @@ -888,9 +883,9 @@ impl CoreBluetoothInternal { { trace!("Setting subscribe!"); cb::peripheral_setnotifyvalue_forcharacteristic( - *peripheral.peripheral, - objc::runtime::NO, - *characteristic.characteristic, + &*peripheral.peripheral, + false, + &*characteristic.characteristic, ); characteristic.unsubscribe_future_state.push_front(fut); } @@ -914,9 +909,9 @@ impl CoreBluetoothInternal { if let Some(descriptor) = characteristic.descriptors.get_mut(&descriptor_uuid) { trace!("Writing descriptor value!"); cb::peripheral_writevalue_fordescriptor( - *peripheral.peripheral, + &*peripheral.peripheral, ns::data(&data), - *descriptor.descriptor, + &*descriptor.descriptor, ); descriptor.write_future_state.push_front(fut); } @@ -940,8 +935,8 @@ impl CoreBluetoothInternal { if let Some(descriptor) = characteristic.descriptors.get_mut(&descriptor_uuid) { trace!("Reading descriptor value!"); cb::peripheral_readvalue_fordescriptor( - *peripheral.peripheral, - *descriptor.descriptor, + &*peripheral.peripheral, + &*descriptor.descriptor, ); descriptor.read_future_state.push_front(fut); } @@ -1130,11 +1125,11 @@ impl CoreBluetoothInternal { let options = ns::mutabledictionary(); // NOTE: If duplicates are not allowed then a peripheral will not show // up again once connected and then disconnected. - ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(YES), unsafe { - cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY + ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(true), unsafe { + &***cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY }); cb::centralmanager_scanforperipheralswithservices_options( - *self.manager, + &*self.manager, service_uuids, options, ); @@ -1142,7 +1137,7 @@ impl CoreBluetoothInternal { fn stop_discovery(&mut self) { trace!("BluetoothAdapter::stop_discovery"); - cb::centralmanager_stopscan(*self.manager); + cb::centralmanager_stopscan(&*self.manager); } } @@ -1157,7 +1152,7 @@ fn scan_filter_to_service_uuids(filter: ScanFilter) -> id { .into_iter() .map(uuid_to_cbuuid) .collect::>(); - unsafe { NSArray::arrayWithObjects(nil, &service_uuids) } + Id::into_raw(NSArray::from_vec(service_uuids)) as id } } @@ -1166,7 +1161,7 @@ impl Drop for CoreBluetoothInternal { trace!("BluetoothAdapter::drop"); // NOTE: stop discovery only here instead of in BluetoothDiscoverySession self.stop_discovery(); - CentralDelegate::delegate_drop_channel(*self.delegate); + CentralDelegate::delegate_drop_channel(&*self.delegate); } } diff --git a/src/corebluetooth/utils/core_bluetooth.rs b/src/corebluetooth/utils/core_bluetooth.rs index 2b02f44d..c0a67514 100644 --- a/src/corebluetooth/utils/core_bluetooth.rs +++ b/src/corebluetooth/utils/core_bluetooth.rs @@ -16,11 +16,14 @@ // This file may not be copied, modified, or distributed except // according to those terms. -use cocoa::base::{id, nil}; +use objc2::rc::Id; +use objc2::runtime::AnyObject; +use objc2_foundation::NSString; use uuid::Uuid; use super::super::framework::{cb, ns}; -use super::nsstring::{nsstring_to_string, str_to_nsstring}; +use super::nsstring::nsstring_to_string; +use super::{id, nil}; /// Convert a CBUUID object to the standard Uuid type. pub fn cbuuid_to_uuid(cbuuid: id) -> Uuid { @@ -40,8 +43,8 @@ pub fn cbuuid_to_uuid(cbuuid: id) -> Uuid { } /// Convert a `Uuid` to a `CBUUID`. -pub fn uuid_to_cbuuid(uuid: Uuid) -> id { - cb::uuid_uuidwithstring(str_to_nsstring(&uuid.to_string())) +pub fn uuid_to_cbuuid(uuid: Uuid) -> Id { + cb::uuid_uuidwithstring(&NSString::from_str(&uuid.to_string())) } pub fn peripheral_debug(peripheral: id) -> String { @@ -83,17 +86,18 @@ pub fn descriptor_debug(descriptor: id) -> String { #[cfg(test)] mod tests { + use objc2_foundation::ns_string; + use super::super::super::framework::cb::uuid_uuidwithstring; - use super::super::nsstring::str_to_nsstring; use super::*; #[test] fn parse_uuid_short() { let uuid_string = "1234"; - let uuid_nsstring = str_to_nsstring(uuid_string); - let cbuuid = uuid_uuidwithstring(uuid_nsstring); - let uuid = cbuuid_to_uuid(cbuuid); + let uuid_nsstring = NSString::from_str(uuid_string); + let cbuuid = uuid_uuidwithstring(&uuid_nsstring); + let uuid = cbuuid_to_uuid(&*cbuuid); assert_eq!( uuid, Uuid::from_u128(0x00001234_0000_1000_8000_00805f9b34fb) @@ -102,9 +106,9 @@ mod tests { #[test] fn parse_uuid_long() { - let uuid_nsstring = str_to_nsstring("12345678-0000-1111-2222-333344445555"); + let uuid_nsstring = ns_string!("12345678-0000-1111-2222-333344445555"); let cbuuid = uuid_uuidwithstring(uuid_nsstring); - let uuid = cbuuid_to_uuid(cbuuid); + let uuid = cbuuid_to_uuid(&*cbuuid); assert_eq!( uuid, Uuid::from_u128(0x12345678_0000_1111_2222_333344445555) @@ -118,7 +122,7 @@ mod tests { Uuid::from_u128(0xabcd1234_0000_1000_8000_00805f9b34fb), Uuid::from_u128(0x12345678_0000_1111_2222_333344445555), ] { - assert_eq!(cbuuid_to_uuid(uuid_to_cbuuid(uuid)), uuid); + assert_eq!(cbuuid_to_uuid(&*uuid_to_cbuuid(uuid)), uuid); } } } diff --git a/src/corebluetooth/utils/mod.rs b/src/corebluetooth/utils/mod.rs index d61d4e4b..73a227e9 100644 --- a/src/corebluetooth/utils/mod.rs +++ b/src/corebluetooth/utils/mod.rs @@ -16,7 +16,8 @@ // This file may not be copied, modified, or distributed except // according to those terms. -use cocoa::base::id; +use objc2::rc::Id; +use objc2::runtime::AnyObject; use std::slice; use uuid::Uuid; @@ -39,3 +40,9 @@ pub fn nsuuid_to_uuid(uuid: id) -> Uuid { let uuid_nsstring = ns::uuid_uuidstring(uuid); nsstring_to_string(uuid_nsstring).unwrap().parse().unwrap() } + +#[allow(non_camel_case_types)] +pub type id = *const objc2::runtime::AnyObject; +#[allow(non_upper_case_globals)] +pub const nil: id = std::ptr::null(); +pub type StrongPtr = Id; diff --git a/src/corebluetooth/utils/nsstring.rs b/src/corebluetooth/utils/nsstring.rs index 72202a9c..fedcaa1f 100644 --- a/src/corebluetooth/utils/nsstring.rs +++ b/src/corebluetooth/utils/nsstring.rs @@ -16,24 +16,16 @@ // This file may not be copied, modified, or distributed except // according to those terms. -use cocoa::{ - base::{id, nil}, - foundation::NSString, -}; -use std::ffi::CStr; +use objc2_foundation::NSString; + +use super::id; /// Convert the given `NSString` to a Rust `String`, or `None` if it is `nil`. pub fn nsstring_to_string(nsstring: id) -> Option { - if nsstring == nil { - return None; - } - unsafe { - Some(String::from( - CStr::from_ptr(nsstring.UTF8String()).to_str().unwrap(), - )) + let nsstring: *const NSString = nsstring.cast(); + if let Some(nsstring) = unsafe { nsstring.as_ref() } { + Some(nsstring.to_string()) + } else { + None } } - -pub fn str_to_nsstring(string: &str) -> id { - unsafe { NSString::alloc(nil).init_str(string) } -} diff --git a/src/lib.rs b/src/lib.rs index edb8c585..aeb3fae7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,12 +85,6 @@ //! } //! ``` -// We won't actually use anything specifically out of this crate. However, if we -// want the CoreBluetooth code to compile, we need the objc protocols -// (specifically, the core bluetooth protocols) exposed by it. -#[cfg(any(target_os = "macos", target_os = "ios"))] -extern crate cocoa; - use crate::api::ParseBDAddrError; use std::result; use std::time::Duration; From 3ed00f35b15a60a027148546a102cac745508691 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 24 Apr 2024 04:08:50 +0200 Subject: [PATCH 2/5] fix: Correct Objective-C calling convention / ABI --- src/corebluetooth/framework.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/corebluetooth/framework.rs b/src/corebluetooth/framework.rs index 15c04336..0a01d777 100644 --- a/src/corebluetooth/framework.rs +++ b/src/corebluetooth/framework.rs @@ -21,7 +21,7 @@ use objc2::encode::{Encode, Encoding}; use objc2::rc::Id; use objc2::{class, msg_send}; use objc2_foundation::{NSArray, NSDictionary, NSInteger, NSString, NSUInteger}; -use std::os::raw::{c_char, c_int, c_uint, c_void}; +use std::os::raw::{c_char, c_void}; use std::ptr; pub mod ns { @@ -75,7 +75,7 @@ pub mod ns { // NSMutableDictionary : NSDictionary pub fn mutabledictionary() -> id { - unsafe { msg_send![class!(NSMutableDictionary), dictionaryWithCapacity:0] } + unsafe { msg_send![class!(NSMutableDictionary), dictionaryWithCapacity: 0usize] } } pub fn mutabledictionary_setobject_forkey(nsmutdict: id, object: id, key: id) { @@ -327,7 +327,7 @@ pub mod cb { // CBPeripheralState = NSInteger from CBPeripheral.h - pub const PERIPHERALSTATE_CONNECTED: c_int = 2; // CBPeripheralStateConnected + pub const PERIPHERALSTATE_CONNECTED: isize = 2; // CBPeripheralStateConnected // CBAttribute @@ -359,7 +359,7 @@ pub mod cb { unsafe { msg_send![cbcharacteristic, value] } } - pub fn characteristic_properties(cbcharacteristic: id) -> c_uint { + pub fn characteristic_properties(cbcharacteristic: id) -> NSUInteger { unsafe { msg_send![cbcharacteristic, properties] } } @@ -379,13 +379,13 @@ pub mod cb { // CBCharacteristicProperties = NSUInteger from CBCharacteristic.h - pub const CHARACTERISTICPROPERTY_BROADCAST: c_uint = 0x01; // CBCharacteristicPropertyBroadcast - pub const CHARACTERISTICPROPERTY_READ: c_uint = 0x02; // CBCharacteristicPropertyRead - pub const CHARACTERISTICPROPERTY_WRITEWITHOUTRESPONSE: c_uint = 0x04; // CBCharacteristicPropertyWriteWithoutResponse - pub const CHARACTERISTICPROPERTY_WRITE: c_uint = 0x08; // CBCharacteristicPropertyWrite - pub const CHARACTERISTICPROPERTY_NOTIFY: c_uint = 0x10; // CBCharacteristicPropertyNotify - pub const CHARACTERISTICPROPERTY_INDICATE: c_uint = 0x20; // CBCharacteristicPropertyIndicate - pub const CHARACTERISTICPROPERTY_AUTHENTICATEDSIGNEDWRITES: c_uint = 0x40; // CBCharacteristicPropertyAuthenticatedSignedWrites + pub const CHARACTERISTICPROPERTY_BROADCAST: usize = 0x01; // CBCharacteristicPropertyBroadcast + pub const CHARACTERISTICPROPERTY_READ: usize = 0x02; // CBCharacteristicPropertyRead + pub const CHARACTERISTICPROPERTY_WRITEWITHOUTRESPONSE: usize = 0x04; // CBCharacteristicPropertyWriteWithoutResponse + pub const CHARACTERISTICPROPERTY_WRITE: usize = 0x08; // CBCharacteristicPropertyWrite + pub const CHARACTERISTICPROPERTY_NOTIFY: usize = 0x10; // CBCharacteristicPropertyNotify + pub const CHARACTERISTICPROPERTY_INDICATE: usize = 0x20; // CBCharacteristicPropertyIndicate + pub const CHARACTERISTICPROPERTY_AUTHENTICATEDSIGNEDWRITES: usize = 0x40; // CBCharacteristicPropertyAuthenticatedSignedWrites // CBUUID From 7f5f7c79937378e473485da0460d04b0e89576b9 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 24 Apr 2024 11:32:28 +0200 Subject: [PATCH 3/5] chore: Use objc2-foundation's types and methods --- Cargo.toml | 13 +- src/corebluetooth/central_delegate.rs | 180 ++++++++++------------ src/corebluetooth/framework.rs | 156 ++++--------------- src/corebluetooth/internal.rs | 48 +++--- src/corebluetooth/utils/core_bluetooth.rs | 16 +- src/corebluetooth/utils/mod.rs | 20 +-- src/corebluetooth/utils/nsstring.rs | 31 ---- 7 files changed, 161 insertions(+), 303 deletions(-) delete mode 100644 src/corebluetooth/utils/nsstring.rs diff --git a/Cargo.toml b/Cargo.toml index 8077af0d..da1c2f50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,18 @@ jni-utils = "0.1.1" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] objc2 = "0.5.1" -objc2-foundation = { version = "0.2.0", features = ["NSArray", "NSData", "NSDictionary", "NSError", "NSString", "NSUUID", "NSValue"] } +objc2-foundation = { version = "0.2.0", features = [ + "block2", + "NSArray", + "NSData", + "NSDictionary", + "NSEnumerator", + "NSError", + "NSObject", + "NSString", + "NSUUID", + "NSValue", +] } libc = "0.2.151" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/src/corebluetooth/central_delegate.rs b/src/corebluetooth/central_delegate.rs index f30d2316..1073091f 100644 --- a/src/corebluetooth/central_delegate.rs +++ b/src/corebluetooth/central_delegate.rs @@ -17,11 +17,9 @@ // according to those terms. use super::{ - framework::{cb, ns}, + framework::cb, utils::{ core_bluetooth::{cbuuid_to_uuid, characteristic_debug, peripheral_debug, service_debug}, - nsdata_to_vec, - nsstring::nsstring_to_string, nsuuid_to_uuid, StrongPtr, }, }; @@ -38,7 +36,6 @@ use std::{ collections::HashMap, fmt::{self, Debug, Formatter}, ops::Deref, - slice, sync::Once, }; use uuid::Uuid; @@ -291,12 +288,9 @@ impl Debug for CentralDelegateEvent { pub mod CentralDelegate { use objc2::runtime::AnyObject; - use objc2_foundation::{NSDictionary, NSString}; + use objc2_foundation::{NSArray, NSData, NSDictionary, NSError, NSNumber, NSObject, NSString}; - use crate::corebluetooth::{ - framework::ns::number_as_i64, - utils::{core_bluetooth::descriptor_debug, id, nil}, - }; + use crate::corebluetooth::utils::{core_bluetooth::descriptor_debug, id}; use super::*; @@ -379,12 +373,11 @@ pub mod CentralDelegate { class!(BtlePlugCentralManagerDelegate) } - fn localized_description(error: id) -> String { - if error == nil { - "".to_string() + fn localized_description(error: Option<&NSError>) -> String { + if let Some(error) = error { + error.localizedDescription().to_string() } else { - let nsstring = unsafe { msg_send![error, localizedDescription] }; - nsstring_to_string(nsstring).unwrap_or_else(|| "".to_string()) + "".to_string() } } @@ -425,9 +418,9 @@ pub mod CentralDelegate { fn get_characteristic_value(characteristic: id) -> Vec { trace!("Getting data!"); let value = cb::characteristic_value(characteristic); - let v = nsdata_to_vec(value); + let v = value.map(|value| value.bytes().into()); trace!("BluetoothGATTCharacteristic::get_value -> {:?}", v); - v + v.unwrap_or_default() } //////////////////////////////////////////////////////////////// @@ -461,7 +454,7 @@ pub mod CentralDelegate { ); cb::peripheral_setdelegate(peripheral, delegate); cb::peripheral_discoverservices(peripheral); - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); send_delegate_event( delegate, CentralDelegateEvent::ConnectedDevice { peripheral_uuid }, @@ -479,7 +472,7 @@ pub mod CentralDelegate { "delegate_centralmanager_diddisconnectperipheral_error {}", peripheral_debug(peripheral) ); - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); send_delegate_event( delegate, CentralDelegateEvent::DisconnectedDevice { peripheral_uuid }, @@ -491,12 +484,11 @@ pub mod CentralDelegate { _cmd: Sel, _central: id, peripheral: id, - error: id, + error: Option<&NSError>, ) { trace!("delegate_centralmanager_didfailtoconnectperipheral_error"); - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); - let error_description_ns = ns::error_localizeddescription(error); - let error_description = nsstring_to_string(error_description_ns); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); + let error_description = error.map(|error| error.localizedDescription().to_string()); send_delegate_event( delegate, CentralDelegateEvent::ConnectionFailed { @@ -512,7 +504,7 @@ pub mod CentralDelegate { _central: id, peripheral: id, adv_data: &NSDictionary, - rssi: id, + rssi: &NSNumber, ) { trace!( "delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi {}", @@ -527,19 +519,20 @@ pub mod CentralDelegate { }, ); - let rssi_value = number_as_i64(rssi) as i16; + let rssi_value = rssi.as_i16(); - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); let manufacturer_data = adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_MANUFACTURER_DATA_KEY }); if let Some(manufacturer_data) = manufacturer_data { - // manufacturer_data: NSData - let length = ns::data_length(manufacturer_data); - if length >= 2 { - let bytes = ns::data_bytes(manufacturer_data); - let v = unsafe { slice::from_raw_parts(bytes, length as usize) }; - let (manufacturer_id, manufacturer_data) = v.split_at(2); + // SAFETY: manufacturer_data is `NSData` + let manufacturer_data: *const AnyObject = manufacturer_data; + let manufacturer_data: *const NSData = manufacturer_data.cast(); + let manufacturer_data = unsafe { &*manufacturer_data }; + + if manufacturer_data.len() >= 2 { + let (manufacturer_id, manufacturer_data) = manufacturer_data.bytes().split_at(2); send_delegate_event( delegate, @@ -555,14 +548,15 @@ pub mod CentralDelegate { let service_data = adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_SERVICE_DATA_KEY }); if let Some(service_data) = service_data { - // service_data: [CBUUID, NSData] - let uuids = ns::dictionary_allkeys(service_data); + // SAFETY: service_data is `NSDictionary` + let service_data: *const AnyObject = service_data; + let service_data: *const NSDictionary = service_data.cast(); + let service_data = unsafe { &*service_data }; + let mut result = HashMap::new(); - for i in 0..ns::array_count(uuids) { - let uuid = ns::array_objectatindex(uuids, i); - let data = ns::dictionary_objectforkey(service_data, uuid); - let data = nsdata_to_vec(data); - result.insert(cbuuid_to_uuid(uuid), data); + for uuid in service_data.keys() { + let data = &service_data[uuid]; + result.insert(cbuuid_to_uuid(&**uuid), data.bytes().to_vec()); } send_delegate_event( @@ -577,11 +571,14 @@ pub mod CentralDelegate { let services = adv_data.get(unsafe { cb::ADVERTISEMENT_DATA_SERVICE_UUIDS_KEY }); if let Some(services) = services { - // services: [CBUUID] + // SAFETY: services is `NSArray` + let services: *const AnyObject = services; + let services: *const NSArray = services.cast(); + let services = unsafe { &*services }; + let mut service_uuids = Vec::new(); - for i in 0..ns::array_count(services) { - let uuid = ns::array_objectatindex(services, i); - service_uuids.push(cbuuid_to_uuid(uuid)); + for uuid in services { + service_uuids.push(cbuuid_to_uuid(&**uuid)); } send_delegate_event( @@ -605,30 +602,26 @@ pub mod CentralDelegate { delegate: &mut Object, _cmd: Sel, peripheral: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_diddiscoverservices {} {}", peripheral_debug(peripheral), localized_description(error) ); - if error == nil { - let services = cb::peripheral_services(peripheral); + if error.is_none() { + let services = cb::peripheral_services(peripheral).unwrap_or_default(); let mut service_map = HashMap::new(); - for i in 0..ns::array_count(services) { - // get the service out of the services array - let s = ns::array_objectatindex(services, i); - + for s in services { // go ahead and ask for characteristics and other services - cb::peripheral_discovercharacteristicsforservice(peripheral, s); - cb::peripheral_discoverincludedservicesforservice(peripheral, s); + cb::peripheral_discovercharacteristicsforservice(peripheral, &s); + cb::peripheral_discoverincludedservicesforservice(peripheral, &s); // Create the map entry we'll need to export. - let uuid = cbuuid_to_uuid(cb::attribute_uuid(s)); - let held_service = unsafe { StrongPtr::retain(s).unwrap() }; - service_map.insert(uuid, held_service); + let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*s)); + service_map.insert(uuid, s); } - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); send_delegate_event( delegate, CentralDelegateEvent::DiscoveredServices { @@ -644,7 +637,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, service: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_diddiscoverincludedservicesforservice_error {} {} {}", @@ -652,11 +645,10 @@ pub mod CentralDelegate { service_debug(service), localized_description(error) ); - if error == nil { - let includes = cb::service_includedservices(service); - for i in 0..ns::array_count(includes) { - let s = ns::array_objectatindex(includes, i); - cb::peripheral_discovercharacteristicsforservice(peripheral, s); + if error.is_none() { + let includes = cb::service_includedservices(service).unwrap_or_default(); + for s in includes { + cb::peripheral_discovercharacteristicsforservice(peripheral, &s); } } } @@ -666,7 +658,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, service: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_diddiscovercharacteristicsforservice_error {} {} {}", @@ -674,18 +666,16 @@ pub mod CentralDelegate { service_debug(service), localized_description(error) ); - if error == nil { + if error.is_none() { let mut characteristics = HashMap::new(); - let chars = cb::service_characteristics(service); - for i in 0..ns::array_count(chars) { - let c = ns::array_objectatindex(chars, i); - cb::peripheral_discoverdescriptorsforcharacteristic(peripheral, c); + let chars = cb::service_characteristics(service).unwrap_or_default(); + for c in chars { + cb::peripheral_discoverdescriptorsforcharacteristic(peripheral, &c); // Create the map entry we'll need to export. - let uuid = cbuuid_to_uuid(cb::attribute_uuid(c)); - let held_char = unsafe { StrongPtr::retain(c).unwrap() }; - characteristics.insert(uuid, held_char); + let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*c)); + characteristics.insert(uuid, c); } - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); let service_uuid = cbuuid_to_uuid(cb::attribute_uuid(service)); send_delegate_event( delegate, @@ -703,7 +693,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, characteristic: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error {} {} {}", @@ -711,17 +701,15 @@ pub mod CentralDelegate { characteristic_debug(characteristic), localized_description(error) ); - if error == nil { + if error.is_none() { let mut descriptors = HashMap::new(); - let descs = cb::characteristic_descriptors(characteristic); - for i in 0..ns::array_count(descs) { - let d = ns::array_objectatindex(descs, i); + let descs = cb::characteristic_descriptors(characteristic).unwrap_or_default(); + for d in descs { // Create the map entry we'll need to export. - let uuid = cbuuid_to_uuid(cb::attribute_uuid(d)); - let held_desc = unsafe { StrongPtr::retain(d).unwrap() }; - descriptors.insert(uuid, held_desc); + let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*d)); + descriptors.insert(uuid, d); } - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); let service = cb::characteristic_service(characteristic); let service_uuid = cbuuid_to_uuid(cb::attribute_uuid(service)); let characteristic_uuid = cbuuid_to_uuid(cb::attribute_uuid(characteristic)); @@ -742,7 +730,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, characteristic: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_didupdatevalueforcharacteristic_error {} {} {}", @@ -750,12 +738,12 @@ pub mod CentralDelegate { characteristic_debug(characteristic), localized_description(error) ); - if error == nil { + if error.is_none() { let service = cb::characteristic_service(characteristic); send_delegate_event( delegate, CentralDelegateEvent::CharacteristicNotified { - peripheral_uuid: nsuuid_to_uuid(cb::peer_identifier(peripheral)), + peripheral_uuid: nsuuid_to_uuid(&cb::peer_identifier(peripheral)), service_uuid: cbuuid_to_uuid(cb::attribute_uuid(service)), characteristic_uuid: cbuuid_to_uuid(cb::attribute_uuid(characteristic)), data: get_characteristic_value(characteristic), @@ -770,7 +758,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, characteristic: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_didwritevalueforcharacteristic_error {} {} {}", @@ -778,12 +766,12 @@ pub mod CentralDelegate { characteristic_debug(characteristic), localized_description(error) ); - if error == nil { + if error.is_none() { let service = cb::characteristic_service(characteristic); send_delegate_event( delegate, CentralDelegateEvent::CharacteristicWritten { - peripheral_uuid: nsuuid_to_uuid(cb::peer_identifier(peripheral)), + peripheral_uuid: nsuuid_to_uuid(&cb::peer_identifier(peripheral)), service_uuid: cbuuid_to_uuid(cb::attribute_uuid(service)), characteristic_uuid: cbuuid_to_uuid(cb::attribute_uuid(characteristic)), }, @@ -796,11 +784,11 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, characteristic: id, - _error: id, + _error: Option<&NSError>, ) { trace!("delegate_peripheral_didupdatenotificationstateforcharacteristic_error"); // TODO check for error here - let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let peripheral_uuid = nsuuid_to_uuid(&cb::peer_identifier(peripheral)); let service = cb::characteristic_service(characteristic); let service_uuid = cbuuid_to_uuid(cb::attribute_uuid(service)); let characteristic_uuid = cbuuid_to_uuid(cb::attribute_uuid(characteristic)); @@ -830,13 +818,13 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, _rssi: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_didreadrssi_error {}", peripheral_debug(peripheral) ); - if error == nil {} + if error.is_none() {} } extern "C" fn delegate_peripheral_didupdatevaluefordescriptor_error( @@ -844,7 +832,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, descriptor: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_didupdatevaluefordescriptor_error {} {} {}", @@ -852,13 +840,13 @@ pub mod CentralDelegate { descriptor_debug(descriptor), localized_description(error) ); - if error == nil { + if error.is_none() { let characteristic = cb::descriptor_characteristic(descriptor); let service = cb::characteristic_service(characteristic); send_delegate_event( delegate, CentralDelegateEvent::DescriptorNotified { - peripheral_uuid: nsuuid_to_uuid(cb::peer_identifier(peripheral)), + peripheral_uuid: nsuuid_to_uuid(&cb::peer_identifier(peripheral)), service_uuid: cbuuid_to_uuid(cb::attribute_uuid(service)), characteristic_uuid: cbuuid_to_uuid(cb::attribute_uuid(characteristic)), descriptor_uuid: cbuuid_to_uuid(cb::attribute_uuid(descriptor)), @@ -874,7 +862,7 @@ pub mod CentralDelegate { _cmd: Sel, peripheral: id, descriptor: id, - error: id, + error: Option<&NSError>, ) { trace!( "delegate_peripheral_didwritevaluefordescriptor_error {} {} {}", @@ -882,13 +870,13 @@ pub mod CentralDelegate { descriptor_debug(descriptor), localized_description(error) ); - if error == nil { + if error.is_none() { let characteristic = cb::descriptor_characteristic(descriptor); let service = cb::characteristic_service(characteristic); send_delegate_event( delegate, CentralDelegateEvent::DescriptorWritten { - peripheral_uuid: nsuuid_to_uuid(cb::peer_identifier(peripheral)), + peripheral_uuid: nsuuid_to_uuid(&cb::peer_identifier(peripheral)), service_uuid: cbuuid_to_uuid(cb::attribute_uuid(service)), characteristic_uuid: cbuuid_to_uuid(cb::attribute_uuid(characteristic)), descriptor_uuid: cbuuid_to_uuid(cb::attribute_uuid(descriptor)), diff --git a/src/corebluetooth/framework.rs b/src/corebluetooth/framework.rs index 0a01d777..a9f40c4b 100644 --- a/src/corebluetooth/framework.rs +++ b/src/corebluetooth/framework.rs @@ -19,111 +19,14 @@ use super::utils::{id, nil}; use objc2::encode::{Encode, Encoding}; use objc2::rc::Id; -use objc2::{class, msg_send}; -use objc2_foundation::{NSArray, NSDictionary, NSInteger, NSString, NSUInteger}; -use std::os::raw::{c_char, c_void}; -use std::ptr; - -pub mod ns { - use objc2::runtime::AnyObject; - - use super::*; - - // NSNumber - - pub fn number_withbool(value: bool) -> id { - unsafe { msg_send![class!(NSNumber), numberWithBool: value] } - } - - pub fn number_as_i64(value: id) -> i64 { - unsafe { - let i: NSInteger = msg_send![&*value, integerValue]; - i as i64 - } - } - - // NSArray - - pub fn array_count(nsarray: id /* NSArray* */) -> NSUInteger { - let nsarray: &NSArray = unsafe { &*nsarray.cast() }; - nsarray.count() - } - - pub fn array_objectatindex( - nsarray: id, /* NSArray* */ - index: NSUInteger, - ) -> *mut AnyObject { - let nsarray: &NSArray = unsafe { &*nsarray.cast() }; - unsafe { Id::into_raw(nsarray.objectAtIndex(index)).cast() } - } - - // NSDictionary - - pub fn dictionary_allkeys(nsdict: id /* NSDictionary* */) -> id /* NSArray* */ { - let nsdict: &NSDictionary = unsafe { &*nsdict.cast() }; - unsafe { Id::into_raw(nsdict.allKeys()).cast() } - } - - pub fn dictionary_objectforkey(nsdict: id /* NSDictionary* */, key: id) -> id { - let nsdict: &NSDictionary = unsafe { &*nsdict.cast() }; - match unsafe { nsdict.objectForKey(&*key) } { - Some(obj) => Id::into_raw(obj).cast(), - None => ptr::null_mut(), - } - } - - // NSMutableDictionary : NSDictionary - - pub fn mutabledictionary() -> id { - unsafe { msg_send![class!(NSMutableDictionary), dictionaryWithCapacity: 0usize] } - } - - pub fn mutabledictionary_setobject_forkey(nsmutdict: id, object: id, key: id) { - unsafe { msg_send![nsmutdict, setObject:object forKey:key] } - } - - // NSData - - pub fn data(bytes: &[u8]) -> id /* NSData* */ { - unsafe { - msg_send![class!(NSData), dataWithBytes:bytes.as_ptr() length:bytes.len() as NSUInteger] - } - } - - pub fn data_length(nsdata: id /* NSData* */) -> NSUInteger { - unsafe { msg_send![nsdata, length] } - } - - pub fn data_bytes(nsdata: id) -> *const u8 { - let bytes: *const c_void = unsafe { msg_send![nsdata, bytes] }; - bytes.cast() - } - - // NSUUID - - pub fn uuid_uuidstring(nsuuid: id) -> id /* NSString* */ { - unsafe { - let uuidstring: id = msg_send![nsuuid, UUIDString]; - uuidstring - } - } - - // NSError - - pub fn error_localizeddescription(nserror: id) -> id /* NSString* */ { - unsafe { - let description: id = msg_send![nserror, localizedDescription]; - description - } - } -} +use objc2::runtime::AnyObject; +use objc2::{class, msg_send, msg_send_id}; +use objc2_foundation::{NSArray, NSData, NSDictionary, NSString, NSUInteger, NSUUID}; +use std::ffi::CString; +use std::os::raw::c_char; pub mod cb { - use objc2::msg_send_id; - use objc2::runtime::AnyObject; - use super::*; - use std::ffi::CString; #[allow(non_camel_case_types)] pub enum dispatch_object_s {} @@ -134,7 +37,6 @@ pub mod cb { pub const DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t = 0 as dispatch_queue_attr_t; #[cfg_attr(target_os = "macos", link(name = "AppKit", kind = "framework"))] - #[link(name = "Foundation", kind = "framework")] #[link(name = "CoreBluetooth", kind = "framework")] extern "C" { pub fn dispatch_queue_create( @@ -173,7 +75,7 @@ pub mod cb { pub fn centralmanager_scanforperipheralswithservices_options( cbcentralmanager: id, service_uuids: id, /* NSArray */ - options: id, /* NSDictionary */ + options: &NSDictionary, ) { unsafe { msg_send![cbcentralmanager, scanForPeripheralsWithServices:service_uuids options:options] @@ -218,14 +120,14 @@ pub mod cb { // CBPeer - pub fn peer_identifier(cbpeer: id) -> id /* NSUUID* */ { - unsafe { msg_send![cbpeer, identifier] } + pub fn peer_identifier(cbpeer: id) -> Id { + unsafe { msg_send_id![cbpeer, identifier] } } // CBPeripheral : CBPeer - pub fn peripheral_name(cbperipheral: id) -> id /* NSString* */ { - unsafe { msg_send![cbperipheral, name] } + pub fn peripheral_name(cbperipheral: id) -> Option> { + unsafe { msg_send_id![cbperipheral, name] } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -255,18 +157,19 @@ pub mod cb { pub fn peripheral_discoverincludedservicesforservice( cbperipheral: id, - service: id, /* CBService* */ + service: &AnyObject, /* CBService* */ ) { unsafe { msg_send![cbperipheral, discoverIncludedServices:nil forService:service] } } - pub fn peripheral_services(cbperipheral: id) -> id /* NSArray* */ { - unsafe { msg_send![cbperipheral, services] } + pub fn peripheral_services(cbperipheral: id) -> Option>> /* NSArray* */ + { + unsafe { msg_send_id![cbperipheral, services] } } pub fn peripheral_discovercharacteristicsforservice( cbperipheral: id, - service: id, /* CBService* */ + service: &AnyObject, /* CBService* */ ) { unsafe { msg_send![cbperipheral, discoverCharacteristics:nil forService:service] } } @@ -280,7 +183,7 @@ pub mod cb { pub fn peripheral_writevalue_forcharacteristic( cbperipheral: id, - value: id, /* NSData* */ + value: &NSData, characteristic: id, /* CBCharacteristic* */ write_type: usize, ) { @@ -300,7 +203,7 @@ pub mod cb { pub fn peripheral_discoverdescriptorsforcharacteristic( cbperipheral: id, - characteristic: id, /* CBCharacteristic* */ + characteristic: &AnyObject, /* CBCharacteristic* */ ) { unsafe { msg_send![ @@ -319,7 +222,7 @@ pub mod cb { pub fn peripheral_writevalue_fordescriptor( cbperipheral: id, - value: id, /* NSData* */ + value: &NSData, descriptor: id, /* CBCharacteristic* */ ) { unsafe { msg_send![cbperipheral, writeValue:value forDescriptor:descriptor] } @@ -341,12 +244,14 @@ pub mod cb { unsafe { msg_send![cbservice, isPrimary] } } - pub fn service_includedservices(cbservice: id) -> id /* NSArray* */ { - unsafe { msg_send![cbservice, includedServices] } + pub fn service_includedservices(cbservice: id) -> Option>> /* NSArray* */ + { + unsafe { msg_send_id![cbservice, includedServices] } } - pub fn service_characteristics(cbservice: id) -> id /* NSArray* */ { - unsafe { msg_send![cbservice, characteristics] } + pub fn service_characteristics(cbservice: id) -> Option>> /* NSArray* */ + { + unsafe { msg_send_id![cbservice, characteristics] } } // CBCharacteristic : CBAttribute @@ -355,8 +260,8 @@ pub mod cb { unsafe { msg_send![cbcharacteristic, isNotifying] } } - pub fn characteristic_value(cbcharacteristic: id) -> id /* NSData* */ { - unsafe { msg_send![cbcharacteristic, value] } + pub fn characteristic_value(cbcharacteristic: id) -> Option> { + unsafe { msg_send_id![cbcharacteristic, value] } } pub fn characteristic_properties(cbcharacteristic: id) -> NSUInteger { @@ -367,8 +272,9 @@ pub mod cb { unsafe { msg_send![cbcharacteristic, service] } } - pub fn characteristic_descriptors(cbcharacteristic: id) -> id /* NSArray* */ { - unsafe { msg_send![cbcharacteristic, descriptors] } + pub fn characteristic_descriptors(cbcharacteristic: id) -> Option>> /* NSArray* */ + { + unsafe { msg_send_id![cbcharacteristic, descriptors] } } // CBDescriptor : CBAttribute @@ -389,8 +295,8 @@ pub mod cb { // CBUUID - pub fn uuid_uuidstring(cbuuid: id) -> id /* NSString* */ { - unsafe { msg_send![cbuuid, UUIDString] } + pub fn uuid_uuidstring(cbuuid: id) -> Id { + unsafe { msg_send_id![cbuuid, UUIDString] } } pub fn uuid_uuidwithstring(s: &NSString) -> Id /* CBUUID */ { diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index d6050435..9ce8ffe7 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -10,16 +10,11 @@ use super::{ central_delegate::{CentralDelegate, CentralDelegateEvent}, - framework::{ - cb::{self, CBManagerAuthorization, CBPeripheralState}, - ns, - }, + framework::cb::{self, CBManagerAuthorization, CBPeripheralState}, future::{BtlePlugFuture, BtlePlugFutureStateShared}, utils::{ core_bluetooth::{cbuuid_to_uuid, uuid_to_cbuuid}, - id, nil, - nsstring::nsstring_to_string, - nsuuid_to_uuid, StrongPtr, + id, nil, nsuuid_to_uuid, StrongPtr, }, }; use crate::api::{CharPropFlags, Characteristic, Descriptor, ScanFilter, Service, WriteType}; @@ -30,7 +25,7 @@ use futures::sink::SinkExt; use futures::stream::{Fuse, StreamExt}; use log::{error, trace, warn}; use objc2::rc::Id; -use objc2_foundation::NSArray; +use objc2_foundation::{NSArray, NSData, NSMutableDictionary, NSNumber}; use std::{ collections::{BTreeSet, HashMap, VecDeque}, fmt::{self, Debug, Formatter}, @@ -91,10 +86,11 @@ impl CBCharacteristic { let uuid = cbuuid_to_uuid(cb::attribute_uuid(&*characteristic)); let descriptors_arr = cb::characteristic_descriptors(&*characteristic); let mut descriptors = HashMap::new(); - for i in 0..ns::array_count(descriptors_arr) { - let d = ns::array_objectatindex(descriptors_arr, i); - let descriptor = CBDescriptor::new(unsafe { StrongPtr::retain(d).unwrap() }); - descriptors.insert(descriptor.uuid, descriptor); + if let Some(descriptors_arr) = descriptors_arr { + for d in descriptors_arr { + let descriptor = CBDescriptor::new(d); + descriptors.insert(descriptor.uuid, descriptor); + } } Self { characteristic, @@ -508,12 +504,15 @@ impl CoreBluetoothInternal { } async fn on_discovered_peripheral(&mut self, peripheral: StrongPtr) { - let uuid = nsuuid_to_uuid(cb::peer_identifier(&*peripheral)); - let name = nsstring_to_string(cb::peripheral_name(&*peripheral)); + let uuid = nsuuid_to_uuid(&cb::peer_identifier(&*peripheral)); + let name = cb::peripheral_name(&*peripheral); if self.peripherals.contains_key(&uuid) { if let Some(name) = name { - self.dispatch_event(CoreBluetoothEvent::DeviceUpdated { uuid, name }) - .await; + self.dispatch_event(CoreBluetoothEvent::DeviceUpdated { + uuid, + name: name.to_string(), + }) + .await; } } else { // Create our channels @@ -522,7 +521,7 @@ impl CoreBluetoothInternal { .insert(uuid, CBPeripheral::new(peripheral, event_sender)); self.dispatch_event(CoreBluetoothEvent::DeviceDiscovered { uuid, - name, + name: name.map(|name| name.to_string()), event_receiver, }) .await; @@ -806,7 +805,7 @@ impl CoreBluetoothInternal { trace!("Writing value! With kind {:?}", kind); cb::peripheral_writevalue_forcharacteristic( &*peripheral.peripheral, - ns::data(&data), + &NSData::from_vec(data), &*characteristic.characteristic, match kind { WriteType::WithResponse => 0, @@ -910,7 +909,7 @@ impl CoreBluetoothInternal { trace!("Writing descriptor value!"); cb::peripheral_writevalue_fordescriptor( &*peripheral.peripheral, - ns::data(&data), + &NSData::from_vec(data), &*descriptor.descriptor, ); descriptor.write_future_state.push_front(fut); @@ -1122,16 +1121,17 @@ impl CoreBluetoothInternal { fn start_discovery(&mut self, filter: ScanFilter) { trace!("BluetoothAdapter::start_discovery"); let service_uuids = scan_filter_to_service_uuids(filter); - let options = ns::mutabledictionary(); + let mut options = NSMutableDictionary::new(); // NOTE: If duplicates are not allowed then a peripheral will not show // up again once connected and then disconnected. - ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(true), unsafe { - &***cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY - }); + options.insert_id( + unsafe { cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY }, + Id::into_super(Id::into_super(Id::into_super(NSNumber::new_bool(true)))), + ); cb::centralmanager_scanforperipheralswithservices_options( &*self.manager, service_uuids, - options, + &**options, ); } diff --git a/src/corebluetooth/utils/core_bluetooth.rs b/src/corebluetooth/utils/core_bluetooth.rs index c0a67514..9166bff7 100644 --- a/src/corebluetooth/utils/core_bluetooth.rs +++ b/src/corebluetooth/utils/core_bluetooth.rs @@ -21,8 +21,7 @@ use objc2::runtime::AnyObject; use objc2_foundation::NSString; use uuid::Uuid; -use super::super::framework::{cb, ns}; -use super::nsstring::nsstring_to_string; +use super::super::framework::cb; use super::{id, nil}; /// Convert a CBUUID object to the standard Uuid type. @@ -30,7 +29,7 @@ pub fn cbuuid_to_uuid(cbuuid: id) -> Uuid { // NOTE: CoreBluetooth tends to return uppercase UUID strings, and only 4 // character long if the UUID is short (16 bits). It can also return 8 // character strings if the rest of the UUID matches the generic UUID. - let uuid = nsstring_to_string(cb::uuid_uuidstring(cbuuid)).unwrap(); + let uuid = cb::uuid_uuidstring(cbuuid).to_string(); let long = if uuid.len() == 4 { format!("0000{}-0000-1000-8000-00805f9b34fb", uuid) } else if uuid.len() == 8 { @@ -51,9 +50,8 @@ pub fn peripheral_debug(peripheral: id) -> String { if peripheral == nil { return String::from("nil"); } - let name = nsstring_to_string(cb::peripheral_name(peripheral)); - let uuid = nsstring_to_string(ns::uuid_uuidstring(cb::peer_identifier(peripheral))).unwrap(); - if let Some(name) = name { + let uuid = cb::peer_identifier(peripheral).UUIDString(); + if let Some(name) = cb::peripheral_name(peripheral) { format!("CBPeripheral({}, {})", name, uuid) } else { format!("CBPeripheral({})", uuid) @@ -65,7 +63,7 @@ pub fn service_debug(service: id) -> String { return String::from("nil"); } let uuid = cb::uuid_uuidstring(cb::attribute_uuid(service)); - format!("CBService({})", nsstring_to_string(uuid).unwrap()) + format!("CBService({})", uuid) } pub fn characteristic_debug(characteristic: id) -> String { @@ -73,7 +71,7 @@ pub fn characteristic_debug(characteristic: id) -> String { return String::from("nil"); } let uuid = cb::uuid_uuidstring(cb::attribute_uuid(characteristic)); - format!("CBCharacteristic({})", nsstring_to_string(uuid).unwrap()) + format!("CBCharacteristic({})", uuid) } pub fn descriptor_debug(descriptor: id) -> String { @@ -81,7 +79,7 @@ pub fn descriptor_debug(descriptor: id) -> String { return String::from("nil"); } let uuid = cb::uuid_uuidstring(cb::attribute_uuid(descriptor)); - format!("CBDescriptor({})", nsstring_to_string(uuid).unwrap()) + format!("CBDescriptor({})", uuid) } #[cfg(test)] diff --git a/src/corebluetooth/utils/mod.rs b/src/corebluetooth/utils/mod.rs index 73a227e9..ac2440d2 100644 --- a/src/corebluetooth/utils/mod.rs +++ b/src/corebluetooth/utils/mod.rs @@ -18,27 +18,13 @@ use objc2::rc::Id; use objc2::runtime::AnyObject; -use std::slice; +use objc2_foundation::NSUUID; use uuid::Uuid; -use self::nsstring::nsstring_to_string; -use super::framework::ns; - pub mod core_bluetooth; -pub mod nsstring; - -pub fn nsdata_to_vec(data: id) -> Vec { - let length = ns::data_length(data); - if length == 0 { - return vec![]; - } - let bytes = ns::data_bytes(data); - unsafe { slice::from_raw_parts(bytes, length as usize).to_vec() } -} -pub fn nsuuid_to_uuid(uuid: id) -> Uuid { - let uuid_nsstring = ns::uuid_uuidstring(uuid); - nsstring_to_string(uuid_nsstring).unwrap().parse().unwrap() +pub fn nsuuid_to_uuid(uuid: &NSUUID) -> Uuid { + uuid.UUIDString().to_string().parse().unwrap() } #[allow(non_camel_case_types)] diff --git a/src/corebluetooth/utils/nsstring.rs b/src/corebluetooth/utils/nsstring.rs deleted file mode 100644 index fedcaa1f..00000000 --- a/src/corebluetooth/utils/nsstring.rs +++ /dev/null @@ -1,31 +0,0 @@ -// btleplug Source Code File -// -// Copyright 2020 Nonpolynomial Labs LLC. All rights reserved. -// -// Licensed under the BSD 3-Clause license. See LICENSE file in the project root -// for full license information. -// -// Some portions of this file are taken and/or modified from blurmac -// (https://github.com/servo/devices), using a BSD 3-Clause license under the -// following copyright: -// -// Copyright (c) 2017 Akos Kiss. -// -// Licensed under the BSD 3-Clause License -// . -// This file may not be copied, modified, or distributed except -// according to those terms. - -use objc2_foundation::NSString; - -use super::id; - -/// Convert the given `NSString` to a Rust `String`, or `None` if it is `nil`. -pub fn nsstring_to_string(nsstring: id) -> Option { - let nsstring: *const NSString = nsstring.cast(); - if let Some(nsstring) = unsafe { nsstring.as_ref() } { - Some(nsstring.to_string()) - } else { - None - } -} From 49ff1a59564df96efd65360e2906a682f76ae7db Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 1 May 2024 04:07:09 +0200 Subject: [PATCH 4/5] Remove direct libc dependency --- Cargo.toml | 1 - src/corebluetooth/central_delegate.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da1c2f50..ade3fdb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,6 @@ objc2-foundation = { version = "0.2.0", features = [ "NSUUID", "NSValue", ] } -libc = "0.2.151" [target.'cfg(target_os = "windows")'.dependencies] windows = { version = "0.52.0", features = ["Devices_Bluetooth", "Devices_Bluetooth_GenericAttributeProfile", "Devices_Bluetooth_Advertisement", "Devices_Radios", "Foundation_Collections", "Foundation", "Storage_Streams"] } diff --git a/src/corebluetooth/central_delegate.rs b/src/corebluetooth/central_delegate.rs index 1073091f..e0ae8cd5 100644 --- a/src/corebluetooth/central_delegate.rs +++ b/src/corebluetooth/central_delegate.rs @@ -25,7 +25,6 @@ use super::{ }; use futures::channel::mpsc::{self, Receiver, Sender}; use futures::sink::SinkExt; -use libc::c_void; use log::{error, trace}; use objc2::runtime::{ AnyClass as Class, AnyObject as Object, AnyProtocol as Protocol, ClassBuilder, Sel, @@ -36,6 +35,7 @@ use std::{ collections::HashMap, fmt::{self, Debug, Formatter}, ops::Deref, + os::raw::c_void, sync::Once, }; use uuid::Uuid; From 0d888c2f3e197758d57df44cd4fcc229258e2d57 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 1 May 2024 05:15:53 +0200 Subject: [PATCH 5/5] Support tvOS, watchOS and visionOS --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/platform.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ade3fdb8..06f9d867 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ jni = "0.19.0" once_cell = "1.19.0" jni-utils = "0.1.1" -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] +[target.'cfg(target_vendor = "apple")'.dependencies] objc2 = "0.5.1" objc2-foundation = { version = "0.2.0", features = [ "block2", diff --git a/src/lib.rs b/src/lib.rs index aeb3fae7..f4a6b5cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,7 +94,7 @@ pub mod api; mod bluez; #[cfg(not(target_os = "linux"))] mod common; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(target_vendor = "apple")] mod corebluetooth; #[cfg(target_os = "android")] mod droidplug; diff --git a/src/platform.rs b/src/platform.rs index 13e01c80..f4535519 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -5,7 +5,7 @@ pub use crate::bluez::{ adapter::Adapter, manager::Manager, peripheral::Peripheral, peripheral::PeripheralId, }; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(target_vendor = "apple")] pub use crate::corebluetooth::{ adapter::Adapter, manager::Manager, peripheral::Peripheral, peripheral::PeripheralId, };