eusb 1.0.5

Rust library for accessing USB devices.
use std::sync::{Arc, Condvar, Mutex};
use std::thread::JoinHandle;
use log::{debug};
use thread_priority::{ThreadBuilderExt, ThreadPriority};
use crate::device::UsbDevice;
use crate::platform::libusb::context::Context;
use crate::platform::*;

pub(crate) struct ManagerCtxImpl {
    ctx: Arc<Context>,
    event: Arc<Mutex<EventControllerCtx>>,
    cond: Arc<Condvar>,
    join: Mutex<Option<JoinHandle<()>>>,
}


impl ManagerCtx for ManagerCtxImpl {
    fn new() -> Self {
        let ctx = Arc::new(Context::new());
        let event = Arc::new(Mutex::new(EventControllerCtx {
            device_count: 0,
            is_exit: false,
        }));
        let cond = Arc::new(Condvar::new());
        let join = work_event(ctx.clone(), event.clone(), cond.clone());

        Self {
            ctx,
            event,
            cond,
            join: Mutex::new(Some(join)),
        }
    }

    fn device_list(&self) -> Result<Vec<UsbDevice>> {
        let ctx = self.ctx.clone();
        let mut d = ctx.device_list()?;
        let mut out = Vec::with_capacity(d.len());
        while let Some(one) = d.pop() {
            let device: DeviceCtxImpl = one.into();
            out.push(device.into());
        }
        Ok(out)
    }

    fn open_device_with_vid_pid(&self, vid: u16, pid: u16) -> Result<UsbDevice> {
        let handle = self.ctx.open_device_with_vid_pid(vid, pid)?;
        let dev = DeviceCtxImpl::from(handle);
        Ok(dev.into())
    }

    #[cfg(unix)]
    fn open_device_with_fd(&self, fd: RawFd) -> Result<UsbDevice> {
        let handle = self.ctx.open_device_with_fd(fd)?;
        let dev = DeviceCtxImpl::from(handle);
        Ok(dev.into())
    }

    fn close(&self) {
        {
            let mut ctx = self.event.lock().unwrap();
            ctx.is_exit = true;
            self.cond.notify_all();
        }
        let mut g = self.join.lock().unwrap();
        if let Some(j) = g.take() {
            let _ = j.join();
        }
    }
}


impl ManagerCtxImpl {

    pub(crate)  fn open_device(&self){
        let mut ctx = self.event.lock().unwrap();
        ctx.device_count+=1;
        debug!("device cnt: {}", ctx.device_count);
        self.cond.notify_all();
    }

    pub(crate)  fn close_device(&self){
        let mut ctx = self.event.lock().unwrap();
        ctx.device_count-=1;
        debug!("device cnt: {}", ctx.device_count);
        self.cond.notify_all();
    }
}

fn work_event(
    ctx: Arc<Context>,
    event: Arc<Mutex<EventControllerCtx>>,
    cond: Arc<Condvar>,
) -> JoinHandle<()> {
    std::thread::Builder::new()
        .name("USB main event".into()).spawn_with_priority(ThreadPriority::Max, move |result| {
        if result.is_err() {
            println!("Set priority result fail: {:?}", result);
        }

        let p = ctx;
        let mut ctx = {
            *event.lock().unwrap()
        };

        while !ctx.is_exit {
            if ctx.device_count > 0 {
                let _ = p.handle_events();
                ctx = *event.lock().unwrap()
            } else {
                let mut g = event.lock().unwrap();
                g = cond.wait(g).unwrap();
                ctx = *g;
            }
        }
        p.exit();
    }).unwrap()
}

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