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),
90 Zircon(Zircon),
92}
93
94impl From<MixedHandle> for MixedHandleType<DriverHandle, ZirconHandle> {
95 fn from(value: MixedHandle) -> Self {
96 value.resolve()
97 }
98}
99
100#[derive(Debug)]
103#[repr(C)]
104pub struct MixedHandle(NonZero<zx_handle_t>);
105
106impl MixedHandle {
107 pub unsafe fn from_raw(handle: NonZero<fdf_handle_t>) -> Self {
114 Self(handle)
115 }
116
117 pub unsafe fn try_from_raw(handle: fdf_handle_t) -> Option<Self> {
125 NonZero::new(handle).map(|handle| {
126 unsafe { Self::from_raw(handle) }
128 })
129 }
130
131 pub fn from_zircon_handle(handle: ZirconHandle) -> Option<Self> {
134 if handle.is_invalid() {
135 None
136 } else {
137 Some(Self(unsafe { NonZero::new_unchecked(handle.into_raw()) }))
140 }
141 }
142
143 pub fn is_driver(&self) -> bool {
145 self.0.get() & 0b1 == 0b0
146 }
147
148 pub fn resolve(self) -> MixedHandleType<DriverHandle, ZirconHandle> {
150 let res = if self.is_driver() {
151 MixedHandleType::Driver(DriverHandle(self.0))
152 } else {
153 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
156 };
157 core::mem::forget(self);
160 res
161 }
162
163 pub fn resolve_ref(&self) -> MixedHandleType<DriverHandleRef<'_>, ZirconHandleRef<'_>> {
165 if self.is_driver() {
166 MixedHandleType::Driver(DriverHandleRef(
167 ManuallyDrop::new(DriverHandle(self.0)),
168 PhantomData,
169 ))
170 } else {
171 MixedHandleType::Zircon(unsafe { ZirconHandleRef::from_raw_handle(self.0.get()) })
174 }
175 }
176}
177
178impl From<DriverHandle> for MixedHandle {
179 fn from(value: DriverHandle) -> Self {
180 let handle = value.0;
181 unsafe {
185 core::mem::forget(value);
186 MixedHandle::from_raw(handle)
187 }
188 }
189}
190
191impl Drop for MixedHandle {
192 fn drop(&mut self) {
193 let handle = if self.is_driver() {
194 MixedHandleType::Driver(DriverHandle(self.0))
195 } else {
196 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
199 };
200 drop(handle)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use zx::{Port, Status};
207
208 use super::*;
209
210 fn make_driver_handle() -> DriverHandle {
212 let (mut left, mut right) = Default::default();
213 Status::ok(unsafe { fdf_channel_create(0, &mut left, &mut right) }).unwrap();
214 unsafe { fdf_handle_close(right) };
215
216 DriverHandle(NonZero::new(left).unwrap())
217 }
218
219 #[test]
220 fn handle_sizes() {
221 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<DriverHandle>>());
222 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<MixedHandle>>());
223 }
224
225 #[test]
226 fn driver_handle_roundtrip() {
227 let handle = make_driver_handle();
228 let mixed_handle = unsafe { MixedHandle::from_raw(handle.into_raw()) };
229 assert!(mixed_handle.is_driver());
230
231 let MixedHandleType::Driver(_handle) = mixed_handle.resolve() else {
232 panic!("driver handle did not translate back to a driver handle");
233 };
234 }
235
236 #[test]
237 fn zircon_handle_roundtrip() {
238 let handle = Port::create();
239 let mixed_handle =
240 unsafe { MixedHandle::from_raw(NonZero::new(handle.into_raw()).unwrap()) };
241 assert!(!mixed_handle.is_driver());
242
243 let MixedHandleType::Zircon(_handle) = mixed_handle.resolve() else {
244 panic!("zircon handle did not translate back to a zircon handle");
245 };
246 }
247}