eusb 0.4.2

Rust library for accessing USB devices.
Documentation
#[cfg(unix)]
use std::os::fd::RawFd;
use std::ptr::{null_mut, slice_from_raw_parts};
use std::sync::{Arc, Condvar, Mutex};
use log::{trace};
use libusb_src::*;
use super::super::{CtxManager, ResultFuture};
use super::device::CtxDeviceImpl;
use super::interface::Interface;
use super::ptr::Context;
use crate::error::*;
#[cfg(unix)]
use crate::platform::ptr::DeviceHandle;
use crate::platform::Request;

pub(crate) struct Manager{
    ctx: Context,
    event: Arc<Mutex<EventControllerCtx>>,
    cond:  Arc<Condvar>,
}

impl Manager{
    pub(crate) fn new(mut ctx: Context) ->Result<Self>{
        ctx.init()?;

        let s =
        Self{
            ctx,
            event:Arc::new(Mutex::new(EventControllerCtx{
                device_count: 0,
                is_exit: false,
            })),
            cond: Arc::new(Condvar::new()),
        };

        s.work_event();

        Ok(s)
    }
    fn work_event(&self){
        let cond = self.cond.clone();
        let event = self.event.clone();
        let ptr = self.ctx.clone();

        std::thread::spawn(move || {
            let p = ptr;
            let mut ctx = {
                event.lock().unwrap().clone()
            };

            unsafe {
                while !ctx.is_exit{
                    if ctx.device_count > 0 {
                        libusb_handle_events(p.0);
                        ctx = event.lock().unwrap().clone()
                    }else{
                        let mut g = event.lock().unwrap();
                        g = cond.wait(g).unwrap();
                        ctx = g.clone();
                    }
                }
                libusb_exit(p.0);
                trace!("event_finish");
            }
        });

    }
    pub(crate)  fn open_device(&self){
        let mut ctx = self.event.lock().unwrap();
        (*ctx).device_count+=1;
        self.cond.notify_all();
    }

    pub(crate)  fn close_device(&self){
        let mut ctx = self.event.lock().unwrap();
        (*ctx).device_count-=1;
        self.cond.notify_all();
    }

    fn exit(&self){
        let mut ctx = self.event.lock().unwrap();
        (*ctx).is_exit=true;
        self.cond.notify_all();
    }
}

impl CtxManager<Request, Interface, CtxDeviceImpl> for Manager {
    fn device_list(&self) -> ResultFuture<Vec<CtxDeviceImpl>>{
        let ctx = self.ctx;
        Box::pin(async move {
            let ctx = ctx;
            let list = unsafe {
                let mut devs_raw: *const *mut libusb_device = null_mut();
                let cnt = libusb_get_device_list(ctx.0, &mut devs_raw);
                check_err(cnt as _)?;

                let list = &*slice_from_raw_parts(devs_raw, cnt as _);

                list.into_iter().map(|one|{CtxDeviceImpl::new(*one)}).collect()
            };
            Ok(list)
        })
    }
    #[cfg(unix)]
    fn open_device_with_fd(&self, fd: RawFd) -> Result<CtxDeviceImpl> {
        unsafe {
            let mut handle= null_mut();
            check_err(libusb_wrap_sys_device(self.ctx.0, fd as _, &mut handle))?;
            let dev = libusb_get_device(handle);
            let device = CtxDeviceImpl{
                dev,
                handle: Mutex::new(DeviceHandle(handle)),
                manager: None,
            };
            self.open_device();
            Ok(device)
        }
    }
}

impl Drop for Manager {
    fn drop(&mut self) {
        self.exit();
        trace!("drop manager");
    }
}

#[derive(Clone, Debug, Copy)]
struct EventControllerCtx{
    device_count: usize,
    is_exit: bool,
}