use crate::{Context, Device, Error, Result};
use libc::c_int;
use libusb1_sys as ffi;
use std::{
ptr::{self, NonNull},
slice,
};
pub struct DeviceList {
ctx: Context,
devs: &'static [*mut ffi::libusb_device],
}
impl Drop for DeviceList {
fn drop(&mut self) {
unsafe {
ffi::libusb_free_device_list(self.devs.as_ptr(), 1);
}
}
}
impl DeviceList {
pub fn new() -> Result<Self> {
Self::new_with_context(Context::default())
}
pub fn new_with_context(ctx: Context) -> Result<Self> {
let mut list: *const *mut ffi::libusb_device = ptr::null();
let len = unsafe { ffi::libusb_get_device_list(ctx.as_raw(), &mut list) };
if len < 0 {
return Err(Error::from(len as c_int));
}
if list.is_null() {
return Err(Error::NotFound);
}
let devs = unsafe { slice::from_raw_parts(list, len as usize) };
Ok(DeviceList { ctx, devs })
}
pub fn context(&self) -> Context {
self.ctx.clone()
}
pub fn len(&self) -> usize {
self.devs.len()
}
pub fn is_empty(&self) -> bool {
self.devs.is_empty()
}
pub fn get(&self, idx: usize) -> Option<Device> {
if idx >= self.devs.len() {
return None;
}
let dev = self.devs[idx];
Some(unsafe { Device::from_libusb(self.context(), NonNull::new_unchecked(dev)) })
}
pub fn iter(&self) -> Devices {
Devices { list: self, idx: 0 }
}
pub fn into_vec(self) -> Vec<Device> {
self.iter().collect()
}
}
pub struct Devices<'a> {
list: &'a DeviceList,
idx: usize,
}
impl<'a> Iterator for Devices<'a> {
type Item = Device;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.list.len() {
let dev = self.list.get(self.idx);
self.idx += 1;
dev
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.list.devs.len() - self.idx;
(remaining, Some(remaining))
}
}
impl IntoIterator for DeviceList {
type Item = Device;
type IntoIter = DeviceListIterator;
fn into_iter(self) -> Self::IntoIter {
DeviceListIterator { list: self, idx: 0 }
}
}
pub struct DeviceListIterator {
list: DeviceList,
idx: usize,
}
impl Iterator for DeviceListIterator {
type Item = Device;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.list.len() {
let dev = self.list.get(self.idx);
self.idx += 1;
dev
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.list.devs.len() - self.idx;
(remaining, Some(remaining))
}
}