eusb 1.0.5

Rust library for accessing USB devices.
use std::ffi::{c_int, c_uchar};
use std::ptr::slice_from_raw_parts;
use libusb_src::*;
use crate::define::*;
use crate::error::Error;
use crate::platform::libusb::device_handle::DeviceHandle;

pub(crate) mod context;
pub(crate) mod device;
mod errors;
mod device_handle;
pub(crate)mod manager;
mod transfer;
pub(crate) mod endpoint;


pub(crate) unsafe  fn  config_descriptor_convert(raw: *const libusb_config_descriptor, handle: Option<&DeviceHandle>, speed: Speed)->ConfigDescriptor{
    let mut alt_settings = Vec::with_capacity((*raw).bNumInterfaces as _);
    let interface_list = &*slice_from_raw_parts(
        (*raw).interface,
        alt_settings.capacity());
    for desc in interface_list {
        let mut alts = Vec::with_capacity(desc.num_altsetting as _);

        let alts_ptr = &*slice_from_raw_parts(
            desc.altsetting,
            desc.num_altsetting as _
        );
        for interface in alts_ptr {
            let mut endpoints = Vec::with_capacity(interface.bNumEndpoints as _);
            let endpoint_list = &*slice_from_raw_parts(interface.endpoint, endpoints.capacity());
            for endpoint in endpoint_list {
                let direction = if endpoint.bEndpointAddress as u32 & LIBUSB_ENDPOINT_IN as u32 == LIBUSB_ENDPOINT_IN as u32{
                    Direction::In
                } else { Direction::Out };
                let num = endpoint.bEndpointAddress as u32 & LIBUSB_ENDPOINT_ADDRESS_MASK as u32;

                let extra = get_extra(endpoint.extra, endpoint.extra_length);
                let type_int = endpoint.bmAttributes as u32 & LIBUSB_TRANSFER_TYPE_MASK as u32;
                let transfer_type = match type_int as u8 {
                    LIBUSB_TRANSFER_TYPE_ISOCHRONOUS => EndpointTransferType::Isochronous,
                    LIBUSB_TRANSFER_TYPE_INTERRUPT => EndpointTransferType::Interrupt,
                    LIBUSB_TRANSFER_TYPE_BULK => EndpointTransferType::Bulk,
                    LIBUSB_TRANSFER_TYPE_CONTROL => EndpointTransferType::Control,
                    _ => panic!("Transfer type error"),
                };

                let sync_type_int = endpoint.bmAttributes as u32 & LIBUSB_ISO_SYNC_TYPE_MASK as u32;
                let sync_type = match sync_type_int  as u8{
                    LIBUSB_ISO_SYNC_TYPE_NONE => IsoSyncType::None,
                    LIBUSB_ISO_SYNC_TYPE_ASYNC=> IsoSyncType::Async,
                    LIBUSB_ISO_SYNC_TYPE_ADAPTIVE => IsoSyncType::Adaptive,
                    LIBUSB_ISO_SYNC_TYPE_SYNC => IsoSyncType::Sync,
                    _ => panic!("Iso sync type error {}", sync_type_int),
                };

                let usage_type_int = (endpoint.bmAttributes as u32 & LIBUSB_ISO_USAGE_TYPE_MASK as u32) as u8;
                let usage_type = match usage_type_int {
                    LIBUSB_ISO_USAGE_TYPE_DATA => IsoUsageType::Data,
                    LIBUSB_ISO_USAGE_TYPE_FEEDBACK => IsoUsageType::Feedback,
                    LIBUSB_ISO_USAGE_TYPE_IMPLICIT => IsoUsageType::Implicit,
                    _ => IsoUsageType::Unknown(usage_type_int),
                };


                endpoints.push(EndpointDescriptor{
                    num: num as _,
                    direction,
                    transfer_type,
                    sync_type,
                    usage_type,
                    max_packet_size: endpoint.wMaxPacketSize,
                    interval: endpoint.bInterval,
                    refresh: endpoint.bRefresh,
                    synch_address: endpoint.bSynchAddress,
                    extra,
                });
            }
            let extra = get_extra(interface.extra, interface.extra_length);
            let mut interface_string = String::new();

            match handle {
                None => {}
                Some(h) => {
                    if let Ok(s) = h.get_string_descriptor_ascii(interface.iInterface) {interface_string=s}
                }
            }

            alts.push(InterfaceDescriptor{
                num: interface.bInterfaceNumber,
                alt_setting: interface.bAlternateSetting,
                device_class: class_from_lib(interface.bInterfaceClass),
                device_sub_class: class_from_lib(interface.bInterfaceSubClass),
                protocol: class_from_lib(interface.bInterfaceProtocol),
                interface: interface_string,
                endpoints,
                extra
            })
        }


        alt_settings.push(InterfaceAltSettingDescriptor{
            alt_settings: alts,
        })

    }
    let p =  match speed {
        Speed::Unknown => {0}
        Speed::Low => {0}
        Speed::Full => {0}
        Speed::High => {2}
        Speed::Super => {2}
        Speed::SuperPlus => {8}
    } as usize;
    let max_power = p * ((*raw).bMaxPower as usize);
    let extra = get_extra((*raw).extra, (*raw).extra_length);
    let mut configuration = String::new();
    match handle {
        None => {}
        Some(h) => {
            if let Ok(s) = h.get_string_descriptor_ascii((*raw).iConfiguration) {configuration=s}
        }
    }
    ConfigDescriptor{
        value: (*raw).bConfigurationValue,
        interfaces: alt_settings,
        extra,
        max_power,
        configuration,
    }
}

