bluest 0.6.9

A cross-platform Bluetooth Low Energy (BLE) library
Documentation
use windows::Devices::Bluetooth::GenericAttributeProfile::GattCommunicationStatus;
use windows::Devices::Enumeration::{DevicePairingResultStatus, DeviceUnpairingResultStatus};
use windows::Foundation::IReference;

use crate::error::ErrorKind;
use crate::Result;

impl From<windows::core::Error> for crate::Error {
    fn from(err: windows::core::Error) -> Self {
        crate::Error::new(ErrorKind::Other, Some(Box::new(err)), String::new())
    }
}

struct CommunicationError(GattCommunicationStatus);

impl std::fmt::Debug for CommunicationError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "CommunicationError({})", self)
    }
}

impl std::fmt::Display for CommunicationError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let str = match self.0 {
            GattCommunicationStatus::Success => "success",
            GattCommunicationStatus::AccessDenied => "access denied",
            GattCommunicationStatus::Unreachable => "unreachable",
            GattCommunicationStatus::ProtocolError => "protocol error",
            _ => return write!(f, "unknown ({})", self.0 .0),
        };
        f.write_str(str)
    }
}

impl std::error::Error for CommunicationError {}

fn kind_from_communication_status(
    status: GattCommunicationStatus,
    protocol_error: windows::core::Result<IReference<u8>>,
) -> Result<ErrorKind> {
    match status {
        GattCommunicationStatus::Success => {
            unreachable!("kind_from_communication_status must not be called with GattCommunicationStatus::Success")
        }
        GattCommunicationStatus::AccessDenied => Ok(ErrorKind::NotAuthorized),
        GattCommunicationStatus::Unreachable => Ok(ErrorKind::NotConnected),
        GattCommunicationStatus::ProtocolError => Ok(ErrorKind::Protocol(protocol_error?.Value()?.into())),
        _ => Ok(ErrorKind::Other),
    }
}

pub(super) fn check_communication_status(
    status: GattCommunicationStatus,
    protocol_error: windows::core::Result<IReference<u8>>,
    message: &str,
) -> Result<()> {
    use crate::Error;
    match status {
        GattCommunicationStatus::Success => Ok(()),
        _ => Err(Error::new(
            kind_from_communication_status(status, protocol_error)?,
            Some(Box::new(CommunicationError(status))),
            message,
        )),
    }
}

struct PairingError(DevicePairingResultStatus);

impl std::fmt::Debug for PairingError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "PairingError({})", self)
    }
}

impl std::fmt::Display for PairingError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let str = match self.0 {
            DevicePairingResultStatus::Paired => "paired",
            DevicePairingResultStatus::AlreadyPaired => "already paired",
            DevicePairingResultStatus::NotReadyToPair => "not ready to pair",
            DevicePairingResultStatus::NotPaired => "not paired",
            DevicePairingResultStatus::ConnectionRejected => "connection rejected",
            DevicePairingResultStatus::TooManyConnections => "too many connections",
            DevicePairingResultStatus::HardwareFailure => "hardware failure",
            DevicePairingResultStatus::AuthenticationTimeout => "authentication timeout",
            DevicePairingResultStatus::AuthenticationNotAllowed => "authentication not allowed",
            DevicePairingResultStatus::AuthenticationFailure => "authentication failure",
            DevicePairingResultStatus::NoSupportedProfiles => "no supported profiles",
            DevicePairingResultStatus::ProtectionLevelCouldNotBeMet => "protection level could not be met",
            DevicePairingResultStatus::AccessDenied => "access denied",
            DevicePairingResultStatus::InvalidCeremonyData => "invalid ceremony data",
            DevicePairingResultStatus::PairingCanceled => "pairing canceled",
            DevicePairingResultStatus::OperationAlreadyInProgress => "operation already in progress",
            DevicePairingResultStatus::RequiredHandlerNotRegistered => "required handler not registered",
            DevicePairingResultStatus::RejectedByHandler => "rejected by handler",
            DevicePairingResultStatus::RemoteDeviceHasAssociation => "remote device has association",
            DevicePairingResultStatus::Failed => "failed",
            _ => return write!(f, "unknown ({})", self.0 .0),
        };
        f.write_str(str)
    }
}

fn kind_from_pairing_status(status: DevicePairingResultStatus) -> ErrorKind {
    match status {
        DevicePairingResultStatus::NotReadyToPair => ErrorKind::NotReady,
        DevicePairingResultStatus::AuthenticationTimeout => ErrorKind::Timeout,
        DevicePairingResultStatus::AuthenticationNotAllowed | DevicePairingResultStatus::AccessDenied => {
            ErrorKind::NotAuthorized
        }
        DevicePairingResultStatus::ConnectionRejected | DevicePairingResultStatus::TooManyConnections => {
            ErrorKind::ConnectionFailed
        }
        DevicePairingResultStatus::NotPaired
        | DevicePairingResultStatus::HardwareFailure
        | DevicePairingResultStatus::AuthenticationFailure
        | DevicePairingResultStatus::NoSupportedProfiles
        | DevicePairingResultStatus::ProtectionLevelCouldNotBeMet
        | DevicePairingResultStatus::InvalidCeremonyData
        | DevicePairingResultStatus::PairingCanceled
        | DevicePairingResultStatus::OperationAlreadyInProgress
        | DevicePairingResultStatus::RequiredHandlerNotRegistered
        | DevicePairingResultStatus::RejectedByHandler
        | DevicePairingResultStatus::RemoteDeviceHasAssociation
        | DevicePairingResultStatus::Failed => ErrorKind::Other,
        _ => ErrorKind::Other,
    }
}

impl std::error::Error for PairingError {}

pub(super) fn check_pairing_status(status: DevicePairingResultStatus) -> Result<()> {
    match status {
        DevicePairingResultStatus::Paired | DevicePairingResultStatus::AlreadyPaired => Ok(()),
        _ => Err(crate::Error::new(
            kind_from_pairing_status(status),
            Some(Box::new(PairingError(status))),
            String::new(),
        )),
    }
}

struct UnpairingError(DeviceUnpairingResultStatus);

impl std::fmt::Debug for UnpairingError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "UnpairingError({})", self)
    }
}

impl std::fmt::Display for UnpairingError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let str = match self.0 {
            DeviceUnpairingResultStatus::Unpaired => "unpaired",
            DeviceUnpairingResultStatus::AlreadyUnpaired => "already unpaired",
            DeviceUnpairingResultStatus::OperationAlreadyInProgress => "operation already in progress",
            DeviceUnpairingResultStatus::AccessDenied => "access denied",
            DeviceUnpairingResultStatus::Failed => "failed",
            _ => return write!(f, "unknown ({})", self.0 .0),
        };
        f.write_str(str)
    }
}

fn kind_from_unpairing_status(status: DeviceUnpairingResultStatus) -> ErrorKind {
    match status {
        DeviceUnpairingResultStatus::AccessDenied => ErrorKind::NotAuthorized,
        DeviceUnpairingResultStatus::OperationAlreadyInProgress | DeviceUnpairingResultStatus::Failed => {
            ErrorKind::Other
        }
        _ => ErrorKind::Other,
    }
}

impl std::error::Error for UnpairingError {}

pub(super) fn check_unpairing_status(status: DeviceUnpairingResultStatus) -> Result<()> {
    match status {
        DeviceUnpairingResultStatus::Unpaired | DeviceUnpairingResultStatus::AlreadyUnpaired => Ok(()),
        _ => Err(crate::Error::new(
            kind_from_unpairing_status(status),
            Some(Box::new(UnpairingError(status))),
            String::new(),
        )),
    }
}