btle 0.1.4

Lightweight Bluetooth Low Energy Drivers. WIP and very not stable yet!! Designed for https://github.com/AndrewGi/BluetoothMeshRust
Documentation
//! LE [`AdvertisingReport`] and [`ReportInfo`] types.
use crate::bytes::Storage;
use crate::hci::le::{MetaEvent, MetaEventCode};
use crate::le::advertisement::{RawAdvertisement, StaticAdvBuffer, MAX_ADV_LEN};
use crate::le::report::{AddressType, EventType, NumReports, ReportInfo};
use crate::{BTAddress, PackError, BT_ADDRESS_LEN, RSSI};
use core::convert::TryFrom;

#[derive(Copy, Clone, Debug)]
pub struct AdvertisingReport<T: AsRef<[ReportInfo<B>]>, B: AsRef<[u8]> = StaticAdvBuffer> {
    pub reports: T,
    _marker: core::marker::PhantomData<B>,
}
impl<T: AsRef<[ReportInfo<B>]>, B: AsRef<[u8]> + Clone> IntoIterator for AdvertisingReport<T, B> {
    type Item = ReportInfo<B>;
    type IntoIter = AdvertisingReportIter<T, B>;

    fn into_iter(self) -> Self::IntoIter {
        AdvertisingReportIter::new(self)
    }
}
impl<T: AsRef<[ReportInfo<B>]>, B: AsRef<[u8]>> AdvertisingReport<T, B> {
    pub const SUBEVENT_CODE: MetaEventCode = MetaEventCode::AdvertisingReport;
    pub fn new(reports: T) -> Self {
        Self {
            reports,
            _marker: core::marker::PhantomData,
        }
    }
    pub fn byte_len(&self) -> usize {
        self.reports
            .as_ref()
            .iter()
            .fold(0usize, |size, report| size + report.byte_len())
            + 1
    }
}

impl<T: Storage<ReportInfo<B>>, B: Storage<u8> + Default + Copy> MetaEvent
    for AdvertisingReport<T, B>
{
    const META_CODE: MetaEventCode = Self::SUBEVENT_CODE;

    fn meta_byte_len(&self) -> usize {
        AdvertisingReport::byte_len(self)
    }

    fn meta_unpack_from(buf: &[u8]) -> Result<Self, PackError>
    where
        Self: Sized,
    {
        let num_reports = NumReports::try_from(*buf.get(0).ok_or(PackError::BadLength {
            expected: 1,
            got: 0,
        })?)
        .map_err(|_| PackError::bad_index(0))?;
        let reports_len = usize::from(u8::from(num_reports));
        let mut out = AdvertisingReport::new(T::with_size(reports_len));
        let mut total_data_len = 0usize;
        for i in 0..reports_len {
            let event_type_index = i + 1;
            let address_type_index = event_type_index + reports_len;
            let address_index = address_type_index + reports_len;
            let data_len_index = address_index + BT_ADDRESS_LEN * reports_len;
            let data_index = data_len_index + total_data_len;
            let event_type = match buf.get(event_type_index).map(|e| EventType::try_from(*e)) {
                Some(Ok(t)) => t,
                _ => return Err(PackError::bad_index(event_type_index)),
            };
            let address_type = match buf
                .get(address_type_index)
                .map(|e| AddressType::try_from(*e))
            {
                Some(Ok(t)) => t,
                _ => return Err(PackError::bad_index(address_type_index)),
            };

            let address =
                BTAddress::unpack_from(&buf[address_index..address_index + BT_ADDRESS_LEN])?;
            let data_len = buf
                .get(data_len_index)
                .map(|e| *e)
                .ok_or(PackError::bad_index(data_len_index))?;
            let data_index_end = data_index + 1 + usize::from(data_len);
            if usize::from(data_len) > MAX_ADV_LEN {
                return Err(PackError::bad_index(data_len_index));
            }
            let data = &buf[data_index + 1..data_index_end];
            PackError::expect_length(data_len.into(), data)?;
            out.reports.as_mut()[i] = ReportInfo {
                event_type,
                address_type,
                address,
                data: RawAdvertisement(B::from_slice(data)),
                rssi: None,
            };
            total_data_len += usize::from(data_len);
        }
        for i in 0..reports_len {
            let rssi_index = 1 + (1 + 1 + 1 + BT_ADDRESS_LEN) * reports_len + total_data_len + i;
            out.reports.as_mut()[i].rssi =
                match buf.get(rssi_index).map(|val| RSSI::maybe_rssi(*val as i8)) {
                    Some(Ok(maybe_rssi)) => maybe_rssi,
                    _ => return Err(PackError::bad_index(rssi_index)),
                }
        }
        Ok(out)
    }

    fn meta_pack_into(&self, buf: &mut [u8]) -> Result<(), PackError> {
        let reports = self.reports.as_ref();
        let reports_len = reports.len();
        let num_reports =
            NumReports::try_from(reports_len).map_err(|_| PackError::InvalidFields)?;
        let full = self.byte_len();
        PackError::expect_length(full, buf)?;
        let mut total_data_len = 0usize;
        for i in 0..reports_len {
            let report = &reports[i];
            let data = report.data.as_ref();
            let data_len = data.len();
            if data_len > MAX_ADV_LEN {
                return Err(PackError::InvalidFields);
            }
            let event_type_index = i + 1;
            let address_type_index = event_type_index + reports_len;
            let address_index = address_type_index + reports_len;
            let data_len_index = address_index + BT_ADDRESS_LEN * reports_len;
            let data_index = data_len_index + total_data_len;
            let data_index_end = data_index + usize::from(data_len);
            buf[event_type_index] = report.event_type.into();
            buf[address_type_index] = report.address_type.into();
            report
                .address
                .pack_into(&mut buf[address_type_index..address_type_index + BT_ADDRESS_LEN])?;
            buf[data_index..data_index_end].copy_from_slice(data);
            total_data_len += data_len;
        }
        for i in 0..reports_len {
            let rssi_index = 1 + (1 + 1 + 1 + BT_ADDRESS_LEN) * reports_len + total_data_len + i;
            buf[rssi_index] = reports[i]
                .rssi
                .map(i8::from)
                .unwrap_or(RSSI::UNSUPPORTED_RSSI) as u8;
        }
        buf[0] = num_reports.into();
        Ok(())
    }
}

pub struct AdvertisingReportIter<Buf: AsRef<[ReportInfo<ReportBuf>]>, ReportBuf: AsRef<[u8]>> {
    pub report: AdvertisingReport<Buf, ReportBuf>,
    pub index: usize,
    _marker: core::marker::PhantomData<ReportBuf>,
}
impl<Buf: AsRef<[ReportInfo<ReportBuf>]>, ReportBuf: AsRef<[u8]>>
    AdvertisingReportIter<Buf, ReportBuf>
{
    pub fn new(report: AdvertisingReport<Buf, ReportBuf>) -> Self {
        AdvertisingReportIter {
            report,
            index: 0,
            _marker: core::marker::PhantomData,
        }
    }
}
impl<Buf: AsRef<[ReportInfo<ReportBuf>]>, ReportBuf: AsRef<[u8]> + Clone> Iterator
    for AdvertisingReportIter<Buf, ReportBuf>
{
    type Item = ReportInfo<ReportBuf>;

    fn next(&mut self) -> Option<Self::Item> {
        let report = self.report.reports.as_ref().get(self.index)?;
        self.index += 1;
        Some(report.clone())
    }
}