From 545dfc22566d17e258a691a12d9d5d08a8004e08 Mon Sep 17 00:00:00 2001 From: Aleksandr Krotov Date: Sat, 23 Oct 2021 21:10:40 +0300 Subject: [PATCH] Remove bit-set dependency --- Cargo.toml | 1 - src/bit_set.rs | 158 +++++++++++++++++++++++++++++++++++++++++++ src/device_handle.rs | 4 +- src/lib.rs | 3 +- 4 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 src/bit_set.rs diff --git a/Cargo.toml b/Cargo.toml index 577deec..aece0cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ readme = "README.md" keywords = ["usb", "libusb", "hardware", "bindings"] [dependencies] -bit-set = "0.2.0" libusb-sys = "0.2.3" libc = "0.2" diff --git a/src/bit_set.rs b/src/bit_set.rs new file mode 100644 index 0000000..34596e5 --- /dev/null +++ b/src/bit_set.rs @@ -0,0 +1,158 @@ +type Item = u32; +const ITEM_BITS: usize = Item::BITS as usize; + +#[derive(Clone)] +pub struct BitSet { + nbits: usize, + storage: Vec, +} + +impl<'a> BitSet { + #[inline] + pub fn with_capacity(nbits: usize) -> BitSet { + return BitSet { + nbits, + storage: vec![0 as Item; (nbits + ITEM_BITS - 1) / ITEM_BITS], + }; + } + + #[inline] + pub fn contains(&self, value: usize) -> ::Result { + if value < self.nbits { + Ok(self.storage[value / ITEM_BITS] & (1 as Item) << (value % ITEM_BITS) != 0) + } else { + Err(::Error::Overflow) + } + } + + #[inline] + pub fn insert(&mut self, value: usize) -> ::Result<()> { + if !self.contains(value)? { + self.storage[value / ITEM_BITS] |= (1 as Item) << (value % ITEM_BITS); + } + Ok(()) + } + + #[inline] + pub fn remove(&mut self, value: usize) -> ::Result<()> { + if self.contains(value)? { + self.storage[value / ITEM_BITS] &= !((1 as Item) << (value % ITEM_BITS)); + } + Ok(()) + } + + #[inline] + pub fn iter(&'a self) -> Iter<'a> { + return Iter { + data: &self.storage, + offset: 0, + block: self.storage[0], + }; + } +} + +#[derive(Clone)] +pub struct Iter<'a> { + data: &'a Vec, + offset: usize, + block: Item, +} + +impl<'a> Iterator for Iter<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + loop { + while self.block != 0 { + let bit = self.block.trailing_zeros() as Self::Item; + self.block &= self.block - 1; + return Some(self.offset + bit); + } + + self.offset += ITEM_BITS; + + if self.offset < self.data.len() * ITEM_BITS { + self.block = self.data[self.offset / ITEM_BITS]; + } else { + break; + } + } + + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_checks_capacity() { + let mut set = BitSet::with_capacity(256); + + assert!(matches!(set.contains(123), Ok(false))); + assert!(matches!(set.contains(456), Err(::Error::Overflow))); + + assert!(matches!(set.insert(123), Ok(_))); + assert!(matches!(set.insert(456), Err(::Error::Overflow))); + + assert!(matches!(set.remove(123), Ok(_))); + assert!(matches!(set.remove(456), Err(::Error::Overflow))); + } + + #[test] + fn it_inserts() { + let mut set = BitSet::with_capacity(256); + + assert!(matches!(set.contains(123), Ok(false))); + assert!(matches!(set.insert(123), Ok(()))); + assert!(matches!(set.contains(123), Ok(true))); + } + + #[test] + fn it_inserts_existing() { + let mut set = BitSet::with_capacity(256); + set.insert(123).unwrap(); + + assert!(matches!(set.contains(123), Ok(true))); + assert!(matches!(set.insert(123), Ok(()))); + assert!(matches!(set.contains(123), Ok(true))); + } + + #[test] + fn it_removes() { + let mut set = BitSet::with_capacity(256); + set.insert(123).unwrap(); + + assert!(matches!(set.contains(123), Ok(true))); + assert!(matches!(set.remove(123), Ok(()))); + assert!(matches!(set.contains(123), Ok(false))); + } + + #[test] + fn it_removes_nonexistent() { + let mut set = BitSet::with_capacity(256); + + assert!(matches!(set.contains(123), Ok(false))); + assert!(matches!(set.remove(123), Ok(()))); + assert!(matches!(set.contains(123), Ok(false))); + } + + #[test] + fn it_iterates() { + let mut set = BitSet::with_capacity(256); + + let data: Vec = set.iter().collect(); + assert_eq!(data, []); + + set.insert(1).unwrap(); + set.insert(12).unwrap(); + set.insert(123).unwrap(); + set.insert(255).unwrap(); + set.insert(512).unwrap_err(); + + let data: Vec = set.iter().collect(); + assert_eq!(data, [1, 12, 123, 255]); + } +} diff --git a/src/device_handle.rs b/src/device_handle.rs index eb9c360..2aa5d70 100644 --- a/src/device_handle.rs +++ b/src/device_handle.rs @@ -98,14 +98,14 @@ impl<'a> DeviceHandle<'a> { /// when the device handle goes out of scope. pub fn claim_interface(&mut self, iface: u8) -> ::Result<()> { try_unsafe!(libusb_claim_interface(self.handle, iface as c_int)); - self.interfaces.insert(iface as usize); + self.interfaces.insert(iface as usize)?; Ok(()) } /// Releases a claimed interface. pub fn release_interface(&mut self, iface: u8) -> ::Result<()> { try_unsafe!(libusb_release_interface(self.handle, iface as c_int)); - self.interfaces.remove(&(iface as usize)); + self.interfaces.remove(iface as usize)?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 55cb3b4..07b9348 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ //! This crate provides a safe wrapper around the native `libusb` library. -extern crate bit_set; extern crate libusb_sys as libusb; extern crate libc; @@ -39,3 +38,5 @@ mod config_descriptor; mod interface_descriptor; mod endpoint_descriptor; mod language; + +mod bit_set; \ No newline at end of file