udev/
udev.rs

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