keybinds 0.2.0

Platform&Framework-agnostic key binding (keyboard shortcut) dispatcher, parser, and generator written in Safe Rust.
Documentation
//! Support for [`arbitrary`] crate.
//!
//! This module provides [`Arbitrary`] trait support for several types in keybinds crate.
//!
//! ```
//! use arbitrary::{Arbitrary, Result, Unstructured};
//! use keybinds::{Key, KeyInput, KeySeq, Keybind, Keybinds, Mods};
//!
//! // Actions dispatched by key bindings.
//! #[derive(Arbitrary, Debug)]
//! enum Action {
//!     Hello,
//!     Goodbye,
//! }
//!
//! let raw_data = b"
//!     Hello, the document for arbitrary crate support!
//!     This is the random data input from fuzzer.
//! ";
//! let mut unstructured = Unstructured::new(raw_data);
//!
//! // Generate arbitrary instances of types in keybinds crate
//! let _ = Key::arbitrary(&mut unstructured).unwrap();
//! let _ = Mods::arbitrary(&mut unstructured).unwrap();
//! let _ = KeyInput::arbitrary(&mut unstructured).unwrap();
//! let _ = KeySeq::arbitrary(&mut unstructured).unwrap();
//! let _ = Keybind::<Action>::arbitrary(&mut unstructured).unwrap();
//! let _ = Keybinds::<Action>::arbitrary(&mut unstructured).unwrap();
//! ```
use crate::{KeyInput, KeySeq, Keybinds, Mods};
use arbitrary::{Arbitrary, Result, Unstructured};

// Note: We don't use bitflags crate's `arbitrary` feature because it is quite inefficient.
// Almost all bit patterns generated by `Unstructured` are incorrect and they cause 'Incorrect format'
// error which means generating an arbitrary instance failed.
impl Arbitrary<'_> for Mods {
    fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
        let mut mods = Self::NONE;
        if u.arbitrary()? {
            mods |= Mods::CTRL;
        }
        if u.arbitrary()? {
            mods |= Mods::CMD;
        }
        if u.arbitrary()? {
            mods |= Mods::ALT;
        }
        if u.arbitrary()? {
            mods |= Mods::WIN;
        }
        if u.arbitrary()? {
            mods |= Mods::SHIFT;
        }
        Ok(mods)
    }
}

// Note: We don't use `arbitrary` feature of smallvec trait because it will be removed at smallvec v2.
impl Arbitrary<'_> for KeySeq {
    fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
        u.arbitrary_iter::<KeyInput>()?.collect()
    }
}

// Note: Do not generate arbitrary values for timeout and ongoing key sequence.
impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Keybinds<A> {
    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
        Ok(Self::new(u.arbitrary()?))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Key, Keybind};

    #[test]
    fn arbitrary_values() {
        let raw_data = b"
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
            dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
            ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
            fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
            mollit anim id est laborum.
        ";
        let mut u = Unstructured::new(raw_data);

        let _ = Key::arbitrary(&mut u).unwrap();
        let _ = Mods::arbitrary(&mut u).unwrap();
        let _ = KeyInput::arbitrary(&mut u).unwrap();
        let _ = KeySeq::arbitrary(&mut u).unwrap();
        let _ = Keybind::<()>::arbitrary(&mut u).unwrap();
        let _ = Keybinds::<()>::arbitrary(&mut u).unwrap();
    }
}