1//!
2//! libudev Bindings for Rust
3//!
4
5#![warn(missing_docs)]
6
7extern crate libc;
8pub extern crate libudev_sys as ffi;
9#[cfg(feature = "mio06")]
10extern crate mio06;
11#[cfg(feature = "mio07")]
12extern crate mio07;
13#[cfg(feature = "mio08")]
14extern crate mio08;
15
16pub use device::{Attributes, Device, Properties};
17pub use enumerator::{Devices, Enumerator};
18#[cfg(feature = "hwdb")]
19pub use hwdb::Hwdb;
20pub use list::{Entry, List};
21pub use monitor::{Builder as MonitorBuilder, Event, EventType, Socket as MonitorSocket};
22pub use udev::Udev;
23
24macro_rules! try_alloc {
25 ($exp:expr) => {{
26 let ptr = $exp;
27
28 if ptr.is_null() {
29 return Err(std::io::Error::last_os_error());
30 }
31
32 ptr
33 }};
34}
35
36/// Receive the underlying raw pointer
37pub trait AsRaw<T: 'static> {
38 /// Get a reference of the underlying struct.
39 ///
40 /// The reference count will not be increased.
41 fn as_raw(&self) -> *mut T;
42
43 /// Convert the object into the underlying pointer.
44 ///
45 /// You are responsible for freeing the object.
46 fn into_raw(self) -> *mut T;
47}
48
49/// Receive the underlying raw pointer for types with an associated `udev` struct which must
50/// outlive them.
51pub trait AsRawWithContext<T: 'static> {
52 /// Get a reference of the underlying struct.
53 ///
54 /// The reference count will not be increased.
55 fn as_raw(&self) -> *mut T;
56
57 /// The `udev` context with which this struct was created. This must live at least as long as
58 /// the struct itself or undefined behavior will result.
59 fn udev(&self) -> &Udev;
60
61 /// Convert the object into the raw `udev` pointer and the underlying pointer for this object.
62 ///
63 /// You are responsible for freeing both. You're also responsible for ensuring that the `udev`
64 /// pointer is not freed until after this object's pointer is freed.
65 fn into_raw_with_context(self) -> (*mut ffi::udev, *mut T);
66}
67
68/// Convert from a raw pointer
69pub trait FromRaw<T: 'static> {
70 /// Create an object from a given raw pointer.
71 ///
72 /// The reference count will not be increased, be sure not to free this pointer.
73 ///
74 /// ## Safety
75 ///
76 /// The pointer has to be a valid reference to the expected underlying udev-struct or undefined
77 /// behaviour might occur.
78 unsafe fn from_raw(ptr: *mut T) -> Self;
79}
80
81/// Convert from a raw pointer for types which must be associated with a `Udev` context object.
82pub trait FromRawWithContext<T: 'static> {
83 /// Create an object from a given raw pointer and `udev` context pointer.
84 ///
85 /// The reference count will not be increased, be sure not to free this pointer.
86 ///
87 /// ## Safety
88 ///
89 /// The `udev` pointer must correspond to the `udev` pointer used when `ptr` was created. If
90 /// not memory corruption and undefined behavior will result.
91 ///
92 /// Both the `udev` and `ptr` pointers must be a valid reference to the expected underlying udev-struct or undefined
93 /// behaviour might occur. Do NOT attempt to free either pointer; `udev_unref` and the
94 /// corresponding `*_unref` function for `ptr` will be called automatically when this type is
95 /// dropped.
96 unsafe fn from_raw_with_context(udev: *mut ffi::udev, ptr: *mut T) -> Self;
97}
98
99/// Convert from a raw pointer and the matching context
100macro_rules! as_ffi {
101 ($struct_:ident, $field:ident, $type_:ty, $ref:path) => {
102 as_raw!($struct_, $field, $type_, $ref);
103 from_raw!($struct_, $field, $type_);
104 };
105}
106
107macro_rules! as_ffi_with_context {
108 ($struct_:ident, $field:ident, $type_:ty, $ref:path) => {
109 as_raw_with_context!($struct_, $field, $type_, $ref);
110 from_raw_with_context!($struct_, $field, $type_);
111 };
112}
113
114macro_rules! as_raw {
115 ($struct_:ident, $field:ident, $type_:ty, $ref:path) => {
116 impl $crate::AsRaw<$type_> for $struct_ {
117 fn as_raw(&self) -> *mut $type_ {
118 self.$field
119 }
120
121 fn into_raw(self) -> *mut $type_ {
122 // Note that all `AsRaw` implementations also implement `Drop` which calls the
123 // `_unref` function that correponds to $type_. We can't prevent this from
124 // happening, so we have to add a reference here to ensure the returned pointer
125 // remains allocated for the caller.
126 unsafe { $ref(self.$field) };
127
128 self.$field
129 }
130 }
131 };
132}
133
134macro_rules! from_raw {
135 ($struct_:ident, $field:ident, $type_:ty) => {
136 impl $crate::FromRaw<$type_> for $struct_ {
137 unsafe fn from_raw(t: *mut $type_) -> Self {
138 Self { $field: t }
139 }
140 }
141 };
142}
143
144macro_rules! as_raw_with_context {
145 ($struct_:ident, $field:ident, $type_:ty, $ref:path) => {
146 impl $crate::AsRawWithContext<$type_> for $struct_ {
147 fn as_raw(&self) -> *mut $type_ {
148 self.$field
149 }
150
151 fn udev(&self) -> &Udev {
152 &self.udev
153 }
154
155 fn into_raw_with_context(self) -> (*mut ffi::udev, *mut $type_) {
156 // We can't call `self.udev.into_raw()` here, because that will consume
157 // `self.udev`, which is not possible because every type that implements
158 // `AsRawWithContext` also implements `Drop`. Of course we know that it would be
159 // safe here to just skip the `drop()` on `Udev` and "leak" the `udev` pointer back
160 // to the caller, but the Rust compiler doesn't know that.
161 //
162 // So instead we have to add a new reference to the `udev` pointer before we return
163 // it, because as soon as we leave the scope of this function the `Udev` struct
164 // will be dropped which will call `udev_unref` on it. If there's only once
165 // reference left that will free the pointer and we'll end up returning a dangling
166 // pointer to the caller.
167 //
168 // For much the same reason, we do the same with the pointer of type $type
169 let udev = self.udev.as_raw();
170 unsafe { ffi::udev_ref(udev) };
171
172 unsafe { $ref(self.$field) };
173
174 (udev, self.$field)
175 }
176 }
177 };
178}
179
180macro_rules! from_raw_with_context {
181 ($struct_:ident, $field:ident, $type_:ty) => {
182 impl $crate::FromRawWithContext<$type_> for $struct_ {
183 unsafe fn from_raw_with_context(udev: *mut ffi::udev, t: *mut $type_) -> Self {
184 Self {
185 udev: Udev::from_raw(udev),
186 $field: t,
187 }
188 }
189 }
190 };
191}
192
193mod device;
194mod enumerator;
195#[cfg(feature = "hwdb")]
196mod hwdb;
197mod list;
198mod monitor;
199mod udev;
200mod util;
201