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    fn raw_handle(&self) -> sys::zx_handle_t {
350        self.0.as_ref().map(|h| h.raw_handle()).unwrap_or(sys::ZX_HANDLE_INVALID)
351    }
352}
353
354impl HandleBased for NullableHandle {
355    fn into_raw(self) -> sys::zx_handle_t {
356        if let Some(inner) = self.0 { inner.into_raw() } else { sys::ZX_HANDLE_INVALID }
357    }
358}
359
360impl NullableHandle {
361    /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle.
362    #[inline(always)]
363    pub const fn invalid() -> Self {
364        Self(None)
365    }
366
367    /// If a raw handle is obtained from some other source, this method converts
368    /// it into a type-safe owned handle.
369    ///
370    /// # Safety
371    ///
372    /// `raw` must either be a valid handle (i.e. not dangling), or
373    /// `ZX_HANDLE_INVALID`. If `raw` is a valid handle, then either:
374    /// - `raw` may be closed manually and the returned `NullableHandle` must not be
375    ///   dropped.
376    /// - Or `raw` must not be closed until the returned `NullableHandle` is dropped, at
377    ///   which time it will close `raw`.
378    pub const unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
379        // We need to manually construct the inner `Handle` because its constructor is not
380        // const since the only valid way to call this function in a `const` context is to pass
381        // `ZX_HANDLE_INVALID`.
382        if let Some(inner) = NonZeroU32::new(raw) { Self(Some(Handle(inner))) } else { Self(None) }
383    }
384
385    pub const fn raw_handle(&self) -> sys::zx_handle_t {
386        if let Some(inner) = &self.0 { inner.raw_handle() } else { sys::ZX_HANDLE_INVALID }
387    }
388
389    pub fn into_raw(self) -> sys::zx_handle_t {
390        self.0.map(Handle::into_raw).unwrap_or(sys::ZX_HANDLE_INVALID)
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        Unowned {
522            // SAFETY: our raw handle is guaranteed to be valid and Unowned promises to not drop it
523            // during its lifetime which is bound to ours.
524            inner: ManuallyDrop::new(unsafe { NullableHandle::from_raw(self.inner.raw_handle()) }),
525            marker: PhantomData,
526        }
527    }
528}
529
530impl<T: HandleBased> Clone for Unowned<'_, T> {
531    fn clone(&self) -> Self {
532        unsafe { Self::from_raw_handle(self.inner.as_handle_ref().raw_handle()) }
533    }
534}
535
536pub type HandleRef<'a> = Unowned<'a, NullableHandle>;
537
538impl<'a, T: Into<NullableHandle>> Unowned<'a, T> {
539    /// Returns a new object that borrows the underyling handle.  This will work for any type that
540    /// implements `From<U>` where `U` is handle-like i.e. it implements `AsHandleRef` and
541    /// `From<Handle>`.
542    pub fn new<U: AsHandleRef + From<NullableHandle>>(inner: &'a U) -> Self
543    where
544        T: From<U>,
545    {
546        // SAFETY: This is safe because we are converting from &U to U to allow us to create T, and
547        // then when we drop, we convert T into a handle that we forget.
548        Unowned {
549            inner: ManuallyDrop::new(T::from(U::from(unsafe {
550                NullableHandle::from_raw(inner.as_handle_ref().raw_handle())
551            }))),
552            marker: PhantomData,
553        }
554    }
555}
556
557impl<'a, T: HandleBased> Unowned<'a, T> {
558    /// Create a `HandleRef` from a raw handle. Use this method when you are given a raw handle but
559    /// should not take ownership of it. Examples include process-global handles like the root
560    /// VMAR. This method should be called with an explicitly provided lifetime that must not
561    /// outlive the lifetime during which the handle is owned by the current process. It is unsafe
562    /// because most of the time, it is better to use a `Handle` to prevent leaking resources.
563    ///
564    /// # Safety
565    ///
566    /// `handle` must be a valid handle (i.e. not dangling), or
567    /// `ZX_HANDLE_INVALID`. If `handle` is a valid handle, then it must not be
568    /// closed for the lifetime `'a`.
569    pub unsafe fn from_raw_handle(handle: sys::zx_handle_t) -> Self {
570        Unowned {
571            inner: ManuallyDrop::new(T::from(unsafe { NullableHandle::from_raw(handle) })),
572            marker: PhantomData,
573        }
574    }
575
576    /// Returns the raw handle's integer value.
577    pub fn raw_handle(&self) -> sys::zx_handle_t {
578        self.inner.raw_handle()
579    }
580}
581
582/// Result from `HandleRef::wait` and `AsHandleRef::wait_handle`. Conveys the
583/// result of the
584/// [zx_object_wait_one](https://fuchsia.dev/reference/syscalls/object_wait_one)
585/// syscall and the signals that were asserted on the object when the syscall
586/// completed.
587#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
588pub enum WaitResult {
589    /// The syscall completed with `ZX_OK` and the provided signals were observed.
590    Ok(Signals),
591
592    /// The syscall completed with `ZX_ERR_TIMED_OUT` and the provided signals
593    /// were observed. These signals may reflect state changes that occurred
594    /// after the deadline passed, but before the syscall returned.
595    TimedOut(Signals),
596
597    /// The syscall completed with `ZX_ERR_CANCELED` and the provided signals
598    /// were observed. The signals will include `ZX_SIGNAL_HANDLE_CLOSED`.
599    ///
600    /// Note that the state of these signals may be racy and difficult to
601    /// interpret. Often, the correct behavior in this case is to treat this as
602    /// an error.
603    Canceled(Signals),
604
605    /// The syscall completed with a status other than `ZX_OK`, `ZX_ERR_TIMED_OUT`,
606    /// or `ZX_ERR_CANCELED`. No signals are returned in this scenario.
607    Err(Status),
608}
609
610impl WaitResult {
611    /// Convert this `WaitResult` into a `Result<Signals, Status>`. The signals
612    /// are discarded in all cases except `WaitResult::Ok`.
613    pub const fn to_result(self) -> Result<Signals, Status> {
614        match self {
615            WaitResult::Ok(signals) => Ok(signals),
616            WaitResult::TimedOut(_signals) => Err(Status::TIMED_OUT),
617            WaitResult::Canceled(_signals) => Err(Status::CANCELED),
618            WaitResult::Err(status) => Err(status),
619        }
620    }
621
622    // The following definitions are all copied from `std::result::Result`. They
623    // allow a `WaitResult` to be treated like a `Result` in many circumstance. All
624    // simply delegate to `to_result()`.
625
626    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
627    #[inline]
628    pub const fn is_ok(&self) -> bool {
629        self.to_result().is_ok()
630    }
631
632    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
633    #[inline]
634    pub const fn is_err(&self) -> bool {
635        self.to_result().is_err()
636    }
637
638    #[inline]
639    pub fn map<U, F: FnOnce(Signals) -> U>(self, op: F) -> Result<U, Status> {
640        self.to_result().map(op)
641    }
642
643    #[inline]
644    pub fn map_err<F, O: FnOnce(Status) -> F>(self, op: O) -> Result<Signals, F> {
645        self.to_result().map_err(op)
646    }
647
648    #[inline]
649    #[track_caller]
650    pub fn expect(self, msg: &str) -> Signals {
651        self.to_result().expect(msg)
652    }
653
654    #[inline]
655    #[track_caller]
656    pub fn expect_err(self, msg: &str) -> Status {
657        self.to_result().expect_err(msg)
658    }
659
660    #[inline(always)]
661    #[track_caller]
662    pub fn unwrap(self) -> Signals {
663        self.to_result().unwrap()
664    }
665}
666
667impl<'a> Unowned<'a, NullableHandle> {
668    /// Convert this HandleRef to one of a specific type.
669    pub fn cast<T: HandleBased>(self) -> Unowned<'a, T> {
670        // SAFETY: this function's guarantees are upheld by the self input.
671        unsafe { Unowned::from_raw_handle(self.raw_handle()) }
672    }
673}
674
675/// A trait to get a reference to the underlying handle of an object.
676pub trait AsHandleRef {
677    /// Get a reference to the handle. One important use of such a reference is
678    /// for `object_wait_many`.
679    fn as_handle_ref(&self) -> HandleRef<'_>;
680
681    /// Interpret the reference as a raw handle (an integer type). Two distinct
682    /// handles will have different raw values (so it can perhaps be used as a
683    /// key in a data structure).
684    fn raw_handle(&self) -> sys::zx_handle_t {
685        NullableHandle::raw_handle(&self.as_handle_ref())
686    }
687
688    /// Causes packet delivery on the given port when the object changes state and matches signals.
689    /// [zx_object_wait_async](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_async.md)
690    /// syscall.
691    fn wait_async_handle(
692        &self,
693        port: &Port,
694        key: u64,
695        signals: Signals,
696        options: WaitAsyncOpts,
697    ) -> Result<(), Status> {
698        NullableHandle::wait_async(&self.as_handle_ref(), port, key, signals, options)
699    }
700
701    /// Get the [Property::NAME] property for this object.
702    ///
703    /// Wraps a call to the
704    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
705    /// syscall for the ZX_PROP_NAME property.
706    fn get_name(&self) -> Result<Name, Status> {
707        NullableHandle::get_name(&self.as_handle_ref())
708    }
709
710    /// Set the [Property::NAME] property for this object.
711    ///
712    /// The name's length must be less than [sys::ZX_MAX_NAME_LEN], i.e.
713    /// name.[to_bytes_with_nul()](CStr::to_bytes_with_nul()).len() <= [sys::ZX_MAX_NAME_LEN], or
714    /// Err([Status::INVALID_ARGS]) will be returned.
715    ///
716    /// Wraps a call to the
717    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
718    /// syscall for the ZX_PROP_NAME property.
719    fn set_name(&self, name: &Name) -> Result<(), Status> {
720        NullableHandle::set_name(&self.as_handle_ref(), name)
721    }
722
723    /// Wraps the
724    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
725    /// syscall for the ZX_INFO_HANDLE_BASIC topic.
726    fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
727        NullableHandle::basic_info(&self.as_handle_ref())
728    }
729
730    /// Wraps the
731    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
732    /// syscall for the ZX_INFO_HANDLE_COUNT topic.
733    fn count_info(&self) -> Result<HandleCountInfo, Status> {
734        NullableHandle::count_info(&self.as_handle_ref())
735    }
736
737    /// Returns the koid (kernel object ID) for this handle.
738    fn get_koid(&self) -> Result<Koid, Status> {
739        NullableHandle::koid(&self.as_handle_ref())
740    }
741}
742
743impl<T: AsHandleRef> AsHandleRef for &T {
744    fn as_handle_ref(&self) -> HandleRef<'_> {
745        (*self).as_handle_ref()
746    }
747}
748
749/// A trait implemented by all handle-based types.
750///
751/// Note: it is reasonable for user-defined objects wrapping a handle to implement
752/// this trait. For example, a specific interface in some protocol might be
753/// represented as a newtype of `Channel`, and implement the `as_handle_ref`
754/// method and the `From<Handle>` trait to facilitate conversion from and to the
755/// interface.
756pub trait HandleBased: AsHandleRef + From<NullableHandle> + Into<NullableHandle> {
757    /// Duplicate a handle, possibly reducing the rights available. Wraps the
758    /// [zx_handle_duplicate](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_duplicate.md)
759    /// syscall.
760    fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
761        self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle))
762    }
763
764    /// Create a replacement for a handle, possibly reducing the rights available. This invalidates
765    /// the original handle. Wraps the
766    /// [zx_handle_replace](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace.md)
767    /// syscall.
768    fn replace_handle(self, rights: Rights) -> Result<Self, Status> {
769        <Self as Into<NullableHandle>>::into(self).replace(rights).map(|handle| Self::from(handle))
770    }
771
772    /// Converts the value into its inner handle.
773    ///
774    /// This is a convenience function which simply forwards to the `Into` trait.
775    fn into_handle(self) -> NullableHandle {
776        self.into()
777    }
778
779    /// Converts the handle into it's raw representation.
780    ///
781    /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak.
782    fn into_raw(self) -> sys::zx_handle_t {
783        self.into_handle().into_raw()
784    }
785
786    /// Creates an instance of this type from a handle.
787    ///
788    /// This is a convenience function which simply forwards to the `From` trait.
789    fn from_handle(handle: NullableHandle) -> Self {
790        Self::from(handle)
791    }
792
793    /// Creates an instance of another handle-based type from this value's inner handle.
794    fn into_handle_based<H: HandleBased>(self) -> H {
795        H::from_handle(self.into_handle())
796    }
797
798    /// Creates an instance of this type from the inner handle of another
799    /// handle-based type.
800    fn from_handle_based<H: HandleBased>(h: H) -> Self {
801        Self::from_handle(h.into_handle())
802    }
803
804    fn is_invalid_handle(&self) -> bool {
805        self.as_handle_ref().is_invalid()
806    }
807}
808
809/// A trait implemented by all handles for objects which have a peer.
810pub trait Peered: HandleBased {
811    /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
812    /// [zx_object_signal_peer][osp] syscall.
813    ///
814    /// [osp]: https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal_peer.md
815    fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
816        let handle = self.raw_handle();
817        let status =
818            unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) };
819        ok(status)
820    }
821
822    /// Returns true if the handle has received the `PEER_CLOSED` signal.
823    ///
824    /// # Errors
825    ///
826    /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
827    /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
828    /// errors are propagated.
829    fn is_closed(&self) -> Result<bool, Status> {
830        match self
831            .as_handle_ref()
832            .wait_one(Signals::OBJECT_PEER_CLOSED, MonotonicInstant::INFINITE_PAST)
833        {
834            WaitResult::Ok(signals) => Ok(signals.contains(Signals::OBJECT_PEER_CLOSED)),
835            WaitResult::TimedOut(_) => Ok(false),
836            WaitResult::Canceled(_) => Err(Status::CANCELED),
837            WaitResult::Err(e) => Err(e),
838        }
839    }
840}
841
842/// Basic information about a handle.
843///
844/// Wrapper for data returned from [Handle::basic_info()].
845#[derive(Debug, Copy, Clone, Eq, PartialEq)]
846pub struct HandleBasicInfo {
847    pub koid: Koid,
848    pub rights: Rights,
849    pub object_type: ObjectType,
850    pub related_koid: Koid,
851}
852
853impl Default for HandleBasicInfo {
854    fn default() -> Self {
855        Self::from(sys::zx_info_handle_basic_t::default())
856    }
857}
858
859impl From<sys::zx_info_handle_basic_t> for HandleBasicInfo {
860    fn from(info: sys::zx_info_handle_basic_t) -> Self {
861        let sys::zx_info_handle_basic_t { koid, rights, type_, related_koid, .. } = info;
862
863        // Note lossy conversion of Rights and HandleProperty here if either of those types are out
864        // of date or incomplete.
865        HandleBasicInfo {
866            koid: Koid::from_raw(koid),
867            rights: Rights::from_bits_truncate(rights),
868            object_type: ObjectType::from_raw(type_),
869            related_koid: Koid::from_raw(related_koid),
870        }
871    }
872}
873
874// zx_info_handle_basic_t is able to be safely replaced with a byte representation and is a PoD
875// type.
876struct HandleBasicInfoQuery;
877unsafe impl ObjectQuery for HandleBasicInfoQuery {
878    const TOPIC: Topic = Topic::HANDLE_BASIC;
879    type InfoTy = sys::zx_info_handle_basic_t;
880}
881
882sys::zx_info_handle_count_t!(HandleCountInfo);
883
884impl From<sys::zx_info_handle_count_t> for HandleCountInfo {
885    fn from(sys::zx_info_handle_count_t { handle_count }: sys::zx_info_handle_count_t) -> Self {
886        HandleCountInfo { handle_count }
887    }
888}
889
890// zx_info_handle_count_t is able to be safely replaced with a byte representation and is a PoD
891// type.
892struct HandleCountInfoQuery;
893unsafe impl ObjectQuery for HandleCountInfoQuery {
894    const TOPIC: Topic = Topic::HANDLE_COUNT;
895    type InfoTy = sys::zx_info_handle_count_t;
896}
897
898/// Handle operation.
899#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
900pub enum HandleOp<'a> {
901    Move(NullableHandle),
902    Duplicate(HandleRef<'a>),
903}
904
905/// Operation to perform on handles during write. ABI-compatible with `zx_handle_disposition_t`.
906#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
907#[repr(C)]
908pub struct HandleDisposition<'a> {
909    // Must be either ZX_HANDLE_OP_MOVE or ZX_HANDLE_OP_DUPLICATE.
910    operation: sys::zx_handle_op_t,
911    // ZX_HANDLE_OP_MOVE==owned, ZX_HANDLE_OP_DUPLICATE==borrowed.
912    handle: sys::zx_handle_t,
913    // Preserve a borrowed handle's lifetime. Does not occupy any layout.
914    _handle_lifetime: std::marker::PhantomData<&'a ()>,
915
916    pub object_type: ObjectType,
917    pub rights: Rights,
918    pub result: Status,
919}
920
921static_assertions::assert_eq_size!(HandleDisposition<'_>, sys::zx_handle_disposition_t);
922static_assertions::const_assert_eq!(
923    std::mem::offset_of!(HandleDisposition<'_>, operation),
924    std::mem::offset_of!(sys::zx_handle_disposition_t, operation)
925);
926static_assertions::const_assert_eq!(
927    std::mem::offset_of!(HandleDisposition<'_>, handle),
928    std::mem::offset_of!(sys::zx_handle_disposition_t, handle)
929);
930static_assertions::const_assert_eq!(
931    std::mem::offset_of!(HandleDisposition<'_>, object_type),
932    std::mem::offset_of!(sys::zx_handle_disposition_t, type_)
933);
934static_assertions::const_assert_eq!(
935    std::mem::offset_of!(HandleDisposition<'_>, rights),
936    std::mem::offset_of!(sys::zx_handle_disposition_t, rights)
937);
938static_assertions::const_assert_eq!(
939    std::mem::offset_of!(HandleDisposition<'_>, result),
940    std::mem::offset_of!(sys::zx_handle_disposition_t, result)
941);
942
943impl<'a> HandleDisposition<'a> {
944    #[inline]
945    pub fn new(
946        handle_op: HandleOp<'a>,
947        object_type: ObjectType,
948        rights: Rights,
949        status: Status,
950    ) -> Self {
951        let (operation, handle) = match handle_op {
952            HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
953            HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
954        };
955
956        Self {
957            operation,
958            handle,
959            _handle_lifetime: std::marker::PhantomData,
960            object_type,
961            rights: rights,
962            result: status,
963        }
964    }
965
966    pub fn raw_handle(&self) -> sys::zx_handle_t {
967        self.handle
968    }
969
970    pub fn is_move(&self) -> bool {
971        self.operation == sys::ZX_HANDLE_OP_MOVE
972    }
973
974    pub fn is_duplicate(&self) -> bool {
975        self.operation == sys::ZX_HANDLE_OP_DUPLICATE
976    }
977
978    pub fn take_op(&mut self) -> HandleOp<'a> {
979        match self.operation {
980            sys::ZX_HANDLE_OP_MOVE => {
981                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
982                // type's public API and the kernel's guarantees.
983                HandleOp::Move(unsafe {
984                    NullableHandle::from_raw(std::mem::replace(
985                        &mut self.handle,
986                        sys::ZX_HANDLE_INVALID,
987                    ))
988                })
989            }
990            sys::ZX_HANDLE_OP_DUPLICATE => {
991                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
992                // type's public API and the kernel's guarantees.
993                HandleOp::Duplicate(Unowned {
994                    inner: ManuallyDrop::new(unsafe { NullableHandle::from_raw(self.handle) }),
995                    marker: PhantomData,
996                })
997            }
998            _ => unreachable!(),
999        }
1000    }
1001
1002    pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
1003        match self.take_op() {
1004            HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
1005                operation: sys::ZX_HANDLE_OP_MOVE,
1006                handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
1007                type_: self.object_type.into_raw(),
1008                rights: self.rights.bits(),
1009                result: self.result.into_raw(),
1010            },
1011            HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
1012                operation: sys::ZX_HANDLE_OP_DUPLICATE,
1013                handle: handle_ref.raw_handle(),
1014                type_: self.object_type.into_raw(),
1015                rights: self.rights.bits(),
1016                result: self.result.into_raw(),
1017            },
1018        }
1019    }
1020}
1021
1022impl<'a> Drop for HandleDisposition<'a> {
1023    fn drop(&mut self) {
1024        // Ensure we clean up owned handle variants.
1025        if self.operation == sys::ZX_HANDLE_OP_MOVE {
1026            unsafe { drop(NullableHandle::from_raw(self.handle)) };
1027        }
1028    }
1029}
1030
1031/// Information on handles that were read.
1032///
1033/// ABI-compatible with zx_handle_info_t.
1034#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1035#[repr(C)]
1036pub struct HandleInfo {
1037    pub handle: NullableHandle,
1038    pub object_type: ObjectType,
1039    pub rights: Rights,
1040
1041    // Necessary for ABI compatibility with zx_handle_info_t.
1042    pub(crate) _unused: u32,
1043}
1044
1045static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
1046static_assertions::const_assert_eq!(
1047    std::mem::offset_of!(HandleInfo, handle),
1048    std::mem::offset_of!(sys::zx_handle_info_t, handle)
1049);
1050static_assertions::const_assert_eq!(
1051    std::mem::offset_of!(HandleInfo, object_type),
1052    std::mem::offset_of!(sys::zx_handle_info_t, ty)
1053);
1054static_assertions::const_assert_eq!(
1055    std::mem::offset_of!(HandleInfo, rights),
1056    std::mem::offset_of!(sys::zx_handle_info_t, rights)
1057);
1058static_assertions::const_assert_eq!(
1059    std::mem::offset_of!(HandleInfo, _unused),
1060    std::mem::offset_of!(sys::zx_handle_info_t, unused)
1061);
1062
1063impl HandleInfo {
1064    /// Make a new `HandleInfo`.
1065    pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
1066        Self { handle, object_type, rights, _unused: 0 }
1067    }
1068
1069    /// # Safety
1070    ///
1071    /// See [`Handle::from_raw`] for requirements about the validity and closing
1072    /// of `raw.handle`.
1073    ///
1074    /// Note that while `raw.ty` _should_ correspond to the type of the handle,
1075    /// that this is not required for safety.
1076    pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
1077        HandleInfo::new(
1078            // SAFETY: invariants to not double-close are upheld by the caller.
1079            unsafe { NullableHandle::from_raw(raw.handle) },
1080            ObjectType::from_raw(raw.ty),
1081            Rights::from_bits_retain(raw.rights),
1082        )
1083    }
1084}
1085
1086#[cfg(test)]
1087mod tests {
1088    use super::*;
1089    // The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
1090    // zx::Vmar that we need to use.
1091    use zx::{
1092        AsHandleRef, Channel, HandleBased, HandleDisposition, HandleInfo, HandleOp, Name,
1093        NullableHandle, ObjectType, Rights, Vmo,
1094    };
1095    use zx_sys as sys;
1096
1097    #[test]
1098    fn into_raw() {
1099        let vmo = Vmo::create(1).unwrap();
1100        let h = vmo.into_raw();
1101        let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
1102        assert!(vmo2.write(b"1", 0).is_ok());
1103    }
1104
1105    #[test]
1106    fn check_raw_valid() {
1107        assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
1108        let vmo = Vmo::create(1).unwrap();
1109        let vmo_raw = vmo.raw_handle();
1110        assert!(Handle::check_raw_valid(vmo_raw).is_ok());
1111        drop(vmo);
1112        assert!(Handle::check_raw_valid(vmo_raw).is_err());
1113    }
1114
1115    /// Test duplication by means of a VMO
1116    #[test]
1117    fn duplicate() {
1118        let hello_length: usize = 5;
1119
1120        // Create a VMO and write some data to it.
1121        let vmo = Vmo::create(hello_length as u64).unwrap();
1122        assert!(vmo.write(b"hello", 0).is_ok());
1123
1124        // Replace, reducing rights to read.
1125        let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
1126        // Make sure we can read but not write.
1127        let mut read_vec = vec![0; hello_length];
1128        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1129        assert_eq!(read_vec, b"hello");
1130        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1131
1132        // Write new data to the original handle, and read it from the new handle
1133        assert!(vmo.write(b"bye", 0).is_ok());
1134        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1135        assert_eq!(read_vec, b"byelo");
1136    }
1137
1138    // Test replace by means of a VMO
1139    #[test]
1140    fn replace() {
1141        let hello_length: usize = 5;
1142
1143        // Create a VMO and write some data to it.
1144        let vmo = Vmo::create(hello_length as u64).unwrap();
1145        assert!(vmo.write(b"hello", 0).is_ok());
1146
1147        // Replace, reducing rights to read.
1148        let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
1149        // Make sure we can read but not write.
1150        let mut read_vec = vec![0; hello_length];
1151        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1152        assert_eq!(read_vec, b"hello");
1153        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1154    }
1155
1156    #[test]
1157    fn set_get_name() {
1158        // We need some concrete object to exercise the AsHandleRef<'_> set/get_name functions.
1159        let vmo = Vmo::create(1).unwrap();
1160        let short_name = Name::new("v").unwrap();
1161        assert!(vmo.set_name(&short_name).is_ok());
1162        assert_eq!(vmo.get_name().unwrap(), short_name);
1163    }
1164
1165    #[test]
1166    fn set_get_max_len_name() {
1167        let vmo = Vmo::create(1).unwrap();
1168        let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); // 31 bytes
1169        assert!(vmo.set_name(&max_len_name).is_ok());
1170        assert_eq!(vmo.get_name().unwrap(), max_len_name);
1171    }
1172
1173    #[test]
1174    fn basic_info_channel() {
1175        let (side1, side2) = Channel::create();
1176        let info1 = side1.basic_info().expect("side1 basic_info failed");
1177        let info2 = side2.basic_info().expect("side2 basic_info failed");
1178
1179        assert_eq!(info1.koid, info2.related_koid);
1180        assert_eq!(info2.koid, info1.related_koid);
1181
1182        for info in &[info1, info2] {
1183            assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
1184            assert_eq!(info.object_type, ObjectType::CHANNEL);
1185            assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
1186        }
1187
1188        let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
1189        let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
1190        assert_eq!(info1_repl.koid, info1.koid);
1191        assert_eq!(info1_repl.rights, Rights::READ);
1192    }
1193
1194    #[test]
1195    fn basic_info_vmar() {
1196        // VMARs aren't waitable.
1197        let root_vmar = fuchsia_runtime::vmar_root_self();
1198        let info = root_vmar.basic_info().expect("vmar basic_info failed");
1199        assert_eq!(info.object_type, ObjectType::VMAR);
1200        assert!(!info.rights.contains(Rights::WAIT));
1201    }
1202
1203    #[test]
1204    fn count_info() {
1205        let vmo0 = Vmo::create(1).unwrap();
1206        let count_info = vmo0.count_info().expect("vmo0 count_info failed");
1207        assert_eq!(count_info.handle_count, 1);
1208
1209        let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
1210        let count_info = vmo1.count_info().expect("vmo1 count_info failed");
1211        assert_eq!(count_info.handle_count, 2);
1212    }
1213
1214    #[test]
1215    fn raw_handle_disposition() {
1216        const RAW_HANDLE: sys::zx_handle_t = 1;
1217        let hd = HandleDisposition::new(
1218            HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
1219            ObjectType::VMO,
1220            Rights::EXECUTE,
1221            Status::OK,
1222        );
1223        let raw_hd = hd.into_raw();
1224        assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
1225        assert_eq!(raw_hd.handle, RAW_HANDLE);
1226        assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
1227        assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
1228        assert_eq!(raw_hd.result, sys::ZX_OK);
1229    }
1230
1231    #[test]
1232    fn regression_nullable_handle_into_raw_recursion() {
1233        let h = NullableHandle::invalid();
1234        // This should not stack overflow
1235        assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
1236
1237        let vmo = Vmo::create(1).unwrap();
1238        let raw = vmo.raw_handle();
1239        let h = vmo.into_handle();
1240        // This should not stack overflow
1241        assert_eq!(h.into_raw(), raw);
1242    }
1243
1244    #[test]
1245    fn handle_info_from_raw() {
1246        const RAW_HANDLE: sys::zx_handle_t = 1;
1247        let raw_hi = sys::zx_handle_info_t {
1248            handle: RAW_HANDLE,
1249            ty: sys::ZX_OBJ_TYPE_VMO,
1250            rights: sys::ZX_RIGHT_EXECUTE,
1251            unused: 128,
1252        };
1253        let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1254        assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1255        assert_eq!(hi.object_type, ObjectType::VMO);
1256        assert_eq!(hi.rights, Rights::EXECUTE);
1257    }
1258
1259    #[test]
1260    fn basic_peer_closed() {
1261        let (lhs, rhs) = crate::EventPair::create();
1262        assert!(!lhs.is_closed().unwrap());
1263        assert!(!rhs.is_closed().unwrap());
1264        drop(rhs);
1265        assert!(lhs.is_closed().unwrap());
1266    }
1267}