ble-peripheral-rust 0.2.0

A cross-platform Rust crate for building Bluetooth Low Energy peripherals
Documentation
use crate::gatt::{
    characteristic::Characteristic,
    descriptor::Descriptor,
    properties::{AttributePermission, CharacteristicProperty},
};
use objc2::{rc::Retained, runtime::AnyObject, ClassType};
use objc2_core_bluetooth::{
    CBAttributePermissions, CBCharacteristicProperties, CBDescriptor, CBMutableCharacteristic,
    CBMutableDescriptor,
};
use objc2_foundation::{NSArray, NSData};

use super::mac_extensions::uuid_to_cbuuid;

pub fn parse_characteristic(characteristic: &Characteristic) -> Retained<CBMutableCharacteristic> {
    unsafe {
        let properties = characteristic
            .properties
            .iter()
            .fold(CBCharacteristicProperties::empty(), |acc, property| {
                acc | property.clone().to_cb_property()
            });

        let permissions = characteristic
            .permissions
            .iter()
            .fold(CBAttributePermissions::empty(), |acc, permission| {
                acc | permission.clone().to_attribute_permission()
            });

        let value_data = characteristic
            .value
            .as_ref()
            .map(|value| NSData::from_vec(value.clone()));

        let mutable_char = CBMutableCharacteristic::initWithType_properties_value_permissions(
            CBMutableCharacteristic::alloc(),
            &uuid_to_cbuuid(characteristic.uuid),
            properties,
            value_data.as_ref().map(|data| data as &NSData),
            permissions,
        );

        let descriptors: Retained<NSArray<CBDescriptor>> = NSArray::from_vec(
            characteristic
                .descriptors
                .iter()
                .map(|desc| parse_descriptor(desc))
                .collect(),
        );

        mutable_char.setDescriptors(Some(&descriptors));
        if !descriptors.is_empty() {
            log::debug!("DescriptorAdded");
        }
        return mutable_char;
    }
}

pub fn parse_descriptor(descriptor: &Descriptor) -> Retained<CBDescriptor> {
    unsafe {
        let value_data = descriptor
            .value
            .as_ref()
            .map(|value| NSData::from_vec(value.clone()));

        return Retained::into_super(CBMutableDescriptor::initWithType_value(
            CBMutableDescriptor::alloc(),
            &uuid_to_cbuuid(descriptor.uuid),
            value_data.as_ref().map(|data| data as &AnyObject),
        ));
    }
}

impl CharacteristicProperty {
    fn to_cb_property(self) -> CBCharacteristicProperties {
        return match self {
            CharacteristicProperty::Broadcast => {
                CBCharacteristicProperties::CBCharacteristicPropertyBroadcast
            }
            CharacteristicProperty::Read => {
                CBCharacteristicProperties::CBCharacteristicPropertyRead
            }
            CharacteristicProperty::WriteWithoutResponse => {
                CBCharacteristicProperties::CBCharacteristicPropertyWriteWithoutResponse
            }
            CharacteristicProperty::Write => {
                CBCharacteristicProperties::CBCharacteristicPropertyWrite
            }
            CharacteristicProperty::Notify => {
                CBCharacteristicProperties::CBCharacteristicPropertyNotify
            }
            CharacteristicProperty::NotifyEncryptionRequired => {
                CBCharacteristicProperties::CBCharacteristicPropertyNotifyEncryptionRequired
            }
            CharacteristicProperty::Indicate => {
                CBCharacteristicProperties::CBCharacteristicPropertyIndicate
            }
            CharacteristicProperty::IndicateEncryptionRequired => {
                CBCharacteristicProperties::CBCharacteristicPropertyIndicateEncryptionRequired
            }
            CharacteristicProperty::AuthenticatedSignedWrites => {
                CBCharacteristicProperties::CBCharacteristicPropertyAuthenticatedSignedWrites
            }
            CharacteristicProperty::ExtendedProperties => {
                CBCharacteristicProperties::CBCharacteristicPropertyExtendedProperties
            }
        };
    }
}

impl AttributePermission {
    fn to_attribute_permission(self) -> CBAttributePermissions {
        return match self {
            AttributePermission::Readable => CBAttributePermissions::Readable,
            AttributePermission::Writeable => CBAttributePermissions::Writeable,
            AttributePermission::ReadEncryptionRequired => {
                CBAttributePermissions::ReadEncryptionRequired
            }
            AttributePermission::WriteEncryptionRequired => {
                CBAttributePermissions::WriteEncryptionRequired
            }
        };
    }
}