eusb 1.0.5

Rust library for accessing USB devices.
use std::ffi::c_void;
use std::ptr::{null_mut, slice_from_raw_parts_mut};
use std::time::Duration;

use log::trace;

use libusb_src::*;

use crate::platform::libusb::status_to_result;

use super::errors::*;

pub(crate) struct Transfer {
    pub ptr: *mut libusb_transfer,
    pub data: Vec<u8>,
}

unsafe impl Sync for Transfer {}

unsafe impl Send for Transfer {}

pub(crate) enum TransferDirection {
    Out { data: Vec<u8> },
    In { len: usize },
}

#[allow(unused)]
impl Transfer {
    pub fn new(iso_packets: i32, size: usize) -> Self {
        unsafe {
            let ptr = libusb_alloc_transfer(iso_packets);
            Self {
                ptr,
                data: vec![0; size],
            }
        }
    }
    pub fn new_with_direction(iso_packets: i32, direction: TransferDirection) -> Self {
        match direction {
            TransferDirection::Out { data } => {
                let mut t = Self::new(iso_packets, data.len());
                t.data.copy_from_slice(&data);
                t
            }
            TransferDirection::In { len } => {
                Self::new(iso_packets, len)
            }
        }
    }

    pub unsafe fn control_transfer(
        callback: libusb_transfer_cb_fn,
        direction: TransferDirection,
        request_type: u8, request: u8, value: u16, index: u16, timeout: Duration,
    ) -> Self {
        let length;
        let mut t = match direction {
            TransferDirection::Out { data } => {
                length = data.len();
                let mut t = Self::new(0, LIBUSB_CONTROL_SETUP_SIZE + length);
                t.data[LIBUSB_CONTROL_SETUP_SIZE..].copy_from_slice(&data);
                t
            }
            TransferDirection::In { len } => {
                length = len;
                Self::new(0, LIBUSB_CONTROL_SETUP_SIZE + len)
            }
        };

        let buffer_ptr = t.data.as_mut_ptr();
        libusb_fill_control_setup(buffer_ptr, request_type, request, value, index, length as _);
        libusb_fill_control_transfer(t.ptr, null_mut(), buffer_ptr, callback, null_mut(), timeout.as_millis() as _);
        t
    }

    pub unsafe fn bulk_transfer(
        mut endpoint: u8,
        callback: libusb_transfer_cb_fn,
        direction: TransferDirection,
        timeout: Duration,
    ) -> Self {
        endpoint = match &direction {
            TransferDirection::Out { .. } => { LIBUSB_ENDPOINT_OUT | endpoint }
            TransferDirection::In { .. } => { LIBUSB_ENDPOINT_IN | endpoint }
        };
        let mut t = Self::new_with_direction(0, direction);


        unsafe {
            let buffer_ptr = t.data.as_mut_ptr();
            libusb_fill_bulk_transfer(t.ptr, null_mut(), endpoint, buffer_ptr, t.data.len() as _, callback, null_mut(), timeout.as_millis() as _);
        }
        t
    }

    pub unsafe fn iso_transfer(
        mut endpoint: u8,
        num_iso_packets: i32,
        callback: libusb_transfer_cb_fn,
        direction: TransferDirection,
        timeout: Duration,
    ) -> Self {
        endpoint = match &direction {
            TransferDirection::Out { .. } => { LIBUSB_ENDPOINT_OUT | endpoint }
            TransferDirection::In { .. } => { LIBUSB_ENDPOINT_IN | endpoint }
        };
        let mut t = Self::new_with_direction(num_iso_packets, direction);
        let length = t.data.len() as i32;

        unsafe {
            let buffer_ptr = t.data.as_mut_ptr();
            libusb_fill_iso_transfer(
                t.ptr,
                null_mut(),
                endpoint,
                buffer_ptr,
                length,
                num_iso_packets,
                callback, null_mut(), timeout.as_millis() as _);

            libusb_set_iso_packet_lengths(t.ptr, (length / num_iso_packets) as _)
        }
        t
    }

    pub fn control_transfer_get_data(&self) -> &[u8] {
        unsafe {
            let p = libusb_control_transfer_get_data(self.ptr);
            let l = (*self.ptr).actual_length as usize;
            &*slice_from_raw_parts_mut(p, l)
        }
    }
    pub unsafe fn set_handle(&mut self, handle: *mut libusb_device_handle) {
        (*self.ptr).dev_handle = handle;
    }
    pub unsafe fn set_callback(&mut self, callback: libusb_transfer_cb_fn) {
        (*self.ptr).callback = callback;
    }
    pub unsafe fn set_user_data(&mut self, user_data: *mut c_void) {
        (*self.ptr).user_data = user_data;
    }

    pub unsafe fn get_user_data(&mut self) -> *mut c_void {
        (*self.ptr).user_data
    }
    pub fn submit(&self) -> Result {
        unsafe {
            check_err(libusb_submit_transfer(self.ptr))?;
            Ok(())
        }
    }
    pub fn actual_length(&self) -> usize {
        unsafe {
            (*self.ptr).actual_length as _
        }
    }
    pub fn cancel(&self) -> Result {
        unsafe {
            check_err(libusb_cancel_transfer(self.ptr))?;
            Ok(())
        }
    }

    pub fn result(&self) -> Result {
        unsafe {
            (*self.ptr).to_result()
        }
    }
}

pub(crate) trait ToResult {
    fn to_result(&self) -> Result;
}


impl ToResult for libusb_transfer {
    fn to_result(&self) -> Result {
        status_to_result(self.status)
    }
}


impl Drop for Transfer {
    fn drop(&mut self) {
        unsafe {
            libusb_free_transfer(self.ptr);
            trace!("transfer free");
        }
    }
}