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(ptr: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
34as_ffi!(Udev, udev, ffi::udev, ffi::udev_ref);
35
36impl Udev {
37 /// Creates a new Udev context.
38 pub fn new() -> Result<Self> {
39 let ptr: *mut udev = try_alloc!(unsafe { ffi::udev_new() });
40 Ok(unsafe { Self::from_raw(ptr) })
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47 use AsRaw;
48
49 #[test]
50 fn clone_drop() {
51 // Exercise clone/drop. We won't be able to catch a bug here that leaks memory, but a
52 // crash due to the ref count getting out of whack would show up here.
53 let mut udev = Udev::new().unwrap();
54
55 for _ in 0..1000 {
56 let clone = udev.clone();
57
58 assert_eq!(udev.as_raw(), clone.as_raw());
59
60 // This will `drop()` what's in `udev`, and transfer ownership from `clone` to `udev`
61 udev = clone;
62 }
63 }
64
65 #[test]
66 fn round_trip_to_raw_pointers() {
67 // Make sure this can be made into a raw pointer, then back to a Rust type, and still works
68 let udev = Udev::new().unwrap();
69
70 let ptr = udev.into_raw();
71
72 let udev = unsafe { Udev::from_raw(ptr) };
73
74 assert_eq!(ptr, udev.as_raw());
75 }
76}
77