core_bluetooth 0.1.0

Safe API wrapper for Core Bluetooth framework
Documentation
use super::*;
use super::characteristic::{CBCharacteristic, WriteKind};
use super::descriptor::CBDescriptor;
use super::service::CBService;

macro_rules! impl_via_manager {
    ($ctx_ty:ident => $($n:ident ( $ctx:ident ) $code:expr)*) => {
        impl $ctx_ty {
            $(
            pub fn $n(self) {
                extern fn f(ctx: *mut c_void) {
                    unsafe {
                        let $ctx = $ctx_ty::from_ctx(ctx);
                        $code;
                    }
                }
                unsafe {
                    let queue = self.manager.delegate().queue();
                    Command::dispatch(self, queue, f);
                }
            }
            )*
        }
    };
}

macro_rules! impl_via_peripheral {
    ($ctx_ty:ident => $($n:ident ( $ctx:ident ) $code:expr)*) => {
        impl $ctx_ty {
            $(
            pub fn $n(self) {
                extern fn f(ctx: *mut c_void) {
                    unsafe {
                        let $ctx = $ctx_ty::from_ctx(ctx);
                        $code;
                    }
                }
                unsafe {
                    let queue = self.peripheral.delegate().queue();
                    Command::dispatch(self, queue, f);
                }
            }
            )*
        }
    };
}

pub trait Command: 'static + Sized + Send  {
    fn into_ctx(self) -> *mut c_void {
        Box::into_raw(Box::new(self)) as *mut c_void
    }

    unsafe fn from_ctx(v: *mut c_void) -> Self {
        *Box::from_raw(v as *mut Self)
    }

    unsafe fn dispatch(self, queue: *mut Object, f: dispatch_function_t) {
        dispatch_async_f(queue, self.into_ctx(), f);
    }
}

#[repr(transparent)]
pub struct Manager {
    pub(in super) manager: StrongPtr<CBCentralManager>,
}

impl Command for Manager {
    fn into_ctx(self) -> *mut c_void {
        unsafe { mem::transmute(self) }
    }

    unsafe fn from_ctx(v: *mut c_void) -> Self {
        mem::transmute(v)
    }
}

