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}