1use fdf_sys::*;
9
10use core::marker::PhantomData;
11use core::mem::ManuallyDrop;
12use core::num::NonZero;
13use core::ops::Deref;
14
15use zx::HandleBased;
16use zx::sys::zx_handle_t;
17pub use zx::{Handle as ZirconHandle, HandleRef as ZirconHandleRef};
18
19pub use fdf_sys::fdf_handle_t;
20
21#[repr(C)]
23#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
24pub struct DriverHandle(NonZero<fdf_handle_t>);
25
26impl DriverHandle {
27 pub unsafe fn new_unchecked(handle: NonZero<fdf_handle_t>) -> Self {
37 Self(handle)
38 }
39
40 pub fn as_handle_ref(&self) -> DriverHandleRef<'_> {
42 DriverHandleRef(ManuallyDrop::new(Self(self.0)), PhantomData)
43 }
44
45 pub unsafe fn get_raw(&self) -> NonZero<fdf_handle_t> {
52 self.0
53 }
54
55 pub fn into_raw(self) -> NonZero<fdf_handle_t> {
59 let handle = self.0;
60 core::mem::forget(self);
62 handle
63 }
64}
65
66impl Drop for DriverHandle {
67 fn drop(&mut self) {
68 unsafe { fdf_handle_close(self.0.get()) };
71 }
72}
73
74#[derive(Debug)]
76pub struct DriverHandleRef<'a>(ManuallyDrop<DriverHandle>, PhantomData<&'a DriverHandle>);
77
78impl<'a> Deref for DriverHandleRef<'a> {
79 type Target = DriverHandle;
80
81 fn deref(&self) -> &Self::Target {
82 &self.0
83 }
84}
85
86#[derive(Debug)]
88pub enum MixedHandleType<Driver, Zircon> {
89 Driver(Driver),
91 Zircon(Zircon),
93}
94
95impl From<MixedHandle> for MixedHandleType<DriverHandle, ZirconHandle> {
96 fn from(value: MixedHandle) -> Self {
97 value.resolve()
98 }
99}
100
101#[derive(Debug)]
104#[repr(C)]
105pub struct MixedHandle(NonZero<zx_handle_t>);
106
107impl MixedHandle {
108 pub unsafe fn from_raw(handle: NonZero<fdf_handle_t>) -> Self {
115 Self(handle)
116 }
117
118 pub unsafe fn try_from_raw(handle: fdf_handle_t) -> Option<Self> {
126 NonZero::new(handle).map(|handle| {
127 unsafe { Self::from_raw(handle) }
129 })
130 }
131
132 pub fn from_zircon_handle(handle: ZirconHandle) -> Option<Self> {
135 if handle.is_invalid() {
136 None
137 } else {
138 Some(Self(unsafe { NonZero::new_unchecked(handle.into_raw()) }))
141 }
142 }
143
144 pub fn is_driver(&self) -> bool {
146 self.0.get() & 0b1 == 0b0
147 }
148
149 pub fn resolve(self) -> MixedHandleType<DriverHandle, ZirconHandle> {
151 let res = if self.is_driver() {
152 MixedHandleType::Driver(DriverHandle(self.0))
153 } else {
154 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
157 };
158 core::mem::forget(self);
161 res
162 }
163
164 pub fn resolve_ref(&self) -> MixedHandleType<DriverHandleRef<'_>, ZirconHandleRef<'_>> {
166 if self.is_driver() {
167 MixedHandleType::Driver(DriverHandleRef(
168 ManuallyDrop::new(DriverHandle(self.0)),
169 PhantomData,
170 ))
171 } else {
172 MixedHandleType::Zircon(unsafe { ZirconHandleRef::from_raw_handle(self.0.get()) })
175 }
176 }
177}
178
179impl From<DriverHandle> for MixedHandle {
180 fn from(value: DriverHandle) -> Self {
181 let handle = value.0;
182 unsafe {
186 core::mem::forget(value);
187 MixedHandle::from_raw(handle)
188 }
189 }
190}
191
192impl Drop for MixedHandle {
193 fn drop(&mut self) {
194 let handle = if self.is_driver() {
195 MixedHandleType::Driver(DriverHandle(self.0))
196 } else {
197 MixedHandleType::Zircon(unsafe { ZirconHandle::from_raw(self.0.get()) })
200 };
201 drop(handle)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use zx::{Port, Status};
208
209 use super::*;
210
211 fn make_driver_handle() -> DriverHandle {
213 let (mut left, mut right) = Default::default();
214 Status::ok(unsafe { fdf_channel_create(0, &mut left, &mut right) }).unwrap();
215 unsafe { fdf_handle_close(right) };
216
217 DriverHandle(NonZero::new(left).unwrap())
218 }
219
220 #[test]
221 fn handle_sizes() {
222 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<DriverHandle>>());
223 assert_eq!(size_of::<fdf_handle_t>(), size_of::<Option<MixedHandle>>());
224 }
225
226 #[test]
227 fn driver_handle_roundtrip() {
228 let handle = make_driver_handle();
229 let mixed_handle = unsafe { MixedHandle::from_raw(handle.into_raw()) };
230 assert!(mixed_handle.is_driver());
231
232 let MixedHandleType::Driver(_handle) = mixed_handle.resolve() else {
233 panic!("driver handle did not translate back to a driver handle");
234 };
235 }
236
237 #[test]
238 fn zircon_handle_roundtrip() {
239 let handle = Port::create();
240 let mixed_handle =
241 unsafe { MixedHandle::from_raw(NonZero::new(handle.into_raw()).unwrap()) };
242 assert!(!mixed_handle.is_driver());
243
244 let MixedHandleType::Zircon(_handle) = mixed_handle.resolve() else {
245 panic!("zircon handle did not translate back to a zircon handle");
246 };
247 }
248}