impl_via_manager! { Manager =>
    cancel_scan(ctx) {
        ctx.manager.cancel_scan();
    }
    drop_self(ctx) {
        ctx.manager.drop_self();
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct GetPeripherals {
    pub(in super) manager: StrongPtr<CBCentralManager>,
    pub(in super) uuids: StrongPtr<NSArray>,
    pub(in super) tag: Option<Tag>,
}

impl Command for GetPeripherals {}

impl_via_manager! { GetPeripherals =>
    get_peripherals(ctx) {
        let peripherals = ctx.manager.get_peripherals(*ctx.uuids).unwrap_or_default();
        ctx.manager.delegate().send(CentralEvent::GetPeripheralsResult {
            peripherals,
            tag: ctx.tag,
        });
    }
    get_peripherals_with_services(ctx) {
        let peripherals = ctx.manager.get_peripherals_with_services(*ctx.uuids).unwrap_or_default();
        ctx.manager.delegate().send(CentralEvent::GetPeripheralsWithServicesResult {
            peripherals,
            tag: ctx.tag,
        });
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct CancelConnect {
    pub(in super) manager: StrongPtr<CBCentralManager>,
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
}

impl Command for CancelConnect {}

impl_via_manager! { CancelConnect =>
    cancel_connect(ctx) {
        ctx.manager.cancel_connect(&ctx.peripheral);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct Scan {
    pub(in super) manager: StrongPtr<CBCentralManager>,
    pub(in super) options: ScanOptions,
}

impl Command for Scan {}

impl_via_manager! { Scan =>
    dispatch(ctx) {
        ctx.manager.scan(&ctx.options);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct Connect {
    pub(in super) manager: StrongPtr<CBCentralManager>,
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
}

impl Command for Connect {}

impl_via_manager! { Connect =>
    dispatch(ctx) {
        ctx.manager.connect(&ctx.peripheral);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct DiscoverServices {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) uuids: Option<StrongPtr<NSArray>>,
}

impl Command for DiscoverServices {}

impl_via_peripheral! { DiscoverServices =>
    dispatch(ctx) {
        ctx.peripheral.discover_services(ctx.uuids.as_ref().map(|v| **v));
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct PeripheralServiceUuids {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) service: StrongPtr<CBService>,
    pub(in super) uuids: Option<StrongPtr<NSArray>>,
}

impl Command for PeripheralServiceUuids {}

impl_via_peripheral! { PeripheralServiceUuids =>
    discover_characteristics(ctx) {
        ctx.peripheral.discover_characteristics(*ctx.service, ctx.uuids.as_ref().map(|v| **v));
    }
    discover_included_services(ctx) {
        ctx.peripheral.discover_included_services(*ctx.service, ctx.uuids.as_ref().map(|v| **v));
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct Peripheral {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
}

impl Command for Peripheral {
    fn into_ctx(self) -> *mut c_void {
        unsafe { mem::transmute(self) }
    }

    unsafe fn from_ctx(v: *mut c_void) -> Self {
        mem::transmute(v)
    }
}

impl_via_peripheral! { Peripheral =>
    read_rssi(ctx) {
        ctx.peripheral.read_rssi();
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct PeripheralTag {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) tag: Option<Tag>,
}

impl Command for PeripheralTag {}

impl_via_peripheral! { PeripheralTag =>
    get_max_write_len(ctx) {
        let with_response = ctx.peripheral.max_write_len(WriteKind::WithResponse);
        let without_response = ctx.peripheral.max_write_len(WriteKind::WithoutResponse);
        let max_write_len = MaxWriteLen {
            with_response,
            without_response,
        };
        ctx.peripheral.delegate().send(CentralEvent::GetMaxWriteLenResult {
            max_write_len,
            tag: ctx.tag,
        });
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct Characteristic {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) characteristic: StrongPtr<CBCharacteristic>,
}

impl Command for Characteristic {}

impl_via_peripheral! { Characteristic =>
    discover_descriptors(ctx) {
        ctx.peripheral.discover_descriptors(*ctx.characteristic);
    }
    read(ctx) {
        ctx.peripheral.read_characteristic(*ctx.characteristic);
    }
    subscribe(ctx) {
        ctx.peripheral.set_notify_value(*ctx.characteristic, true);
    }
    unsubscribe(ctx) {
        ctx.peripheral.set_notify_value(*ctx.characteristic, false);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct WriteCharacteristic {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) characteristic: StrongPtr<CBCharacteristic>,
    pub(in super) value: StrongPtr<NSData>,
    pub(in super) kind: WriteKind,
}

impl Command for WriteCharacteristic {}

impl_via_peripheral! { WriteCharacteristic =>
    dispatch(ctx) {
        ctx.peripheral.write_characteristic(*ctx.characteristic, *ctx.value, ctx.kind);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct Descriptor {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) descriptor: StrongPtr<CBDescriptor>,
}

impl Command for Descriptor {}

impl_via_peripheral! { Descriptor =>
    read(ctx) {
        ctx.peripheral.read_descriptor(*ctx.descriptor);
    }
}

///////////////////////////////////////////////////////////////////////////////////

pub struct WriteDescriptor {
    pub(in super) peripheral: StrongPtr<CBPeripheral>,
    pub(in super) descriptor: StrongPtr<CBDescriptor>,
    pub(in super) value: StrongPtr<NSData>,
}

impl Command for WriteDescriptor {}

impl_via_peripheral! { WriteDescriptor =>
    dispatch(ctx) {
        ctx.peripheral.write_descriptor(*ctx.descriptor, *ctx.value);
    }
}