kawaiifi 0.2.1

Wi-Fi scanning library for Linux, macOS, and Windows.
Documentation
use deku::{DekuContainerWrite, DekuRead, DekuWrite};
use serde::{Deserialize, Serialize};

use crate::ies::{BitRange, Field, IeId};

#[derive(Debug, Clone, PartialEq, Eq, Hash, DekuRead, DekuWrite, Serialize, Deserialize)]
#[deku(ctx = "len: usize")]
pub struct Tim {
    #[deku(bytes = 1)]
    pub dtim_count: u8,
    #[deku(bytes = 1)]
    pub dtim_period: u8,
    #[deku(cond = "len >= 3")]
    pub bitmap_control: Option<BitmapControl>,
    #[deku(cond = "len >= 4", count = "len.saturating_sub(3)")]
    pub partial_virtual_bitmap: Option<Vec<u8>>,
}

impl Tim {
    pub const NAME: &'static str = "TIM";
    pub const ID: u8 = 5;
    pub const ID_EXT: Option<u8> = None;
    pub(crate) const IE_ID: IeId = IeId::new(Self::ID, Self::ID_EXT);

    pub fn is_dtim(&self) -> bool {
        self.dtim_count == 0
    }

    pub fn summary(&self) -> String {
        format!(
            "DTIM Count: {}, DTIM Period: {}",
            self.dtim_count, self.dtim_period
        )
    }

    pub fn fields(&self) -> Vec<Field> {
        let mut fields = vec![
            Field::builder()
                .title("DTIM Count")
                .value(self.dtim_count)
                .byte(self.dtim_count)
                .build(),
            Field::builder()
                .title("DTIM Period")
                .value(self.dtim_period)
                .byte(self.dtim_period)
                .build(),
        ];

        if let Some(bitmap_control) = self.bitmap_control {
            fields.push(bitmap_control.to_field());
        }

        fields
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DekuRead, DekuWrite, Serialize, Deserialize)]
#[deku(bit_order = "lsb")]
pub struct BitmapControl {
    #[deku(bits = 1)]
    pub traffic_indicator: bool,
    #[deku(bits = 7)]
    pub bitmap_offset: u8,
}

impl BitmapControl {
    pub fn to_field(&self) -> Field {
        let byte = self
            .to_bytes()
            .unwrap_or_default()
            .first()
            .cloned()
            .unwrap_or_default();
        Field::builder()
            .title("Bitmap Control")
            .value("")
            .byte(byte)
            .subfields([
                Field::builder()
                    .title("Traffic Indicator")
                    .value(self.traffic_indicator)
                    .bits(BitRange::from_byte(byte, 0, 1))
                    .build(),
                Field::builder()
                    .title("Bitmap Offset")
                    .value(self.bitmap_offset)
                    .bits(BitRange::from_byte(byte, 1, 7))
                    .build(),
            ])
            .build()
    }
}