fn get_extra(
    extra: *const c_uchar,
    extra_length: c_int,
)->Vec<u8>{
    if extra_length ==0 {
        return vec![];
    }

    unsafe {
        let  data = &*slice_from_raw_parts(extra, extra_length as usize);
        data.to_vec()
    }
}
pub(crate) fn class_from_lib(class: u8)->DeviceClass{
    match class {
        LIBUSB_CLASS_PER_INTERFACE=> DeviceClass::PerInterface,
        LIBUSB_CLASS_AUDIO => DeviceClass::Audio,
        LIBUSB_CLASS_COMM => DeviceClass::Comm,
        LIBUSB_CLASS_HID => DeviceClass::Hid,
        LIBUSB_CLASS_PHYSICAL => DeviceClass::Physical,
        LIBUSB_CLASS_PRINTER => DeviceClass::Printer,
        LIBUSB_CLASS_IMAGE => DeviceClass::Image,
        LIBUSB_CLASS_MASS_STORAGE => DeviceClass::MassStorage,
        LIBUSB_CLASS_HUB => DeviceClass::Hub,
        LIBUSB_CLASS_DATA => DeviceClass::Data,
        LIBUSB_CLASS_SMART_CARD => DeviceClass::SmartCard,
        LIBUSB_CLASS_CONTENT_SECURITY => DeviceClass::ContentSecurity,
        LIBUSB_CLASS_VIDEO => DeviceClass::Video,
        LIBUSB_CLASS_PERSONAL_HEALTHCARE => DeviceClass::PersonalHealthcare,
        LIBUSB_CLASS_DIAGNOSTIC_DEVICE => DeviceClass::DiagnosticDevice,
        LIBUSB_CLASS_WIRELESS => DeviceClass::Wireless,
        LIBUSB_CLASS_APPLICATION => DeviceClass::Application,
        LIBUSB_CLASS_VENDOR_SPEC => DeviceClass::VendorSpec,
        _ =>DeviceClass::Unknown,
    }
}



pub trait ToLib: Sized {
    fn to_lib(self) -> u8;
}

impl ToLib for Direction {
    fn to_lib(self) -> u8 {
        match self {
            Direction::In { .. } => LIBUSB_ENDPOINT_IN,
            Direction::Out { .. } => LIBUSB_ENDPOINT_OUT,
        }
    }
}

impl ToLib for UsbControlTransferType {
    fn to_lib(self) -> u8 {
        let t: u8 = match self {
            UsbControlTransferType::Standard => LIBUSB_REQUEST_TYPE_STANDARD,
            UsbControlTransferType::Class => LIBUSB_REQUEST_TYPE_CLASS,
            UsbControlTransferType::Vendor => LIBUSB_REQUEST_TYPE_VENDOR,
            UsbControlTransferType::Reserved => LIBUSB_REQUEST_TYPE_RESERVED,
        };
        t
    }
}

impl ToLib for UsbControlRecipient {
    fn to_lib(self) -> u8 {
        let t: u8 = match self {
            UsbControlRecipient::Device => LIBUSB_RECIPIENT_DEVICE,
            UsbControlRecipient::Endpoint => LIBUSB_RECIPIENT_ENDPOINT,
            UsbControlRecipient::Other => LIBUSB_RECIPIENT_OTHER,
            UsbControlRecipient::DefaultInterface
            | UsbControlRecipient::SpecifiedInterface => LIBUSB_RECIPIENT_INTERFACE,
        };
        t
    }
}

pub(crate) fn status_to_result(status: c_int)-> crate::error::Result {
    match status {
        LIBUSB_TRANSFER_COMPLETED => Ok(()),
        LIBUSB_TRANSFER_OVERFLOW => Err(Error::Overflow),
        LIBUSB_TRANSFER_TIMED_OUT => Err(Error::Timeout),
        LIBUSB_TRANSFER_CANCELLED => Err(Error::Cancelled),
        LIBUSB_TRANSFER_STALL => Err(Error::NotSupported),
        LIBUSB_TRANSFER_NO_DEVICE => Err(Error::NoDevice),
        _ => Err(Error::Other("Unknown".to_string())),
    }
}