use std::ffi::{CString, OsStr};
use std::io::Result;
use std::marker::PhantomData;
use std::os::unix::ffi::OsStrExt;
use libc::c_char;
use ffi;
use list::EntryList;
use FromRaw;
pub struct Hwdb {
hwdb: *mut ffi::udev_hwdb,
}
impl Clone for Hwdb {
fn clone(&self) -> Self {
unsafe { Self::from_raw(ffi::udev_hwdb_ref(self.hwdb)) }
}
}
impl Drop for Hwdb {
fn drop(&mut self) {
unsafe { ffi::udev_hwdb_unref(self.hwdb) };
}
}
as_ffi!(Hwdb, hwdb, ffi::udev_hwdb, ffi::udev_hwdb_ref);
impl Hwdb {
pub fn new() -> Result<Self> {
let junk: *mut ffi::udev = 0x41414141_41414141 as *mut ffi::udev;
let ptr = try_alloc!(unsafe { ffi::udev_hwdb_new(junk) });
Ok(unsafe { Self::from_raw(ptr) })
}
pub fn query<S: AsRef<OsStr>>(&self, modalias: S) -> EntryList<Hwdb> {
let modalias = CString::new(modalias.as_ref().as_bytes())
.expect("query() called with malformed modalias string");
EntryList {
entry: unsafe {
ffi::udev_hwdb_get_properties_list_entry(
self.hwdb,
modalias.as_ptr() as *const c_char,
0,
)
},
phantom: PhantomData,
}
}
pub fn query_one<S: AsRef<OsStr>>(&self, modalias: S, name: S) -> Option<&OsStr> {
self.query(modalias)
.find(|e| e.name == name.as_ref())
.map(|e| e.value.unwrap_or_else(|| OsStr::new("")))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_query() {
let hwdb = Hwdb::new().unwrap();
let results: Vec<_> = hwdb.query("usb:v1D6Bp0001").collect();
assert!(results.len() >= 2);
assert!(results.iter().any(|e| e.name == "ID_VENDOR_FROM_DATABASE"));
assert!(results.iter().any(|e| e.name == "ID_MODEL_FROM_DATABASE"));
assert!(results
.iter()
.any(|e| e.value.unwrap_or(OsStr::new("")) == "Linux Foundation"));
assert!(results
.iter()
.any(|e| e.value.unwrap_or(OsStr::new("")) == "1.1 root hub"));
}
#[test]
fn test_query_one() {
let hwdb = Hwdb::new().unwrap();
let value = hwdb
.query_one("usb:v1D6Bp0001", "ID_MODEL_FROM_DATABASE")
.unwrap();
assert_eq!(value, "1.1 root hub");
}
}