1use fdf_sys::*;
9
10use core::marker::PhantomData;
11use core::mem::ManuallyDrop;
12use core::num::NonZero;
13use core::ops::Deref;
14
15use zx::HandleBased;
16pub use zx::{Handle as ZirconHandle, HandleRef as ZirconHandleRef};
17
18pub use fdf_sys::fdf_handle_t;
19
20#[repr(C)]
22#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
23pub struct DriverHandle(NonZero<fdf_handle_t>);
24
25impl DriverHandle {
26 pub unsafe fn new_unchecked(handle: NonZero<fdf_handle_t>) -> Self {
36 Self(handle)
37 }
38
39 pub fn as_handle_ref(&self) -> DriverHandleRef<'_> {
41 DriverHandleRef(ManuallyDrop::new(Self(self.0)), PhantomData)
42 }
43
44 pub unsafe fn get_raw(&self) -> NonZero<fdf_handle_t> {
51 self.0
52 }
53
54 pub fn into_raw(self) -> NonZero<fdf_handle_t> {
58 let handle = self.0;
59 core::mem::forget(self);
61 handle
62 }
63}
64
65impl Drop for DriverHandle {
66 fn drop(&mut self) {
67 unsafe { fdf_handle_close(self.0.get()) };
70 }
71}
72
73#[derive(Debug)]
75pub struct DriverHandleRef<'a>(ManuallyDrop<DriverHandle>, PhantomData<&'a DriverHandle>);
76
77impl<'a> Deref for DriverHandleRef<'a> {
78 type Target = DriverHandle;
79
80 fn deref(&self) -> &Self::Target {
81 &self.0
82 }
83}
84
85#[derive(Debug)]
87pub enum MixedHandleType<Driver, Zircon> {
88 Driver(Driver),
89 Zircon(Zircon),
90}
91
92impl From<MixedHandle> for MixedHandleType<DriverHandle, ZirconHandle> {
93 fn from(value: MixedHandle) -> Self {
94 value.resolve()
95 }
96}
97
98#[derive(Debug)]
101#[repr(C)]
102pub struct MixedHandle(NonZero<zx_handle_t>);
103
104impl MixedHandle {
105 pub unsafe fn from_raw(handle: NonZero<fdf_handle_t>) -> Self {
112 Self(handle)
113 }
114
115 pub unsafe fn try_from_raw(handle: fdf_handle_t) -> Option<Self> {
123 NonZero::new(handle).map(|handle| {
124 unsafe { Self::from_raw(handle) }
126 })
127 }
128
129 pub fn from_zircon_handle(handle: ZirconHandle) -> Option<Self> {
132 if handle.is_invalid() {
133 None
134 } else {
135 Some(Self(unsafe { NonZero::new_unchecked(handle.into_raw()) }))
138 }
139 }
140
141 pub fn is_driver(&self) -> bool {
143 self.0.get() & 0b1 == 0b0
144 }
145
146 pub fn resolve(self) -> MixedHandleType<DriverHandle, ZirconHandle> {
148 let res = if self.is_driver() {
149 MixedHandleType::Driver(DriverHandle(self.0))
150 } else {
151 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
154 };
155 core::mem::forget(self);
158 res
159 }
160
161 pub fn resolve_ref(&self) -> MixedHandleType<DriverHandleRef<'_>, ZirconHandleRef<'_>> {
163 if self.is_driver() {
164 MixedHandleType::Driver(DriverHandleRef(
165 ManuallyDrop::new(DriverHandle(self.0)),
166 PhantomData,
167 ))
168 } else {
169 MixedHandleType::Zircon(unsafe { ZirconHandleRef::from_raw_handle(self.0.get()) })
172 }
173 }
174}
175
176impl From<DriverHandle> for MixedHandle {
177 fn from(value: DriverHandle) -> Self {
178 let handle = value.0;
179 unsafe {
183 core::mem::forget(value);
184 MixedHandle::from_raw(handle)
185 }
186 }
187}
188
189impl Drop for MixedHandle {
190 fn drop(&mut self) {
191 let handle = if self.is_driver() {
192 MixedHandleType::Driver(DriverHandle(self.0))
193 } else {
194 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
197 };
198 drop(handle)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use zx::{Port, Status};
205
206 use super::*;
207
208 fn make_driver_handle() -> DriverHandle {
210 let (mut left, mut right) = Default::default();
211 Status::ok(unsafe { fdf_channel_create(0, &mut left, &mut right) }).unwrap();
212 unsafe { fdf_handle_close(right) };
213
214 DriverHandle(NonZero::new(left).unwrap())
215 }
216
217 #[test]
218 fn handle_sizes() {
219 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<DriverHandle>>());
220 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<MixedHandle>>());
221 }
222
223 #[test]
224 fn driver_handle_roundtrip() {
225 let handle = make_driver_handle();
226 let mixed_handle = unsafe { MixedHandle::from_raw(handle.into_raw()) };
227 assert!(mixed_handle.is_driver());
228
229 let MixedHandleType::Driver(_handle) = mixed_handle.resolve() else {
230 panic!("driver handle did not translate back to a driver handle");
231 };
232 }
233
234 #[test]
235 fn zircon_handle_roundtrip() {
236 let handle = Port::create();
237 let mixed_handle =
238 unsafe { MixedHandle::from_raw(NonZero::new(handle.into_raw()).unwrap()) };
239 assert!(!mixed_handle.is_driver());
240
241 let MixedHandleType::Zircon(_handle) = mixed_handle.resolve() else {
242 panic!("zircon handle did not translate back to a zircon handle");
243 };
244 }
245}