1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
use std::io::Result;
use ffi;
use FromRaw;
/// Rust wrapper for the `udev` struct which represents an opaque libudev context
///
/// Most other `libudev` calls take a `struct udev*` argument, although whether or not this
/// argument is actually used depends on the version of libudev. In more recent versions the
/// context is ignored, therefore it sometimes works to pass a NULL or a invalid pointer for
/// `udev`. However older versions, specifically 215 which shipped with Debian 8, expect this to
/// be a valid `udev` struct. Thus it is not optional.
///
/// `udev` is a ref-counted struct, with references added and removed with `udev_ref` and
/// `udef_unref` respectively. This Rust wrapper takes advantage of that ref counting to implement
/// `Clone` and `Drop`, so callers need not worry about any C-specific resource management.
pub struct Udev {
udev: *mut ffi::udev,
}
impl Clone for Udev {
fn clone(&self) -> Self {
unsafe { Self::from_raw(ffi::udev_ref(self.udev)) }
}
}
impl Drop for Udev {
fn drop(&mut self) {
unsafe { ffi::udev_unref(self.udev) };
}
}
as_ffi!(Udev, udev, ffi::udev, ffi::udev_ref);
impl Udev {
/// Creates a new Udev context.
pub fn new() -> Result<Self> {
let ptr = try_alloc!(unsafe { ffi::udev_new() });
Ok(unsafe { Self::from_raw(ptr) })
}
}
#[cfg(test)]
mod tests {
use super::*;
use AsRaw;
#[test]
fn clone_drop() {
// Exercise clone/drop. We won't be able to catch a bug here that leaks memory, but a
// crash due to the ref count getting out of whack would show up here.
let mut udev = Udev::new().unwrap();
for _ in 0..1000 {
let clone = udev.clone();
assert_eq!(udev.as_raw(), clone.as_raw());
// This will `drop()` what's in `udev`, and transfer ownership from `clone` to `udev`
udev = clone;
}
}
#[test]
fn round_trip_to_raw_pointers() {
// Make sure this can be made into a raw pointer, then back to a Rust type, and still works
let udev = Udev::new().unwrap();
let ptr = udev.into_raw();
let udev = unsafe { Udev::from_raw(ptr) };
assert_eq!(ptr, udev.as_raw());
}
}