1 use libc::c_int; 2 3 use std::{mem, slice}; 4 5 use crate::{ 6 context::{GlobalContext, UsbContext}, 7 device::{self, Device}, 8 error, 9 }; 10 use libusb1_sys::*; 11 12 /// A list of detected USB devices. 13 pub struct DeviceList<T: UsbContext> { 14 context: T, 15 list: *const *mut libusb_device, 16 len: usize, 17 } 18 19 impl<T: UsbContext> Drop for DeviceList<T> { 20 /// Frees the device list. drop(&mut self)21 fn drop(&mut self) { 22 unsafe { 23 libusb_free_device_list(self.list, 1); 24 } 25 } 26 } 27 28 impl DeviceList<GlobalContext> { new() -> crate::Result<DeviceList<GlobalContext>>29 pub fn new() -> crate::Result<DeviceList<GlobalContext>> { 30 let mut list = mem::MaybeUninit::<*const *mut libusb_device>::uninit(); 31 32 let n = 33 unsafe { libusb_get_device_list(GlobalContext::default().as_raw(), list.as_mut_ptr()) }; 34 35 if n < 0 { 36 Err(error::from_libusb(n as c_int)) 37 } else { 38 Ok(unsafe { 39 DeviceList { 40 context: Default::default(), 41 list: list.assume_init(), 42 len: n as usize, 43 } 44 }) 45 } 46 } 47 } 48 49 impl<T: UsbContext> DeviceList<T> { new_with_context(context: T) -> crate::Result<DeviceList<T>>50 pub fn new_with_context(context: T) -> crate::Result<DeviceList<T>> { 51 let mut list = mem::MaybeUninit::<*const *mut libusb_device>::uninit(); 52 53 let len = unsafe { libusb_get_device_list(context.as_raw(), list.as_mut_ptr()) }; 54 55 if len < 0 { 56 Err(error::from_libusb(len as c_int)) 57 } else { 58 Ok(unsafe { 59 DeviceList { 60 context, 61 list: list.assume_init(), 62 len: len as usize, 63 } 64 }) 65 } 66 } 67 68 /// Returns the number of devices in the list. len(&self) -> usize69 pub fn len(&self) -> usize { 70 self.len 71 } 72 73 /// Returns true if the list is empty, else returns false. is_empty(&self) -> bool74 pub fn is_empty(&self) -> bool { 75 self.len == 0 76 } 77 78 /// Returns an iterator over the devices in the list. 79 /// 80 /// The iterator yields a sequence of `Device` objects. iter(&self) -> Devices<T>81 pub fn iter(&self) -> Devices<T> { 82 Devices { 83 context: self.context.clone(), 84 devices: unsafe { slice::from_raw_parts(self.list, self.len) }, 85 index: 0, 86 } 87 } 88 } 89 90 /// Iterator over detected USB devices. 91 pub struct Devices<'a, T> { 92 context: T, 93 devices: &'a [*mut libusb_device], 94 index: usize, 95 } 96 97 impl<'a, T: UsbContext> Iterator for Devices<'a, T> { 98 type Item = Device<T>; 99 next(&mut self) -> Option<Device<T>>100 fn next(&mut self) -> Option<Device<T>> { 101 if self.index < self.devices.len() { 102 let device = self.devices[self.index]; 103 104 self.index += 1; 105 Some(unsafe { 106 device::Device::from_libusb( 107 self.context.clone(), 108 std::ptr::NonNull::new_unchecked(device), 109 ) 110 }) 111 } else { 112 None 113 } 114 } 115 size_hint(&self) -> (usize, Option<usize>)116 fn size_hint(&self) -> (usize, Option<usize>) { 117 let remaining = self.devices.len() - self.index; 118 (remaining, Some(remaining)) 119 } 120 } 121