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();
554unsafe impl PropertyQuery for NameProperty {
555    const PROPERTY: Property = Property::NAME;
556    // SAFETY: this type is correctly sized and the kernel guarantees that it will be
557    // null-terminated like the type requires.
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(
888        handle_op: HandleOp<'a>,
889        object_type: ObjectType,
890        rights: Rights,
891        status: Status,
892    ) -> Self {
893        let (operation, handle) = match handle_op {
894            HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
895            HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
896        };
897
898        Self {
899            operation,
900            handle,
901            _handle_lifetime: std::marker::PhantomData,
902            object_type,
903            rights: rights,
904            result: status,
905        }
906    }
907
908    pub fn raw_handle(&self) -> sys::zx_handle_t {
909        self.handle
910    }
911
912    pub fn is_move(&self) -> bool {
913        self.operation == sys::ZX_HANDLE_OP_MOVE
914    }
915
916    pub fn is_duplicate(&self) -> bool {
917        self.operation == sys::ZX_HANDLE_OP_DUPLICATE
918    }
919
920    pub fn take_op(&mut self) -> HandleOp<'a> {
921        match self.operation {
922            sys::ZX_HANDLE_OP_MOVE => {
923                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
924                // type's public API and the kernel's guarantees.
925                HandleOp::Move(unsafe {
926                    NullableHandle::from_raw(std::mem::replace(
927                        &mut self.handle,
928                        sys::ZX_HANDLE_INVALID,
929                    ))
930                })
931            }
932            sys::ZX_HANDLE_OP_DUPLICATE => {
933                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
934                // type's public API and the kernel's guarantees.
935                HandleOp::Duplicate(Unowned {
936                    inner: ManuallyDrop::new(unsafe { NullableHandle::from_raw(self.handle) }),
937                    marker: PhantomData,
938                })
939            }
940            _ => unreachable!(),
941        }
942    }
943
944    pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
945        match self.take_op() {
946            HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
947                operation: sys::ZX_HANDLE_OP_MOVE,
948                handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
949                type_: self.object_type.into_raw(),
950                rights: self.rights.bits(),
951                result: self.result.into_raw(),
952            },
953            HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
954                operation: sys::ZX_HANDLE_OP_DUPLICATE,
955                handle: handle_ref.raw_handle(),
956                type_: self.object_type.into_raw(),
957                rights: self.rights.bits(),
958                result: self.result.into_raw(),
959            },
960        }
961    }
962}
963
964impl<'a> Drop for HandleDisposition<'a> {
965    fn drop(&mut self) {
966        // Ensure we clean up owned handle variants.
967        if self.operation == sys::ZX_HANDLE_OP_MOVE {
968            unsafe { drop(NullableHandle::from_raw(self.handle)) };
969        }
970    }
971}
972
973/// Information on handles that were read.
974///
975/// ABI-compatible with zx_handle_info_t.
976#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
977#[repr(C)]
978pub struct HandleInfo {
979    pub handle: NullableHandle,
980    pub object_type: ObjectType,
981    pub rights: Rights,
982
983    // Necessary for ABI compatibility with zx_handle_info_t.
984    pub(crate) _unused: u32,
985}
986
987static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
988static_assertions::const_assert_eq!(
989    std::mem::offset_of!(HandleInfo, handle),
990    std::mem::offset_of!(sys::zx_handle_info_t, handle)
991);
992static_assertions::const_assert_eq!(
993    std::mem::offset_of!(HandleInfo, object_type),
994    std::mem::offset_of!(sys::zx_handle_info_t, ty)
995);
996static_assertions::const_assert_eq!(
997    std::mem::offset_of!(HandleInfo, rights),
998    std::mem::offset_of!(sys::zx_handle_info_t, rights)
999);
1000static_assertions::const_assert_eq!(
1001    std::mem::offset_of!(HandleInfo, _unused),
1002    std::mem::offset_of!(sys::zx_handle_info_t, unused)
1003);
1004
1005impl HandleInfo {
1006    /// Make a new `HandleInfo`.
1007    pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
1008        Self { handle, object_type, rights, _unused: 0 }
1009    }
1010
1011    /// # Safety
1012    ///
1013    /// See [`Handle::from_raw`] for requirements about the validity and closing
1014    /// of `raw.handle`.
1015    ///
1016    /// Note that while `raw.ty` _should_ correspond to the type of the handle,
1017    /// that this is not required for safety.
1018    pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
1019        HandleInfo::new(
1020            // SAFETY: invariants to not double-close are upheld by the caller.
1021            unsafe { NullableHandle::from_raw(raw.handle) },
1022            ObjectType::from_raw(raw.ty),
1023            Rights::from_bits_retain(raw.rights),
1024        )
1025    }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030    use super::*;
1031    // The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
1032    // zx::Vmar that we need to use.
1033    use zx::{
1034        Channel, HandleDisposition, HandleInfo, HandleOp, Name, NullableHandle, ObjectType, Rights,
1035        Vmo,
1036    };
1037    use zx_sys as sys;
1038
1039    #[test]
1040    fn into_raw() {
1041        let vmo = Vmo::create(1).unwrap();
1042        let h = vmo.into_raw();
1043        let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
1044        assert!(vmo2.write(b"1", 0).is_ok());
1045    }
1046
1047    #[test]
1048    fn check_raw_valid() {
1049        assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
1050        let vmo = Vmo::create(1).unwrap();
1051        let vmo_raw = vmo.raw_handle();
1052        assert!(Handle::check_raw_valid(vmo_raw).is_ok());
1053        drop(vmo);
1054        assert!(Handle::check_raw_valid(vmo_raw).is_err());
1055    }
1056
1057    /// Test duplication by means of a VMO
1058    #[test]
1059    fn duplicate() {
1060        let hello_length: usize = 5;
1061
1062        // Create a VMO and write some data to it.
1063        let vmo = Vmo::create(hello_length as u64).unwrap();
1064        assert!(vmo.write(b"hello", 0).is_ok());
1065
1066        // Replace, reducing rights to read.
1067        let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
1068        // Make sure we can read but not write.
1069        let mut read_vec = vec![0; hello_length];
1070        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1071        assert_eq!(read_vec, b"hello");
1072        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1073
1074        // Write new data to the original handle, and read it from the new handle
1075        assert!(vmo.write(b"bye", 0).is_ok());
1076        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1077        assert_eq!(read_vec, b"byelo");
1078    }
1079
1080    // Test replace by means of a VMO
1081    #[test]
1082    fn replace() {
1083        let hello_length: usize = 5;
1084
1085        // Create a VMO and write some data to it.
1086        let vmo = Vmo::create(hello_length as u64).unwrap();
1087        assert!(vmo.write(b"hello", 0).is_ok());
1088
1089        // Replace, reducing rights to read.
1090        let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
1091        // Make sure we can read but not write.
1092        let mut read_vec = vec![0; hello_length];
1093        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1094        assert_eq!(read_vec, b"hello");
1095        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1096    }
1097
1098    #[test]
1099    fn set_get_name() {
1100        // We need some concrete object to exercise the AsHandleRef<'_> set/get_name functions.
1101        let vmo = Vmo::create(1).unwrap();
1102        let short_name = Name::new("v").unwrap();
1103        assert!(vmo.set_name(&short_name).is_ok());
1104        assert_eq!(vmo.get_name().unwrap(), short_name);
1105    }
1106
1107    #[test]
1108    fn set_get_max_len_name() {
1109        let vmo = Vmo::create(1).unwrap();
1110        let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); // 31 bytes
1111        assert!(vmo.set_name(&max_len_name).is_ok());
1112        assert_eq!(vmo.get_name().unwrap(), max_len_name);
1113    }
1114
1115    #[test]
1116    fn basic_info_channel() {
1117        let (side1, side2) = Channel::create();
1118        let info1 = side1.basic_info().expect("side1 basic_info failed");
1119        let info2 = side2.basic_info().expect("side2 basic_info failed");
1120
1121        assert_eq!(info1.koid, info2.related_koid);
1122        assert_eq!(info2.koid, info1.related_koid);
1123
1124        for info in &[info1, info2] {
1125            assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
1126            assert_eq!(info.object_type, ObjectType::CHANNEL);
1127            assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
1128        }
1129
1130        let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
1131        let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
1132        assert_eq!(info1_repl.koid, info1.koid);
1133        assert_eq!(info1_repl.rights, Rights::READ);
1134    }
1135
1136    #[test]
1137    fn basic_info_vmar() {
1138        // VMARs aren't waitable.
1139        let root_vmar = fuchsia_runtime::vmar_root_self();
1140        let info = root_vmar.basic_info().expect("vmar basic_info failed");
1141        assert_eq!(info.object_type, ObjectType::VMAR);
1142        assert!(!info.rights.contains(Rights::WAIT));
1143    }
1144
1145    #[test]
1146    fn count_info() {
1147        let vmo0 = Vmo::create(1).unwrap();
1148        let count_info = vmo0.count_info().expect("vmo0 count_info failed");
1149        assert_eq!(count_info.handle_count, 1);
1150
1151        let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
1152        let count_info = vmo1.count_info().expect("vmo1 count_info failed");
1153        assert_eq!(count_info.handle_count, 2);
1154    }
1155
1156    #[test]
1157    fn raw_handle_disposition() {
1158        const RAW_HANDLE: sys::zx_handle_t = 1;
1159        let hd = HandleDisposition::new(
1160            HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
1161            ObjectType::VMO,
1162            Rights::EXECUTE,
1163            Status::OK,
1164        );
1165        let raw_hd = hd.into_raw();
1166        assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
1167        assert_eq!(raw_hd.handle, RAW_HANDLE);
1168        assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
1169        assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
1170        assert_eq!(raw_hd.result, sys::ZX_OK);
1171    }
1172
1173    #[test]
1174    fn regression_nullable_handle_into_raw_recursion() {
1175        let h = NullableHandle::invalid();
1176        // This should not stack overflow
1177        assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
1178
1179        let vmo = Vmo::create(1).unwrap();
1180        let raw = vmo.raw_handle();
1181        let h = vmo.into_handle();
1182        // This should not stack overflow
1183        assert_eq!(h.into_raw(), raw);
1184    }
1185
1186    #[test]
1187    fn handle_info_from_raw() {
1188        const RAW_HANDLE: sys::zx_handle_t = 1;
1189        let raw_hi = sys::zx_handle_info_t {
1190            handle: RAW_HANDLE,
1191            ty: sys::ZX_OBJ_TYPE_VMO,
1192            rights: sys::ZX_RIGHT_EXECUTE,
1193            unused: 128,
1194        };
1195        let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1196        assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1197        assert_eq!(hi.object_type, ObjectType::VMO);
1198        assert_eq!(hi.rights, Rights::EXECUTE);
1199    }
1200
1201    #[test]
1202    fn basic_peer_closed() {
1203        let (lhs, rhs) = crate::EventPair::create();
1204        assert!(!lhs.is_closed().unwrap());
1205        assert!(!rhs.is_closed().unwrap());
1206        drop(rhs);
1207        assert!(lhs.is_closed().unwrap());
1208    }
1209
1210    #[test]
1211    fn poisoned_drops_without_closing() {
1212        let handle = Handle::poison();
1213        assert!(handle.is_poison());
1214        drop(handle);
1215    }
1216
1217    #[test]
1218    fn valid_handles_not_poisoned() {
1219        let event = zx::Event::create();
1220        let event: zx::Handle = event.try_into().unwrap();
1221        assert!(!event.is_poison());
1222    }
1223}