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