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