libmtp_rs/
internals.rs

1//! Module to manage some internal functionality of `libmtp` like debug levels and
2//! the supported devices, you won't usually use it.
3
4use bitflags::bitflags;
5use libmtp_sys as ffi;
6use std::ffi::CStr;
7
8use crate::error::Error;
9use crate::Result;
10
11pub(crate) fn maybe_init() {
12    static mut ALREADY_INIT: bool = false;
13    unsafe {
14        if !ALREADY_INIT {
15            ffi::LIBMTP_Init();
16            ALREADY_INIT = true;
17        }
18    }
19}
20
21bitflags! {
22    /// Bitflags to activate different levels of debugging inside `libmtp`, multiple levels
23    /// are activated by using a bitwise or.
24    ///
25    /// ## Example
26    /// ```
27    /// use libmtp_rs::internals::DebugLevel;
28    ///
29    /// let debug_level = DebugLevel::USB | DebugLevel::PTP | DebugLevel::DATA;
30    /// ```
31    pub struct DebugLevel: i32 {
32        const NONE = ffi::LIBMTP_DEBUG_NONE as i32;
33        const PTP = ffi::LIBMTP_DEBUG_PTP as i32;
34        const PLST = ffi::LIBMTP_DEBUG_PLST as i32;
35        const USB = ffi::LIBMTP_DEBUG_USB as i32;
36        const DATA = ffi::LIBMTP_DEBUG_DATA as i32;
37        const ALL = ffi::LIBMTP_DEBUG_ALL as i32;
38    }
39}
40
41/// Set the internal debug level of libmtp (C library) using bitflags.
42///
43/// Note that [`DebugLevel`](struct.DebugLevel.html) isn't an enum but a bitflag, so you can activate
44/// specific parts.
45///
46/// ## Example
47/// ```
48/// use libmtp_rs::internals::{set_debug, DebugLevel};
49///
50/// set_debug(DebugLevel::PTP | DebugLevel::DATA);
51/// ```
52pub fn set_debug(level: DebugLevel) {
53    maybe_init();
54
55    unsafe {
56        ffi::LIBMTP_Set_Debug(level.bits());
57    }
58}
59
60/// Contains information about the devices `libmtp` supports. More information
61/// on [`music-players.h`](https://github.com/libmtp/libmtp/blob/master/src/music-players.h).
62#[derive(Debug, Clone)]
63pub struct DeviceEntry {
64    pub vendor: &'static str,
65    pub vendor_id: u16,
66    pub product: &'static str,
67    pub product_id: u16,
68    pub device_flags: u32,
69}
70
71/// Retrieves the devices `libmtp` claims to support as stated in
72/// [`music-players.h`](https://github.com/libmtp/libmtp/blob/master/src/music-players.h).
73pub fn get_supported_devices() -> Result<Vec<DeviceEntry>> {
74    maybe_init();
75
76    let mut devices_ptr = std::ptr::null_mut();
77    let mut len = 0;
78
79    let res = unsafe { ffi::LIBMTP_Get_Supported_Devices_List(&mut devices_ptr, &mut len) };
80
81    if res != 0 {
82        Err(Error::Unknown)
83    } else {
84        let mut devices = Vec::new();
85        for offset in 0..len as isize {
86            unsafe {
87                let device = &*devices_ptr.offset(offset);
88                let vendor = CStr::from_ptr(device.vendor);
89                let product = CStr::from_ptr(device.product);
90
91                devices.push(DeviceEntry {
92                    vendor: vendor.to_str().expect("Invalid UTF-8 in music-players.h?"),
93                    vendor_id: device.vendor_id,
94                    product: product.to_str().expect("Invalid UTF-8 in music-players.h?"),
95                    product_id: device.product_id,
96                    device_flags: device.device_flags,
97                });
98            }
99        }
100
101        Ok(devices)
102    }
103}