Skip to main content

zx/
handle.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Type-safe bindings for Zircon handles.
6
7use crate::{
8    Koid, MonotonicInstant, Name, ObjectQuery, ObjectType, Port, Property, PropertyQuery, Rights,
9    Signals, Status, Topic, WaitAsyncOpts, WaitItem, ok, sys,
10};
11use std::marker::PhantomData;
12use std::mem::{ManuallyDrop, MaybeUninit};
13use std::num::NonZeroU32;
14use zerocopy::{FromBytes, Immutable, IntoBytes};
15
16/// Tuning constant for Handle::get_info_vec(). pub(crate) to support unit tests.
17pub(crate) const INFO_VEC_SIZE_INITIAL: usize = 16;
18
19/// An owned and valid Zircon
20/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles) to a kernel object.
21///
22/// This type can be interconverted to and from more specific types. Those conversions are not
23/// enforced in the type system; attempting to use them will result in errors returned by the
24/// kernel. These conversions don't change the underlying representation, but do change the type and
25/// what operations are available.
26///
27/// # Lifecycle
28///
29/// This type closes the handle it owns when dropped.
30///
31/// # Layout
32///
33/// `Option<Handle>` is guaranteed to have the same layout and bit patterns as `zx_handle_t`.
34/// Unlike many types in this crate it does not implement `zerocopy` traits because those are not
35/// appropriate for types with real `Drop` implementations.
36#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
37#[repr(transparent)]
38pub struct Handle(NonZeroU32);
39
40// Ensure ABI-compatibility with zx_handle_t with the following static assertions. NonZeroU32 lets
41// Option store the None variant in the all-zeroes bit pattern, which is ZX_HANDLE_INVALID. By
42// banning use of ZX_HANDLE_INVALID inside a Handle, we ensure that Option<Handle> is ABI-compatible
43// with sys::zx_handle_t while providing statically checkable nullability.
44static_assertions::const_assert_eq!(sys::ZX_HANDLE_INVALID, 0);
45static_assertions::assert_eq_size!(Handle, sys::zx_handle_t);
46static_assertions::assert_eq_align!(Handle, sys::zx_handle_t);
47static_assertions::assert_eq_size!(Option<Handle>, sys::zx_handle_t);
48static_assertions::assert_eq_align!(Option<Handle>, sys::zx_handle_t);
49
50impl Handle {
51    /// Take exclusive ownership over a raw handle.
52    ///
53    /// # Safety
54    ///
55    /// `raw` must either be `ZX_HANDLE_INVALID` or be a valid handle present in the current handle
56    /// table that will not be closed by another owner.
57    pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Option<Self> {
58        let inner = NonZeroU32::new(raw)?;
59        debug_assert!(Self::check_raw_valid(raw).is_ok());
60        Some(Self(inner))
61    }
62
63    /// Take exclusive ownership over a raw handle.
64    ///
65    /// # Safety
66    ///
67    /// `raw` must be a valid handle present in the current handle table that will not be closed by
68    /// another owner.
69    pub unsafe fn from_raw_unchecked(raw: sys::zx_handle_t) -> Self {
70        debug_assert!(Self::check_raw_valid(raw).is_ok());
71        // SAFETY: invariant is passed on to our caller.
72        Self(unsafe { NonZeroU32::new_unchecked(raw) })
73    }
74
75    // A program which uses a handle returned from this function for anything other than being
76    // `Drop`ped may be terminated by the kernel.
77    #[doc(hidden)]
78    pub fn poison() -> Self {
79        Self(unsafe { NonZeroU32::new_unchecked(1) })
80    }
81
82    #[doc(hidden)]
83    pub fn is_poison(&self) -> bool {
84        // From https://fuchsia.dev/fuchsia-src/concepts/kernel/handles:
85        //
86        // > The integer value for a handle is any 32-bit number except the value corresponding to
87        // > `ZX_HANDLE_INVALID` which will always have the value of 0. In addition to this, the
88        // > integer value of a valid handle will always have two least significant bits of the
89        // > handle set. The mask representing these bits may be accessed using
90        // > `ZX_HANDLE_FIXED_BITS_MASK`.
91        (self.0.get() & sys::ZX_HANDLE_FIXED_BITS_MASK) != sys::ZX_HANDLE_FIXED_BITS_MASK
92    }
93
94    /// Wraps the
95    /// [zx_handle_check_valid](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_check_valid.md)
96    /// syscall.
97    ///
98    /// Note that this does *not* guarantee that the handle is safe to pass to `Handle::from_raw`
99    /// in cases where another function may close the handle.
100    pub fn check_raw_valid(raw: sys::zx_handle_t) -> Result<(), Status> {
101        // SAFETY: basic FFI call.
102        ok(unsafe { sys::zx_handle_check_valid(raw) })
103    }
104
105    /// Returns the raw handle's integer value.
106    pub const fn raw_handle(&self) -> sys::zx_handle_t {
107        self.0.get()
108    }
109
110    /// Return the raw handle's integer value without closing it when `self` is dropped.
111    pub fn into_raw(self) -> sys::zx_handle_t {
112        let ret = self.0.get();
113        std::mem::forget(self);
114        ret
115    }
116
117    /// Wraps the
118    /// [`zx_handle_duplicate`](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_duplicate)
119    /// syscall.
120    pub fn duplicate(&self, rights: Rights) -> Result<Self, Status> {
121        let mut out = 0;
122        // SAFETY: basic FFI call.
123        let status =
124            unsafe { sys::zx_handle_duplicate(self.raw_handle(), rights.bits(), &mut out) };
125        ok(status)?;
126
127        // SAFETY: zx_handle_duplicate returns a valid handle that this function owns.
128        Ok(unsafe { Self::from_raw_unchecked(out) })
129    }
130
131    /// Wraps the
132    /// [`zx_handle_replace`](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace)
133    /// syscall.
134    pub fn replace(self, rights: Rights) -> Result<Self, Status> {
135        let mut out = 0;
136
137        // SAFETY: basic FFI call.
138        let status = unsafe { sys::zx_handle_replace(self.into_raw(), rights.bits(), &mut out) };
139        ok(status)?;
140
141        // SAFETY: zx_handle_replace gives us a valid owned handle if the call succeeded.
142        unsafe { Ok(Self::from_raw_unchecked(out)) }
143    }
144
145    /// Wraps the [`zx_object_signal`](https://fuchsia.dev/reference/syscalls/object_signal) syscall.
146    pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
147        // SAFETY: basic FFI call.
148        ok(unsafe { sys::zx_object_signal(self.raw_handle(), clear_mask.bits(), set_mask.bits()) })
149    }
150
151    /// Wraps the [`zx_object_wait_one`](https://fuchsia.dev/reference/syscalls/object_wait_one)
152    /// syscall.
153    pub fn wait_one(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
154        let mut pending = Signals::empty().bits();
155        // SAFETY: basic FFI call.
156        let status = unsafe {
157            sys::zx_object_wait_one(
158                self.raw_handle(),
159                signals.bits(),
160                deadline.into_nanos(),
161                &mut pending,
162            )
163        };
164        let signals = Signals::from_bits_truncate(pending);
165        match ok(status) {
166            Ok(()) => WaitResult::Ok(signals),
167            Err(Status::TIMED_OUT) => WaitResult::TimedOut(signals),
168            Err(Status::CANCELED) => WaitResult::Canceled(signals),
169            Err(e) => WaitResult::Err(e),
170        }
171    }
172
173    /// Wraps the [zx_object_wait_async](https://fuchsia.dev/reference/syscalls/object_wait_async)
174    /// syscall.
175    pub fn wait_async(
176        &self,
177        port: &Port,
178        key: u64,
179        signals: Signals,
180        options: WaitAsyncOpts,
181    ) -> Result<(), Status> {
182        // SAFETY: basic FFI call.
183        ok(unsafe {
184            sys::zx_object_wait_async(
185                self.raw_handle(),
186                port.raw_handle(),
187                key,
188                signals.bits(),
189                options.bits(),
190            )
191        })
192    }
193
194    /// Return a [`WaitItem`] for this handle and `signals` that can be used with
195    /// [`object_wait_many`].
196    pub fn wait_item(&self, signals: Signals) -> WaitItem<'_> {
197        WaitItem::new(self.as_handle_ref(), signals)
198    }
199
200    /// Get the [Property::NAME] property for this object.
201    ///
202    /// Wraps a call to the
203    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
204    /// syscall for the `ZX_PROP_NAME` property.
205    pub fn get_name(&self) -> Result<Name, Status> {
206        self.get_property::<NameProperty>()
207    }
208
209    /// Set the [Property::NAME] property for this object.
210    ///
211    /// The name's length must be less than [sys::ZX_MAX_NAME_LEN], i.e.
212    /// name.[to_bytes_with_nul()](CStr::to_bytes_with_nul()).len() <= [sys::ZX_MAX_NAME_LEN], or
213    /// Err([Status::INVALID_ARGS]) will be returned.
214    ///
215    /// Wraps a call to the
216    /// [`zx_object_get_property`](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
217    /// syscall for the `ZX_PROP_NAME` property.
218    pub fn set_name(&self, name: &Name) -> Result<(), Status> {
219        self.set_property::<NameProperty>(&name)
220    }
221
222    /// Get a property on a zircon object
223    pub(crate) fn get_property<P: PropertyQuery>(&self) -> Result<P::PropTy, Status>
224    where
225        P::PropTy: FromBytes + Immutable,
226    {
227        let mut out = ::std::mem::MaybeUninit::<P::PropTy>::uninit();
228
229        // SAFETY: safe due to the contract on the P::PropTy type in the ObjectProperty trait.
230        let status = unsafe {
231            sys::zx_object_get_property(
232                self.raw_handle(),
233                *P::PROPERTY,
234                out.as_mut_ptr().cast::<u8>(),
235                std::mem::size_of::<P::PropTy>(),
236            )
237        };
238        Status::ok(status).map(|_| unsafe { out.assume_init() })
239    }
240
241    /// Set a property on a zircon object
242    pub(crate) fn set_property<P: PropertyQuery>(&self, val: &P::PropTy) -> Result<(), Status>
243    where
244        P::PropTy: IntoBytes + Immutable,
245    {
246        let status = unsafe {
247            sys::zx_object_set_property(
248                self.raw_handle(),
249                *P::PROPERTY,
250                std::ptr::from_ref(val).cast::<u8>(),
251                std::mem::size_of::<P::PropTy>(),
252            )
253        };
254        Status::ok(status)
255    }
256
257    /// Wraps the
258    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
259    /// syscall for the ZX_INFO_HANDLE_BASIC topic.
260    pub fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
261        Ok(HandleBasicInfo::from(self.get_info_single::<HandleBasicInfoQuery>()?))
262    }
263
264    /// Wraps the
265    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
266    /// syscall for the ZX_INFO_HANDLE_COUNT topic.
267    pub fn count_info(&self) -> Result<HandleCountInfo, Status> {
268        Ok(HandleCountInfo::from(self.get_info_single::<HandleCountInfoQuery>()?))
269    }
270
271    /// Returns the koid (kernel object ID) for the object to which this handle refers.
272    pub fn koid(&self) -> Result<Koid, Status> {
273        self.basic_info().map(|info| info.koid)
274    }
275
276    /// Query information about a zircon object. Returns a valid slice and any remaining capacity on
277    /// success, along with a count of how many infos the kernel had available.
278    pub(crate) fn get_info<'a, Q: ObjectQuery>(
279        &self,
280        out: &'a mut [MaybeUninit<Q::InfoTy>],
281    ) -> Result<(&'a mut [Q::InfoTy], &'a mut [MaybeUninit<Q::InfoTy>], usize), Status>
282    where
283        Q::InfoTy: FromBytes + Immutable,
284    {
285        let mut actual = 0;
286        let mut avail = 0;
287
288        // SAFETY: The slice pointer is known valid to write to for `size_of_val` because it came
289        // from a mutable reference.
290        let status = unsafe {
291            sys::zx_object_get_info(
292                self.raw_handle(),
293                *Q::TOPIC,
294                out.as_mut_ptr().cast::<u8>(),
295                std::mem::size_of_val(out),
296                &mut actual,
297                &mut avail,
298            )
299        };
300        ok(status)?;
301
302        let (initialized, uninit) = out.split_at_mut(actual);
303
304        // TODO(https://fxbug.dev/352398385) switch to MaybeUninit::slice_assume_init_mut
305        // SAFETY: these values have been initialized by the kernel and implement the right zerocopy
306        // traits to be instantiated from arbitrary bytes.
307        let initialized: &mut [Q::InfoTy] = unsafe {
308            std::slice::from_raw_parts_mut(
309                initialized.as_mut_ptr().cast::<Q::InfoTy>(),
310                initialized.len(),
311            )
312        };
313
314        Ok((initialized, uninit, avail))
315    }
316
317    /// Query information about a zircon object, expecting only a single info in the return.
318    pub(crate) fn get_info_single<Q: ObjectQuery>(&self) -> Result<Q::InfoTy, Status>
319    where
320        Q::InfoTy: Copy + FromBytes + Immutable,
321    {
322        let mut info = MaybeUninit::<Q::InfoTy>::uninit();
323        let (info, _uninit, _avail) = self.get_info::<Q>(std::slice::from_mut(&mut info))?;
324        Ok(info[0])
325    }
326
327    /// Query multiple records of information about a zircon object.
328    /// Returns a vec of Q::InfoTy on success.
329    /// Intended for calls that return multiple small objects.
330    pub(crate) fn get_info_vec<Q: ObjectQuery>(&self) -> Result<Vec<Q::InfoTy>, Status> {
331        // Start with a few slots
332        let mut out = Vec::<Q::InfoTy>::with_capacity(INFO_VEC_SIZE_INITIAL);
333        loop {
334            let (init, _uninit, avail) = self.get_info::<Q>(out.spare_capacity_mut())?;
335            let num_initialized = init.len();
336            if num_initialized == avail {
337                // SAFETY: the kernel has initialized all of these values.
338                unsafe { out.set_len(num_initialized) };
339                return Ok(out);
340            } else {
341                if avail > out.capacity() {
342                    out.reserve_exact(avail - out.len());
343                }
344            }
345        }
346    }
347}
348
349impl AsHandleRef for Handle {
350    fn as_handle_ref(&self) -> HandleRef<'_> {
351        // SAFETY: inner is a guaranteed valid handle that will not be closed for self's lifetime.
352        unsafe { Unowned::from_raw_handle(self.raw_handle()) }
353    }
354}
355
356impl Drop for Handle {
357    fn drop(&mut self) {
358        if !self.is_poison() {
359            // SAFETY: basic FFI call.
360            unsafe { sys::zx_handle_close(self.0.get()) };
361        }
362    }
363}
364
365/// An object representing a Zircon
366/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles).
367///
368/// Internally, it is represented as a 32-bit integer, but this wrapper enforces
369/// strict ownership semantics. The `Drop` implementation closes the handle.
370///
371/// This type represents the most general reference to a kernel object, and can
372/// be interconverted to and from more specific types. Those conversions are not
373/// enforced in the type system; attempting to use them will result in errors
374/// returned by the kernel. These conversions don't change the underlying
375/// representation, but do change the type and thus what operations are available.
376// TODO(https://fxbug.dev/465766514): remove
377#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
378#[repr(transparent)]
379pub struct NullableHandle(Option<Handle>);
380
381impl AsHandleRef for NullableHandle {
382    fn as_handle_ref(&self) -> HandleRef<'_> {
383        if let Some(inner) = &self.0 {
384            // SAFETY: inner is a guaranteed valid handle.
385            unsafe { Unowned::from_raw_handle(inner.raw_handle()) }
386        } else {
387            // SAFETY: ZX_HANDLE_INVALID is a valid handle for Unowned::from_raw_handle.
388            unsafe { Unowned::from_raw_handle(sys::ZX_HANDLE_INVALID) }
389        }
390    }
391}
392
393impl NullableHandle {
394    /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle.
395    #[inline(always)]
396    pub const fn invalid() -> Self {
397        Self(None)
398    }
399
400    /// If a raw handle is obtained from some other source, this method converts
401    /// it into a type-safe owned handle.
402    ///
403    /// # Safety
404    ///
405    /// `raw` must either be a valid handle (i.e. not dangling), or
406    /// `ZX_HANDLE_INVALID`. If `raw` is a valid handle, then either:
407    /// - `raw` may be closed manually and the returned `NullableHandle` must not be
408    ///   dropped.
409    /// - Or `raw` must not be closed until the returned `NullableHandle` is dropped, at
410    ///   which time it will close `raw`.
411    pub const unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
412        // We need to manually construct the inner `Handle` because its constructor is not
413        // const since the only valid way to call this function in a `const` context is to pass
414        // `ZX_HANDLE_INVALID`.
415        if let Some(inner) = NonZeroU32::new(raw) { Self(Some(Handle(inner))) } else { Self(None) }
416    }
417
418    pub const fn raw_handle(&self) -> sys::zx_handle_t {
419        if let Some(inner) = &self.0 { inner.raw_handle() } else { sys::ZX_HANDLE_INVALID }
420    }
421
422    pub fn into_raw(self) -> sys::zx_handle_t {
423        self.0.map(Handle::into_raw).unwrap_or(sys::ZX_HANDLE_INVALID)
424    }
425
426    pub fn as_handle_ref(&self) -> HandleRef<'_> {
427        AsHandleRef::as_handle_ref(self)
428    }
429
430    pub const fn is_invalid(&self) -> bool {
431        self.0.is_none()
432    }
433
434    pub fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
435        self.0
436            .as_ref()
437            .map(|h| h.duplicate(rights).map(|new| Self(Some(new))))
438            .unwrap_or(Err(Status::BAD_HANDLE))
439    }
440
441    pub fn replace_handle(mut self, rights: Rights) -> Result<Self, Status> {
442        if let Some(inner) = self.0.take() {
443            let inner = inner.replace(rights)?;
444            Ok(Self(Some(inner)))
445        } else {
446            Ok(Self(None))
447        }
448    }
449
450    pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
451        self.0.as_ref().map(|h| h.signal(clear_mask, set_mask)).unwrap_or(Err(Status::BAD_HANDLE))
452    }
453
454    pub fn wait_one(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
455        self.0
456            .as_ref()
457            .map(|h| h.wait_one(signals, deadline))
458            .unwrap_or(WaitResult::Err(Status::BAD_HANDLE))
459    }
460
461    pub fn wait_async(
462        &self,
463        port: &Port,
464        key: u64,
465        signals: Signals,
466        options: WaitAsyncOpts,
467    ) -> Result<(), Status> {
468        self.0
469            .as_ref()
470            .map(|h| h.wait_async(port, key, signals, options))
471            .unwrap_or(Err(Status::BAD_HANDLE))
472    }
473
474    pub fn wait_item(&self, signals: Signals) -> WaitItem<'_> {
475        WaitItem::new(self.as_handle_ref(), signals)
476    }
477
478    pub fn get_name(&self) -> Result<Name, Status> {
479        self.0.as_ref().map(Handle::get_name).unwrap_or(Err(Status::BAD_HANDLE))
480    }
481
482    pub fn set_name(&self, name: &Name) -> Result<(), Status> {
483        self.0.as_ref().map(|h| h.set_name(name)).unwrap_or(Err(Status::BAD_HANDLE))
484    }
485
486    pub fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
487        self.0.as_ref().map(Handle::basic_info).unwrap_or(Err(Status::BAD_HANDLE))
488    }
489
490    pub fn count_info(&self) -> Result<HandleCountInfo, Status> {
491        self.0.as_ref().map(Handle::count_info).unwrap_or(Err(Status::BAD_HANDLE))
492    }
493
494    pub fn koid(&self) -> Result<Koid, Status> {
495        self.0.as_ref().map(Handle::koid).unwrap_or(Err(Status::BAD_HANDLE))
496    }
497
498    pub(crate) fn get_info<'a, Q: ObjectQuery>(
499        &self,
500        out: &'a mut [MaybeUninit<Q::InfoTy>],
501    ) -> Result<(&'a mut [Q::InfoTy], &'a mut [MaybeUninit<Q::InfoTy>], usize), Status>
502    where
503        Q::InfoTy: FromBytes + Immutable,
504    {
505        self.0.as_ref().map(|h| h.get_info::<Q>(out)).unwrap_or(Err(Status::BAD_HANDLE))
506    }
507
508    pub(crate) fn get_info_single<Q: ObjectQuery>(&self) -> Result<Q::InfoTy, Status>
509    where
510        Q::InfoTy: Copy + FromBytes + Immutable,
511    {
512        self.0.as_ref().map(|h| h.get_info_single::<Q>()).unwrap_or(Err(Status::BAD_HANDLE))
513    }
514
515    pub(crate) fn get_info_vec<Q: ObjectQuery>(&self) -> Result<Vec<Q::InfoTy>, Status> {
516        self.0.as_ref().map(|h| h.get_info_vec::<Q>()).unwrap_or(Err(Status::BAD_HANDLE))
517    }
518
519    pub(crate) fn get_property<P: PropertyQuery>(&self) -> Result<P::PropTy, Status>
520    where
521        P::PropTy: FromBytes + Immutable,
522    {
523        self.0.as_ref().map(|h| h.get_property::<P>()).unwrap_or(Err(Status::BAD_HANDLE))
524    }
525
526    pub(crate) fn set_property<P: PropertyQuery>(&self, val: &P::PropTy) -> Result<(), Status>
527    where
528        P::PropTy: IntoBytes + Immutable,
529    {
530        self.0.as_ref().map(|h| h.set_property::<P>(val)).unwrap_or(Err(Status::BAD_HANDLE))
531    }
532}
533
534impl From<Handle> for NullableHandle {
535    fn from(h: Handle) -> Self {
536        Self(Some(h))
537    }
538}
539
540impl From<Option<Handle>> for NullableHandle {
541    fn from(h: Option<Handle>) -> Self {
542        Self(h)
543    }
544}
545
546impl TryFrom<NullableHandle> for Handle {
547    type Error = Status;
548    fn try_from(h: NullableHandle) -> Result<Self, Self::Error> {
549        h.0.ok_or(Status::BAD_HANDLE)
550    }
551}
552
553struct NameProperty();
554// SAFETY: this type is correctly sized and the kernel guarantees that it will be
555// null-terminated like the type requires.
556unsafe impl PropertyQuery for NameProperty {
557    const PROPERTY: Property = Property::NAME;
558    type PropTy = Name;
559}
560
561/// A borrowed value of type `T`.
562///
563/// This is primarily used for working with borrowed values of handle wrapper types.
564#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
565#[repr(transparent)]
566pub struct Unowned<'a, T> {
567    inner: ManuallyDrop<T>,
568    marker: PhantomData<&'a T>,
569}
570
571// Ensure ABI-compatibility with zx_handle_t with the following static assertions, like on Handle.
572static_assertions::assert_eq_size!(Unowned<'static, Handle>, sys::zx_handle_t);
573static_assertions::assert_eq_align!(Unowned<'static, Handle>, sys::zx_handle_t);
574static_assertions::assert_eq_size!(Option<Unowned<'static, Handle>>, sys::zx_handle_t);
575static_assertions::assert_eq_align!(Option<Unowned<'static, Handle>>, sys::zx_handle_t);
576
577impl<'a, T> std::ops::Deref for Unowned<'a, T> {
578    type Target = T;
579
580    fn deref(&self) -> &Self::Target {
581        &*self.inner
582    }
583}
584
585impl<'a, T: AsHandleRef> AsHandleRef for Unowned<'a, T> {
586    fn as_handle_ref(&self) -> HandleRef<'_> {
587        self.inner.as_handle_ref()
588    }
589}
590
591impl<T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>> Clone for Unowned<'_, T> {
592    fn clone(&self) -> Self {
593        unsafe { Self::from_raw_handle(self.inner.as_handle_ref().raw_handle()) }
594    }
595}
596
597pub type HandleRef<'a> = Unowned<'a, NullableHandle>;
598
599impl<'a, T: Into<NullableHandle>> Unowned<'a, T> {
600    /// Returns a new object that borrows the underyling handle.  This will work for any type that
601    /// implements `From<U>` where `U` is handle-like i.e. it implements `AsHandleRef` and
602    /// `From<Handle>`.
603    pub fn new<U: AsHandleRef + From<NullableHandle>>(inner: &'a U) -> Self
604    where
605        T: From<U>,
606    {
607        // SAFETY: This is safe because we are converting from &U to U to allow us to create T, and
608        // then when we drop, we convert T into a handle that we forget.
609        Unowned {
610            inner: ManuallyDrop::new(T::from(U::from(unsafe {
611                NullableHandle::from_raw(inner.as_handle_ref().raw_handle())
612            }))),
613            marker: PhantomData,
614        }
615    }
616}
617
618impl<'a, T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>> Unowned<'a, T> {
619    /// Create a `HandleRef` from a raw handle. Use this method when you are given a raw handle but
620    /// should not take ownership of it. Examples include process-global handles like the root
621    /// VMAR. This method should be called with an explicitly provided lifetime that must not
622    /// outlive the lifetime during which the handle is owned by the current process. It is unsafe
623    /// because most of the time, it is better to use a `Handle` to prevent leaking resources.
624    ///
625    /// # Safety
626    ///
627    /// `handle` must be a valid handle (i.e. not dangling), or
628    /// `ZX_HANDLE_INVALID`. If `handle` is a valid handle, then it must not be
629    /// closed for the lifetime `'a`.
630    pub unsafe fn from_raw_handle(handle: sys::zx_handle_t) -> Self {
631        Unowned {
632            inner: ManuallyDrop::new(T::from(unsafe { NullableHandle::from_raw(handle) })),
633            marker: PhantomData,
634        }
635    }
636
637    /// Returns the raw handle's integer value.
638    pub fn raw_handle(&self) -> sys::zx_handle_t {
639        NullableHandle::raw_handle(&*self.inner.as_handle_ref())
640    }
641}
642
643/// Result from `HandleRef::wait` and `AsHandleRef::wait_handle`. Conveys the
644/// result of the
645/// [zx_object_wait_one](https://fuchsia.dev/reference/syscalls/object_wait_one)
646/// syscall and the signals that were asserted on the object when the syscall
647/// completed.
648#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
649pub enum WaitResult {
650    /// The syscall completed with `ZX_OK` and the provided signals were observed.
651    Ok(Signals),
652
653    /// The syscall completed with `ZX_ERR_TIMED_OUT` and the provided signals
654    /// were observed. These signals may reflect state changes that occurred
655    /// after the deadline passed, but before the syscall returned.
656    TimedOut(Signals),
657
658    /// The syscall completed with `ZX_ERR_CANCELED` and the provided signals
659    /// were observed. The signals will include `ZX_SIGNAL_HANDLE_CLOSED`.
660    ///
661    /// Note that the state of these signals may be racy and difficult to
662    /// interpret. Often, the correct behavior in this case is to treat this as
663    /// an error.
664    Canceled(Signals),
665
666    /// The syscall completed with a status other than `ZX_OK`, `ZX_ERR_TIMED_OUT`,
667    /// or `ZX_ERR_CANCELED`. No signals are returned in this scenario.
668    Err(Status),
669}
670
671impl WaitResult {
672    /// Convert this `WaitResult` into a `Result<Signals, Status>`. The signals
673    /// are discarded in all cases except `WaitResult::Ok`.
674    pub const fn to_result(self) -> Result<Signals, Status> {
675        match self {
676            WaitResult::Ok(signals) => Ok(signals),
677            WaitResult::TimedOut(_signals) => Err(Status::TIMED_OUT),
678            WaitResult::Canceled(_signals) => Err(Status::CANCELED),
679            WaitResult::Err(status) => Err(status),
680        }
681    }
682
683    // The following definitions are all copied from `std::result::Result`. They
684    // allow a `WaitResult` to be treated like a `Result` in many circumstance. All
685    // simply delegate to `to_result()`.
686
687    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
688    #[inline]
689    pub const fn is_ok(&self) -> bool {
690        self.to_result().is_ok()
691    }
692
693    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
694    #[inline]
695    pub const fn is_err(&self) -> bool {
696        self.to_result().is_err()
697    }
698
699    #[inline]
700    pub fn map<U, F: FnOnce(Signals) -> U>(self, op: F) -> Result<U, Status> {
701        self.to_result().map(op)
702    }
703
704    #[inline]
705    pub fn map_err<F, O: FnOnce(Status) -> F>(self, op: O) -> Result<Signals, F> {
706        self.to_result().map_err(op)
707    }
708
709    #[inline]
710    #[track_caller]
711    pub fn expect(self, msg: &str) -> Signals {
712        self.to_result().expect(msg)
713    }
714
715    #[inline]
716    #[track_caller]
717    pub fn expect_err(self, msg: &str) -> Status {
718        self.to_result().expect_err(msg)
719    }
720
721    #[inline(always)]
722    #[track_caller]
723    pub fn unwrap(self) -> Signals {
724        self.to_result().unwrap()
725    }
726}
727
728impl<'a> Unowned<'a, NullableHandle> {
729    /// Convert this HandleRef to one of a specific type.
730    pub fn cast<T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>>(
731        self,
732    ) -> Unowned<'a, T> {
733        // SAFETY: this function's guarantees are upheld by the self input.
734        unsafe { Unowned::from_raw_handle(self.raw_handle()) }
735    }
736}
737
738/// A trait to get a reference to the underlying handle of an object.
739pub trait AsHandleRef {
740    /// Get a reference to the handle. One important use of such a reference is
741    /// for `object_wait_many`.
742    fn as_handle_ref(&self) -> HandleRef<'_>;
743}
744
745impl<T: AsHandleRef> AsHandleRef for &T {
746    fn as_handle_ref(&self) -> HandleRef<'_> {
747        (*self).as_handle_ref()
748    }
749}
750
751/// A trait implemented by all handles for objects which have a peer.
752pub trait Peered: AsHandleRef {
753    /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
754    /// [zx_object_signal_peer][osp] syscall.
755    ///
756    /// [osp]: https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal_peer.md
757    fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
758        let handle = self.as_handle_ref().raw_handle();
759        let status =
760            unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) };
761        ok(status)
762    }
763
764    /// Returns true if the handle has received the `PEER_CLOSED` signal.
765    ///
766    /// # Errors
767    ///
768    /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
769    /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
770    /// errors are propagated.
771    fn is_closed(&self) -> Result<bool, Status> {
772        match self
773            .as_handle_ref()
774            .wait_one(Signals::OBJECT_PEER_CLOSED, MonotonicInstant::INFINITE_PAST)
775        {
776            WaitResult::Ok(signals) => Ok(signals.contains(Signals::OBJECT_PEER_CLOSED)),
777            WaitResult::TimedOut(_) => Ok(false),
778            WaitResult::Canceled(_) => Err(Status::CANCELED),
779            WaitResult::Err(e) => Err(e),
780        }
781    }
782}
783
784/// Basic information about a handle.
785///
786/// Wrapper for data returned from [Handle::basic_info()].
787#[derive(Debug, Copy, Clone, Eq, PartialEq)]
788pub struct HandleBasicInfo {
789    pub koid: Koid,
790    pub rights: Rights,
791    pub object_type: ObjectType,
792    pub related_koid: Koid,
793}
794
795impl Default for HandleBasicInfo {
796    fn default() -> Self {
797        Self::from(sys::zx_info_handle_basic_t::default())
798    }
799}
800
801impl From<sys::zx_info_handle_basic_t> for HandleBasicInfo {
802    fn from(info: sys::zx_info_handle_basic_t) -> Self {
803        let sys::zx_info_handle_basic_t { koid, rights, type_, related_koid, .. } = info;
804
805        // Note lossy conversion of Rights and HandleProperty here if either of those types are out
806        // of date or incomplete.
807        HandleBasicInfo {
808            koid: Koid::from_raw(koid),
809            rights: Rights::from_bits_truncate(rights),
810            object_type: ObjectType::from_raw(type_),
811            related_koid: Koid::from_raw(related_koid),
812        }
813    }
814}
815
816// zx_info_handle_basic_t is able to be safely replaced with a byte representation and is a PoD
817// type.
818struct HandleBasicInfoQuery;
819unsafe impl ObjectQuery for HandleBasicInfoQuery {
820    const TOPIC: Topic = Topic::HANDLE_BASIC;
821    type InfoTy = sys::zx_info_handle_basic_t;
822}
823
824sys::zx_info_handle_count_t!(HandleCountInfo);
825
826impl From<sys::zx_info_handle_count_t> for HandleCountInfo {
827    fn from(sys::zx_info_handle_count_t { handle_count }: sys::zx_info_handle_count_t) -> Self {
828        HandleCountInfo { handle_count }
829    }
830}
831
832// zx_info_handle_count_t is able to be safely replaced with a byte representation and is a PoD
833// type.
834struct HandleCountInfoQuery;
835unsafe impl ObjectQuery for HandleCountInfoQuery {
836    const TOPIC: Topic = Topic::HANDLE_COUNT;
837    type InfoTy = sys::zx_info_handle_count_t;
838}
839
840/// Handle operation.
841#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
842pub enum HandleOp<'a> {
843    Move(NullableHandle),
844    Duplicate(HandleRef<'a>),
845}
846
847/// Operation to perform on handles during write. ABI-compatible with `zx_handle_disposition_t`.
848#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
849#[repr(C)]
850pub struct HandleDisposition<'a> {
851    // Must be either ZX_HANDLE_OP_MOVE or ZX_HANDLE_OP_DUPLICATE.
852    operation: sys::zx_handle_op_t,
853    // ZX_HANDLE_OP_MOVE==owned, ZX_HANDLE_OP_DUPLICATE==borrowed.
854    handle: sys::zx_handle_t,
855    // Preserve a borrowed handle's lifetime. Does not occupy any layout.
856    _handle_lifetime: std::marker::PhantomData<&'a ()>,
857
858    pub object_type: ObjectType,
859    pub rights: Rights,
860    pub result: Status,
861}
862
863static_assertions::assert_eq_size!(HandleDisposition<'_>, sys::zx_handle_disposition_t);
864static_assertions::const_assert_eq!(
865    std::mem::offset_of!(HandleDisposition<'_>, operation),
866    std::mem::offset_of!(sys::zx_handle_disposition_t, operation)
867);
868static_assertions::const_assert_eq!(
869    std::mem::offset_of!(HandleDisposition<'_>, handle),
870    std::mem::offset_of!(sys::zx_handle_disposition_t, handle)
871);
872static_assertions::const_assert_eq!(
873    std::mem::offset_of!(HandleDisposition<'_>, object_type),
874    std::mem::offset_of!(sys::zx_handle_disposition_t, type_)
875);
876static_assertions::const_assert_eq!(
877    std::mem::offset_of!(HandleDisposition<'_>, rights),
878    std::mem::offset_of!(sys::zx_handle_disposition_t, rights)
879);
880static_assertions::const_assert_eq!(
881    std::mem::offset_of!(HandleDisposition<'_>, result),
882    std::mem::offset_of!(sys::zx_handle_disposition_t, result)
883);
884
885impl<'a> HandleDisposition<'a> {
886    #[inline]
887    pub fn new<R: Into<Result<(), Status>>>(
888        handle_op: HandleOp<'a>,
889        object_type: ObjectType,
890        rights: Rights,
891        status: R,
892    ) -> Self {
893        let status = Status::from_raw(Status::result_into_raw(status.into()));
894        let (operation, handle) = match handle_op {
895            HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
896            HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
897        };
898
899        Self {
900            operation,
901            handle,
902            _handle_lifetime: std::marker::PhantomData,
903            object_type,
904            rights: rights,
905            result: status,
906        }
907    }
908
909    pub fn raw_handle(&self) -> sys::zx_handle_t {
910        self.handle
911    }
912
913    pub fn is_move(&self) -> bool {
914        self.operation == sys::ZX_HANDLE_OP_MOVE
915    }
916
917    pub fn is_duplicate(&self) -> bool {
918        self.operation == sys::ZX_HANDLE_OP_DUPLICATE
919    }
920
921    pub fn take_op(&mut self) -> HandleOp<'a> {
922        match self.operation {
923            sys::ZX_HANDLE_OP_MOVE => {
924                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
925                // type's public API and the kernel's guarantees.
926                HandleOp::Move(unsafe {
927                    NullableHandle::from_raw(std::mem::replace(
928                        &mut self.handle,
929                        sys::ZX_HANDLE_INVALID,
930                    ))
931                })
932            }
933            sys::ZX_HANDLE_OP_DUPLICATE => {
934                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
935                // type's public API and the kernel's guarantees.
936                HandleOp::Duplicate(Unowned {
937                    inner: ManuallyDrop::new(unsafe { NullableHandle::from_raw(self.handle) }),
938                    marker: PhantomData,
939                })
940            }
941            _ => unreachable!(),
942        }
943    }
944
945    pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
946        match self.take_op() {
947            HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
948                operation: sys::ZX_HANDLE_OP_MOVE,
949                handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
950                type_: self.object_type.into_raw(),
951                rights: self.rights.bits(),
952                result: self.result.into_raw(),
953            },
954            HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
955                operation: sys::ZX_HANDLE_OP_DUPLICATE,
956                handle: handle_ref.raw_handle(),
957                type_: self.object_type.into_raw(),
958                rights: self.rights.bits(),
959                result: self.result.into_raw(),
960            },
961        }
962    }
963}
964
965impl<'a> Drop for HandleDisposition<'a> {
966    fn drop(&mut self) {
967        // Ensure we clean up owned handle variants.
968        if self.operation == sys::ZX_HANDLE_OP_MOVE {
969            unsafe { drop(NullableHandle::from_raw(self.handle)) };
970        }
971    }
972}
973
974/// Information on handles that were read.
975///
976/// ABI-compatible with zx_handle_info_t.
977#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
978#[repr(C)]
979pub struct HandleInfo {
980    pub handle: NullableHandle,
981    pub object_type: ObjectType,
982    pub rights: Rights,
983
984    // Necessary for ABI compatibility with zx_handle_info_t.
985    pub(crate) _unused: u32,
986}
987
988static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
989static_assertions::const_assert_eq!(
990    std::mem::offset_of!(HandleInfo, handle),
991    std::mem::offset_of!(sys::zx_handle_info_t, handle)
992);
993static_assertions::const_assert_eq!(
994    std::mem::offset_of!(HandleInfo, object_type),
995    std::mem::offset_of!(sys::zx_handle_info_t, ty)
996);
997static_assertions::const_assert_eq!(
998    std::mem::offset_of!(HandleInfo, rights),
999    std::mem::offset_of!(sys::zx_handle_info_t, rights)
1000);
1001static_assertions::const_assert_eq!(
1002    std::mem::offset_of!(HandleInfo, _unused),
1003    std::mem::offset_of!(sys::zx_handle_info_t, unused)
1004);
1005
1006impl HandleInfo {
1007    /// Make a new `HandleInfo`.
1008    pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
1009        Self { handle, object_type, rights, _unused: 0 }
1010    }
1011
1012    /// # Safety
1013    ///
1014    /// See [`Handle::from_raw`] for requirements about the validity and closing
1015    /// of `raw.handle`.
1016    ///
1017    /// Note that while `raw.ty` _should_ correspond to the type of the handle,
1018    /// that this is not required for safety.
1019    pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
1020        HandleInfo::new(
1021            // SAFETY: invariants to not double-close are upheld by the caller.
1022            unsafe { NullableHandle::from_raw(raw.handle) },
1023            ObjectType::from_raw(raw.ty),
1024            Rights::from_bits_retain(raw.rights),
1025        )
1026    }
1027}
1028
1029#[cfg(test)]
1030mod tests {
1031    use super::*;
1032    // The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
1033    // zx::Vmar that we need to use.
1034    use zx::{
1035        Channel, HandleDisposition, HandleInfo, HandleOp, Name, NullableHandle, ObjectType, Rights,
1036        Vmo,
1037    };
1038    use zx_sys as sys;
1039
1040    #[test]
1041    fn into_raw() {
1042        let vmo = Vmo::create(1).unwrap();
1043        let h = vmo.into_raw();
1044        let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
1045        assert!(vmo2.write(b"1", 0).is_ok());
1046    }
1047
1048    #[test]
1049    fn check_raw_valid() {
1050        assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
1051        let vmo = Vmo::create(1).unwrap();
1052        let vmo_raw = vmo.raw_handle();
1053        assert!(Handle::check_raw_valid(vmo_raw).is_ok());
1054        drop(vmo);
1055        assert!(Handle::check_raw_valid(vmo_raw).is_err());
1056    }
1057
1058    /// Test duplication by means of a VMO
1059    #[test]
1060    fn duplicate() {
1061        let hello_length: usize = 5;
1062
1063        // Create a VMO and write some data to it.
1064        let vmo = Vmo::create(hello_length as u64).unwrap();
1065        assert!(vmo.write(b"hello", 0).is_ok());
1066
1067        // Replace, reducing rights to read.
1068        let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
1069        // Make sure we can read but not write.
1070        let mut read_vec = vec![0; hello_length];
1071        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1072        assert_eq!(read_vec, b"hello");
1073        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1074
1075        // Write new data to the original handle, and read it from the new handle
1076        assert!(vmo.write(b"bye", 0).is_ok());
1077        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1078        assert_eq!(read_vec, b"byelo");
1079    }
1080
1081    // Test replace by means of a VMO
1082    #[test]
1083    fn replace() {
1084        let hello_length: usize = 5;
1085
1086        // Create a VMO and write some data to it.
1087        let vmo = Vmo::create(hello_length as u64).unwrap();
1088        assert!(vmo.write(b"hello", 0).is_ok());
1089
1090        // Replace, reducing rights to read.
1091        let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
1092        // Make sure we can read but not write.
1093        let mut read_vec = vec![0; hello_length];
1094        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1095        assert_eq!(read_vec, b"hello");
1096        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1097    }
1098
1099    #[test]
1100    fn set_get_name() {
1101        // We need some concrete object to exercise the AsHandleRef<'_> set/get_name functions.
1102        let vmo = Vmo::create(1).unwrap();
1103        let short_name = Name::new("v").unwrap();
1104        assert!(vmo.set_name(&short_name).is_ok());
1105        assert_eq!(vmo.get_name().unwrap(), short_name);
1106    }
1107
1108    #[test]
1109    fn set_get_max_len_name() {
1110        let vmo = Vmo::create(1).unwrap();
1111        let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); // 31 bytes
1112        assert!(vmo.set_name(&max_len_name).is_ok());
1113        assert_eq!(vmo.get_name().unwrap(), max_len_name);
1114    }
1115
1116    #[test]
1117    fn basic_info_channel() {
1118        let (side1, side2) = Channel::create();
1119        let info1 = side1.basic_info().expect("side1 basic_info failed");
1120        let info2 = side2.basic_info().expect("side2 basic_info failed");
1121
1122        assert_eq!(info1.koid, info2.related_koid);
1123        assert_eq!(info2.koid, info1.related_koid);
1124
1125        for info in &[info1, info2] {
1126            assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
1127            assert_eq!(info.object_type, ObjectType::CHANNEL);
1128            assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
1129        }
1130
1131        let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
1132        let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
1133        assert_eq!(info1_repl.koid, info1.koid);
1134        assert_eq!(info1_repl.rights, Rights::READ);
1135    }
1136
1137    #[test]
1138    fn basic_info_vmar() {
1139        // VMARs aren't waitable.
1140        let root_vmar = fuchsia_runtime::vmar_root_self();
1141        let info = root_vmar.basic_info().expect("vmar basic_info failed");
1142        assert_eq!(info.object_type, ObjectType::VMAR);
1143        assert!(!info.rights.contains(Rights::WAIT));
1144    }
1145
1146    #[test]
1147    fn count_info() {
1148        let vmo0 = Vmo::create(1).unwrap();
1149        let count_info = vmo0.count_info().expect("vmo0 count_info failed");
1150        assert_eq!(count_info.handle_count, 1);
1151
1152        let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
1153        let count_info = vmo1.count_info().expect("vmo1 count_info failed");
1154        assert_eq!(count_info.handle_count, 2);
1155    }
1156
1157    #[test]
1158    fn raw_handle_disposition() {
1159        const RAW_HANDLE: sys::zx_handle_t = 1;
1160        let hd = HandleDisposition::new(
1161            HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
1162            ObjectType::VMO,
1163            Rights::EXECUTE,
1164            Status::OK,
1165        );
1166        let raw_hd = hd.into_raw();
1167        assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
1168        assert_eq!(raw_hd.handle, RAW_HANDLE);
1169        assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
1170        assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
1171        assert_eq!(raw_hd.result, sys::ZX_OK);
1172    }
1173
1174    #[test]
1175    fn regression_nullable_handle_into_raw_recursion() {
1176        let h = NullableHandle::invalid();
1177        // This should not stack overflow
1178        assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
1179
1180        let vmo = Vmo::create(1).unwrap();
1181        let raw = vmo.raw_handle();
1182        let h = vmo.into_handle();
1183        // This should not stack overflow
1184        assert_eq!(h.into_raw(), raw);
1185    }
1186
1187    #[test]
1188    fn handle_info_from_raw() {
1189        const RAW_HANDLE: sys::zx_handle_t = 1;
1190        let raw_hi = sys::zx_handle_info_t {
1191            handle: RAW_HANDLE,
1192            ty: sys::ZX_OBJ_TYPE_VMO,
1193            rights: sys::ZX_RIGHT_EXECUTE,
1194            unused: 128,
1195        };
1196        let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1197        assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1198        assert_eq!(hi.object_type, ObjectType::VMO);
1199        assert_eq!(hi.rights, Rights::EXECUTE);
1200    }
1201
1202    #[test]
1203    fn basic_peer_closed() {
1204        let (lhs, rhs) = crate::EventPair::create();
1205        assert!(!lhs.is_closed().unwrap());
1206        assert!(!rhs.is_closed().unwrap());
1207        drop(rhs);
1208        assert!(lhs.is_closed().unwrap());
1209    }
1210
1211    #[test]
1212    fn poisoned_drops_without_closing() {
1213        let handle = Handle::poison();
1214        assert!(handle.is_poison());
1215        drop(handle);
1216    }
1217
1218    #[test]
1219    fn valid_handles_not_poisoned() {
1220        let event = zx::Event::create();
1221        let event: zx::Handle = event.try_into().unwrap();
1222        assert!(!event.is_poison());
1223    }
1224}