1use crate::{
8 Koid, MonotonicInstant, Name, ObjectQuery, ObjectType, Port, Property, PropertyQuery, Rights,
9 Signals, Status, Topic, WaitAsyncOpts, WaitItem, ok, sys,
10};
11use std::marker::PhantomData;
12use std::mem::{ManuallyDrop, MaybeUninit};
13use std::num::NonZeroU32;
14use zerocopy::{FromBytes, Immutable, IntoBytes};
15
16pub(crate) const INFO_VEC_SIZE_INITIAL: usize = 16;
18
19#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
37#[repr(transparent)]
38pub struct Handle(NonZeroU32);
39
40static_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 pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Option<Self> {
58 let inner = NonZeroU32::new(raw)?;
59 debug_assert!(Self::check_raw_valid(raw).is_ok());
60 Some(Self(inner))
61 }
62
63 pub unsafe fn from_raw_unchecked(raw: sys::zx_handle_t) -> Self {
70 debug_assert!(Self::check_raw_valid(raw).is_ok());
71 Self(unsafe { NonZeroU32::new_unchecked(raw) })
73 }
74
75 #[doc(hidden)]
78 pub fn poison() -> Self {
79 Self(unsafe { NonZeroU32::new_unchecked(1) })
80 }
81
82 #[doc(hidden)]
83 pub fn is_poison(&self) -> bool {
84 (self.0.get() & sys::ZX_HANDLE_FIXED_BITS_MASK) != sys::ZX_HANDLE_FIXED_BITS_MASK
92 }
93
94 pub fn check_raw_valid(raw: sys::zx_handle_t) -> Result<(), Status> {
101 ok(unsafe { sys::zx_handle_check_valid(raw) })
103 }
104
105 pub const fn raw_handle(&self) -> sys::zx_handle_t {
107 self.0.get()
108 }
109
110 pub fn into_raw(self) -> sys::zx_handle_t {
112 let ret = self.0.get();
113 std::mem::forget(self);
114 ret
115 }
116
117 pub fn duplicate(&self, rights: Rights) -> Result<Self, Status> {
121 let mut out = 0;
122 let status =
124 unsafe { sys::zx_handle_duplicate(self.raw_handle(), rights.bits(), &mut out) };
125 ok(status)?;
126
127 Ok(unsafe { Self::from_raw_unchecked(out) })
129 }
130
131 pub fn replace(self, rights: Rights) -> Result<Self, Status> {
135 let mut out = 0;
136
137 let status = unsafe { sys::zx_handle_replace(self.into_raw(), rights.bits(), &mut out) };
139 ok(status)?;
140
141 unsafe { Ok(Self::from_raw_unchecked(out)) }
143 }
144
145 pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
147 ok(unsafe { sys::zx_object_signal(self.raw_handle(), clear_mask.bits(), set_mask.bits()) })
149 }
150
151 pub fn wait_one(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
154 let mut pending = Signals::empty().bits();
155 let status = unsafe {
157 sys::zx_object_wait_one(
158 self.raw_handle(),
159 signals.bits(),
160 deadline.into_nanos(),
161 &mut pending,
162 )
163 };
164 let signals = Signals::from_bits_truncate(pending);
165 match ok(status) {
166 Ok(()) => WaitResult::Ok(signals),
167 Err(Status::TIMED_OUT) => WaitResult::TimedOut(signals),
168 Err(Status::CANCELED) => WaitResult::Canceled(signals),
169 Err(e) => WaitResult::Err(e),
170 }
171 }
172
173 pub fn wait_async(
176 &self,
177 port: &Port,
178 key: u64,
179 signals: Signals,
180 options: WaitAsyncOpts,
181 ) -> Result<(), Status> {
182 ok(unsafe {
184 sys::zx_object_wait_async(
185 self.raw_handle(),
186 port.raw_handle(),
187 key,
188 signals.bits(),
189 options.bits(),
190 )
191 })
192 }
193
194 pub fn wait_item(&self, signals: Signals) -> WaitItem<'_> {
197 WaitItem::new(self.as_handle_ref(), signals)
198 }
199
200 pub fn get_name(&self) -> Result<Name, Status> {
206 self.get_property::<NameProperty>()
207 }
208
209 pub fn set_name(&self, name: &Name) -> Result<(), Status> {
219 self.set_property::<NameProperty>(&name)
220 }
221
222 pub(crate) fn get_property<P: PropertyQuery>(&self) -> Result<P::PropTy, Status>
224 where
225 P::PropTy: FromBytes + Immutable,
226 {
227 let mut out = ::std::mem::MaybeUninit::<P::PropTy>::uninit();
228
229 let status = unsafe {
231 sys::zx_object_get_property(
232 self.raw_handle(),
233 *P::PROPERTY,
234 out.as_mut_ptr().cast::<u8>(),
235 std::mem::size_of::<P::PropTy>(),
236 )
237 };
238 Status::ok(status).map(|_| unsafe { out.assume_init() })
239 }
240
241 pub(crate) fn set_property<P: PropertyQuery>(&self, val: &P::PropTy) -> Result<(), Status>
243 where
244 P::PropTy: IntoBytes + Immutable,
245 {
246 let status = unsafe {
247 sys::zx_object_set_property(
248 self.raw_handle(),
249 *P::PROPERTY,
250 std::ptr::from_ref(val).cast::<u8>(),
251 std::mem::size_of::<P::PropTy>(),
252 )
253 };
254 Status::ok(status)
255 }
256
257 pub fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
261 Ok(HandleBasicInfo::from(self.get_info_single::<HandleBasicInfoQuery>()?))
262 }
263
264 pub fn count_info(&self) -> Result<HandleCountInfo, Status> {
268 Ok(HandleCountInfo::from(self.get_info_single::<HandleCountInfoQuery>()?))
269 }
270
271 pub fn koid(&self) -> Result<Koid, Status> {
273 self.basic_info().map(|info| info.koid)
274 }
275
276 pub(crate) fn get_info<'a, Q: ObjectQuery>(
279 &self,
280 out: &'a mut [MaybeUninit<Q::InfoTy>],
281 ) -> Result<(&'a mut [Q::InfoTy], &'a mut [MaybeUninit<Q::InfoTy>], usize), Status>
282 where
283 Q::InfoTy: FromBytes + Immutable,
284 {
285 let mut actual = 0;
286 let mut avail = 0;
287
288 let status = unsafe {
291 sys::zx_object_get_info(
292 self.raw_handle(),
293 *Q::TOPIC,
294 out.as_mut_ptr().cast::<u8>(),
295 std::mem::size_of_val(out),
296 &mut actual,
297 &mut avail,
298 )
299 };
300 ok(status)?;
301
302 let (initialized, uninit) = out.split_at_mut(actual);
303
304 let initialized: &mut [Q::InfoTy] = unsafe {
308 std::slice::from_raw_parts_mut(
309 initialized.as_mut_ptr().cast::<Q::InfoTy>(),
310 initialized.len(),
311 )
312 };
313
314 Ok((initialized, uninit, avail))
315 }
316
317 pub(crate) fn get_info_single<Q: ObjectQuery>(&self) -> Result<Q::InfoTy, Status>
319 where
320 Q::InfoTy: Copy + FromBytes + Immutable,
321 {
322 let mut info = MaybeUninit::<Q::InfoTy>::uninit();
323 let (info, _uninit, _avail) = self.get_info::<Q>(std::slice::from_mut(&mut info))?;
324 Ok(info[0])
325 }
326
327 pub(crate) fn get_info_vec<Q: ObjectQuery>(&self) -> Result<Vec<Q::InfoTy>, Status> {
331 let mut out = Vec::<Q::InfoTy>::with_capacity(INFO_VEC_SIZE_INITIAL);
333 loop {
334 let (init, _uninit, avail) = self.get_info::<Q>(out.spare_capacity_mut())?;
335 let num_initialized = init.len();
336 if num_initialized == avail {
337 unsafe { out.set_len(num_initialized) };
339 return Ok(out);
340 } else {
341 if avail > out.capacity() {
342 out.reserve_exact(avail - out.len());
343 }
344 }
345 }
346 }
347}
348
349impl AsHandleRef for Handle {
350 fn as_handle_ref(&self) -> HandleRef<'_> {
351 unsafe { Unowned::from_raw_handle(self.raw_handle()) }
353 }
354}
355
356impl Drop for Handle {
357 fn drop(&mut self) {
358 if !self.is_poison() {
359 unsafe { sys::zx_handle_close(self.0.get()) };
361 }
362 }
363}
364
365#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
378#[repr(transparent)]
379pub struct NullableHandle(Option<Handle>);
380
381impl AsHandleRef for NullableHandle {
382 fn as_handle_ref(&self) -> HandleRef<'_> {
383 if let Some(inner) = &self.0 {
384 unsafe { Unowned::from_raw_handle(inner.raw_handle()) }
386 } else {
387 unsafe { Unowned::from_raw_handle(sys::ZX_HANDLE_INVALID) }
389 }
390 }
391}
392
393impl NullableHandle {
394 #[inline(always)]
396 pub const fn invalid() -> Self {
397 Self(None)
398 }
399
400 pub const unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
412 if let Some(inner) = NonZeroU32::new(raw) { Self(Some(Handle(inner))) } else { Self(None) }
416 }
417
418 pub const fn raw_handle(&self) -> sys::zx_handle_t {
419 if let Some(inner) = &self.0 { inner.raw_handle() } else { sys::ZX_HANDLE_INVALID }
420 }
421
422 pub fn into_raw(self) -> sys::zx_handle_t {
423 self.0.map(Handle::into_raw).unwrap_or(sys::ZX_HANDLE_INVALID)
424 }
425
426 pub fn as_handle_ref(&self) -> HandleRef<'_> {
427 AsHandleRef::as_handle_ref(self)
428 }
429
430 pub const fn is_invalid(&self) -> bool {
431 self.0.is_none()
432 }
433
434 pub fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
435 self.0
436 .as_ref()
437 .map(|h| h.duplicate(rights).map(|new| Self(Some(new))))
438 .unwrap_or(Err(Status::BAD_HANDLE))
439 }
440
441 pub fn replace_handle(mut self, rights: Rights) -> Result<Self, Status> {
442 if let Some(inner) = self.0.take() {
443 let inner = inner.replace(rights)?;
444 Ok(Self(Some(inner)))
445 } else {
446 Ok(Self(None))
447 }
448 }
449
450 pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
451 self.0.as_ref().map(|h| h.signal(clear_mask, set_mask)).unwrap_or(Err(Status::BAD_HANDLE))
452 }
453
454 pub fn wait_one(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
455 self.0
456 .as_ref()
457 .map(|h| h.wait_one(signals, deadline))
458 .unwrap_or(WaitResult::Err(Status::BAD_HANDLE))
459 }
460
461 pub fn wait_async(
462 &self,
463 port: &Port,
464 key: u64,
465 signals: Signals,
466 options: WaitAsyncOpts,
467 ) -> Result<(), Status> {
468 self.0
469 .as_ref()
470 .map(|h| h.wait_async(port, key, signals, options))
471 .unwrap_or(Err(Status::BAD_HANDLE))
472 }
473
474 pub fn wait_item(&self, signals: Signals) -> WaitItem<'_> {
475 WaitItem::new(self.as_handle_ref(), signals)
476 }
477
478 pub fn get_name(&self) -> Result<Name, Status> {
479 self.0.as_ref().map(Handle::get_name).unwrap_or(Err(Status::BAD_HANDLE))
480 }
481
482 pub fn set_name(&self, name: &Name) -> Result<(), Status> {
483 self.0.as_ref().map(|h| h.set_name(name)).unwrap_or(Err(Status::BAD_HANDLE))
484 }
485
486 pub fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
487 self.0.as_ref().map(Handle::basic_info).unwrap_or(Err(Status::BAD_HANDLE))
488 }
489
490 pub fn count_info(&self) -> Result<HandleCountInfo, Status> {
491 self.0.as_ref().map(Handle::count_info).unwrap_or(Err(Status::BAD_HANDLE))
492 }
493
494 pub fn koid(&self) -> Result<Koid, Status> {
495 self.0.as_ref().map(Handle::koid).unwrap_or(Err(Status::BAD_HANDLE))
496 }
497
498 pub(crate) fn get_info<'a, Q: ObjectQuery>(
499 &self,
500 out: &'a mut [MaybeUninit<Q::InfoTy>],
501 ) -> Result<(&'a mut [Q::InfoTy], &'a mut [MaybeUninit<Q::InfoTy>], usize), Status>
502 where
503 Q::InfoTy: FromBytes + Immutable,
504 {
505 self.0.as_ref().map(|h| h.get_info::<Q>(out)).unwrap_or(Err(Status::BAD_HANDLE))
506 }
507
508 pub(crate) fn get_info_single<Q: ObjectQuery>(&self) -> Result<Q::InfoTy, Status>
509 where
510 Q::InfoTy: Copy + FromBytes + Immutable,
511 {
512 self.0.as_ref().map(|h| h.get_info_single::<Q>()).unwrap_or(Err(Status::BAD_HANDLE))
513 }
514
515 pub(crate) fn get_info_vec<Q: ObjectQuery>(&self) -> Result<Vec<Q::InfoTy>, Status> {
516 self.0.as_ref().map(|h| h.get_info_vec::<Q>()).unwrap_or(Err(Status::BAD_HANDLE))
517 }
518
519 pub(crate) fn get_property<P: PropertyQuery>(&self) -> Result<P::PropTy, Status>
520 where
521 P::PropTy: FromBytes + Immutable,
522 {
523 self.0.as_ref().map(|h| h.get_property::<P>()).unwrap_or(Err(Status::BAD_HANDLE))
524 }
525
526 pub(crate) fn set_property<P: PropertyQuery>(&self, val: &P::PropTy) -> Result<(), Status>
527 where
528 P::PropTy: IntoBytes + Immutable,
529 {
530 self.0.as_ref().map(|h| h.set_property::<P>(val)).unwrap_or(Err(Status::BAD_HANDLE))
531 }
532}
533
534impl From<Handle> for NullableHandle {
535 fn from(h: Handle) -> Self {
536 Self(Some(h))
537 }
538}
539
540impl From<Option<Handle>> for NullableHandle {
541 fn from(h: Option<Handle>) -> Self {
542 Self(h)
543 }
544}
545
546impl TryFrom<NullableHandle> for Handle {
547 type Error = Status;
548 fn try_from(h: NullableHandle) -> Result<Self, Self::Error> {
549 h.0.ok_or(Status::BAD_HANDLE)
550 }
551}
552
553struct NameProperty();
554unsafe impl PropertyQuery for NameProperty {
555 const PROPERTY: Property = Property::NAME;
556 type PropTy = Name;
559}
560
561#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
565#[repr(transparent)]
566pub struct Unowned<'a, T> {
567 inner: ManuallyDrop<T>,
568 marker: PhantomData<&'a T>,
569}
570
571static_assertions::assert_eq_size!(Unowned<'static, Handle>, sys::zx_handle_t);
573static_assertions::assert_eq_align!(Unowned<'static, Handle>, sys::zx_handle_t);
574static_assertions::assert_eq_size!(Option<Unowned<'static, Handle>>, sys::zx_handle_t);
575static_assertions::assert_eq_align!(Option<Unowned<'static, Handle>>, sys::zx_handle_t);
576
577impl<'a, T> std::ops::Deref for Unowned<'a, T> {
578 type Target = T;
579
580 fn deref(&self) -> &Self::Target {
581 &*self.inner
582 }
583}
584
585impl<'a, T: AsHandleRef> AsHandleRef for Unowned<'a, T> {
586 fn as_handle_ref(&self) -> HandleRef<'_> {
587 self.inner.as_handle_ref()
588 }
589}
590
591impl<T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>> Clone for Unowned<'_, T> {
592 fn clone(&self) -> Self {
593 unsafe { Self::from_raw_handle(self.inner.as_handle_ref().raw_handle()) }
594 }
595}
596
597pub type HandleRef<'a> = Unowned<'a, NullableHandle>;
598
599impl<'a, T: Into<NullableHandle>> Unowned<'a, T> {
600 pub fn new<U: AsHandleRef + From<NullableHandle>>(inner: &'a U) -> Self
604 where
605 T: From<U>,
606 {
607 Unowned {
610 inner: ManuallyDrop::new(T::from(U::from(unsafe {
611 NullableHandle::from_raw(inner.as_handle_ref().raw_handle())
612 }))),
613 marker: PhantomData,
614 }
615 }
616}
617
618impl<'a, T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>> Unowned<'a, T> {
619 pub unsafe fn from_raw_handle(handle: sys::zx_handle_t) -> Self {
631 Unowned {
632 inner: ManuallyDrop::new(T::from(unsafe { NullableHandle::from_raw(handle) })),
633 marker: PhantomData,
634 }
635 }
636
637 pub fn raw_handle(&self) -> sys::zx_handle_t {
639 NullableHandle::raw_handle(&*self.inner.as_handle_ref())
640 }
641}
642
643#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
649pub enum WaitResult {
650 Ok(Signals),
652
653 TimedOut(Signals),
657
658 Canceled(Signals),
665
666 Err(Status),
669}
670
671impl WaitResult {
672 pub const fn to_result(self) -> Result<Signals, Status> {
675 match self {
676 WaitResult::Ok(signals) => Ok(signals),
677 WaitResult::TimedOut(_signals) => Err(Status::TIMED_OUT),
678 WaitResult::Canceled(_signals) => Err(Status::CANCELED),
679 WaitResult::Err(status) => Err(status),
680 }
681 }
682
683 #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
688 #[inline]
689 pub const fn is_ok(&self) -> bool {
690 self.to_result().is_ok()
691 }
692
693 #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
694 #[inline]
695 pub const fn is_err(&self) -> bool {
696 self.to_result().is_err()
697 }
698
699 #[inline]
700 pub fn map<U, F: FnOnce(Signals) -> U>(self, op: F) -> Result<U, Status> {
701 self.to_result().map(op)
702 }
703
704 #[inline]
705 pub fn map_err<F, O: FnOnce(Status) -> F>(self, op: O) -> Result<Signals, F> {
706 self.to_result().map_err(op)
707 }
708
709 #[inline]
710 #[track_caller]
711 pub fn expect(self, msg: &str) -> Signals {
712 self.to_result().expect(msg)
713 }
714
715 #[inline]
716 #[track_caller]
717 pub fn expect_err(self, msg: &str) -> Status {
718 self.to_result().expect_err(msg)
719 }
720
721 #[inline(always)]
722 #[track_caller]
723 pub fn unwrap(self) -> Signals {
724 self.to_result().unwrap()
725 }
726}
727
728impl<'a> Unowned<'a, NullableHandle> {
729 pub fn cast<T: AsHandleRef + From<NullableHandle> + Into<NullableHandle>>(
731 self,
732 ) -> Unowned<'a, T> {
733 unsafe { Unowned::from_raw_handle(self.raw_handle()) }
735 }
736}
737
738pub trait AsHandleRef {
740 fn as_handle_ref(&self) -> HandleRef<'_>;
743}
744
745impl<T: AsHandleRef> AsHandleRef for &T {
746 fn as_handle_ref(&self) -> HandleRef<'_> {
747 (*self).as_handle_ref()
748 }
749}
750
751pub trait Peered: AsHandleRef {
753 fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
758 let handle = self.as_handle_ref().raw_handle();
759 let status =
760 unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) };
761 ok(status)
762 }
763
764 fn is_closed(&self) -> Result<bool, Status> {
772 match self
773 .as_handle_ref()
774 .wait_one(Signals::OBJECT_PEER_CLOSED, MonotonicInstant::INFINITE_PAST)
775 {
776 WaitResult::Ok(signals) => Ok(signals.contains(Signals::OBJECT_PEER_CLOSED)),
777 WaitResult::TimedOut(_) => Ok(false),
778 WaitResult::Canceled(_) => Err(Status::CANCELED),
779 WaitResult::Err(e) => Err(e),
780 }
781 }
782}
783
784#[derive(Debug, Copy, Clone, Eq, PartialEq)]
788pub struct HandleBasicInfo {
789 pub koid: Koid,
790 pub rights: Rights,
791 pub object_type: ObjectType,
792 pub related_koid: Koid,
793}
794
795impl Default for HandleBasicInfo {
796 fn default() -> Self {
797 Self::from(sys::zx_info_handle_basic_t::default())
798 }
799}
800
801impl From<sys::zx_info_handle_basic_t> for HandleBasicInfo {
802 fn from(info: sys::zx_info_handle_basic_t) -> Self {
803 let sys::zx_info_handle_basic_t { koid, rights, type_, related_koid, .. } = info;
804
805 HandleBasicInfo {
808 koid: Koid::from_raw(koid),
809 rights: Rights::from_bits_truncate(rights),
810 object_type: ObjectType::from_raw(type_),
811 related_koid: Koid::from_raw(related_koid),
812 }
813 }
814}
815
816struct HandleBasicInfoQuery;
819unsafe impl ObjectQuery for HandleBasicInfoQuery {
820 const TOPIC: Topic = Topic::HANDLE_BASIC;
821 type InfoTy = sys::zx_info_handle_basic_t;
822}
823
824sys::zx_info_handle_count_t!(HandleCountInfo);
825
826impl From<sys::zx_info_handle_count_t> for HandleCountInfo {
827 fn from(sys::zx_info_handle_count_t { handle_count }: sys::zx_info_handle_count_t) -> Self {
828 HandleCountInfo { handle_count }
829 }
830}
831
832struct HandleCountInfoQuery;
835unsafe impl ObjectQuery for HandleCountInfoQuery {
836 const TOPIC: Topic = Topic::HANDLE_COUNT;
837 type InfoTy = sys::zx_info_handle_count_t;
838}
839
840#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
842pub enum HandleOp<'a> {
843 Move(NullableHandle),
844 Duplicate(HandleRef<'a>),
845}
846
847#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
849#[repr(C)]
850pub struct HandleDisposition<'a> {
851 operation: sys::zx_handle_op_t,
853 handle: sys::zx_handle_t,
855 _handle_lifetime: std::marker::PhantomData<&'a ()>,
857
858 pub object_type: ObjectType,
859 pub rights: Rights,
860 pub result: Status,
861}
862
863static_assertions::assert_eq_size!(HandleDisposition<'_>, sys::zx_handle_disposition_t);
864static_assertions::const_assert_eq!(
865 std::mem::offset_of!(HandleDisposition<'_>, operation),
866 std::mem::offset_of!(sys::zx_handle_disposition_t, operation)
867);
868static_assertions::const_assert_eq!(
869 std::mem::offset_of!(HandleDisposition<'_>, handle),
870 std::mem::offset_of!(sys::zx_handle_disposition_t, handle)
871);
872static_assertions::const_assert_eq!(
873 std::mem::offset_of!(HandleDisposition<'_>, object_type),
874 std::mem::offset_of!(sys::zx_handle_disposition_t, type_)
875);
876static_assertions::const_assert_eq!(
877 std::mem::offset_of!(HandleDisposition<'_>, rights),
878 std::mem::offset_of!(sys::zx_handle_disposition_t, rights)
879);
880static_assertions::const_assert_eq!(
881 std::mem::offset_of!(HandleDisposition<'_>, result),
882 std::mem::offset_of!(sys::zx_handle_disposition_t, result)
883);
884
885impl<'a> HandleDisposition<'a> {
886 #[inline]
887 pub fn new(
888 handle_op: HandleOp<'a>,
889 object_type: ObjectType,
890 rights: Rights,
891 status: Status,
892 ) -> Self {
893 let (operation, handle) = match handle_op {
894 HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
895 HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
896 };
897
898 Self {
899 operation,
900 handle,
901 _handle_lifetime: std::marker::PhantomData,
902 object_type,
903 rights: rights,
904 result: status,
905 }
906 }
907
908 pub fn raw_handle(&self) -> sys::zx_handle_t {
909 self.handle
910 }
911
912 pub fn is_move(&self) -> bool {
913 self.operation == sys::ZX_HANDLE_OP_MOVE
914 }
915
916 pub fn is_duplicate(&self) -> bool {
917 self.operation == sys::ZX_HANDLE_OP_DUPLICATE
918 }
919
920 pub fn take_op(&mut self) -> HandleOp<'a> {
921 match self.operation {
922 sys::ZX_HANDLE_OP_MOVE => {
923 HandleOp::Move(unsafe {
926 NullableHandle::from_raw(std::mem::replace(
927 &mut self.handle,
928 sys::ZX_HANDLE_INVALID,
929 ))
930 })
931 }
932 sys::ZX_HANDLE_OP_DUPLICATE => {
933 HandleOp::Duplicate(Unowned {
936 inner: ManuallyDrop::new(unsafe { NullableHandle::from_raw(self.handle) }),
937 marker: PhantomData,
938 })
939 }
940 _ => unreachable!(),
941 }
942 }
943
944 pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
945 match self.take_op() {
946 HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
947 operation: sys::ZX_HANDLE_OP_MOVE,
948 handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
949 type_: self.object_type.into_raw(),
950 rights: self.rights.bits(),
951 result: self.result.into_raw(),
952 },
953 HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
954 operation: sys::ZX_HANDLE_OP_DUPLICATE,
955 handle: handle_ref.raw_handle(),
956 type_: self.object_type.into_raw(),
957 rights: self.rights.bits(),
958 result: self.result.into_raw(),
959 },
960 }
961 }
962}
963
964impl<'a> Drop for HandleDisposition<'a> {
965 fn drop(&mut self) {
966 if self.operation == sys::ZX_HANDLE_OP_MOVE {
968 unsafe { drop(NullableHandle::from_raw(self.handle)) };
969 }
970 }
971}
972
973#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
977#[repr(C)]
978pub struct HandleInfo {
979 pub handle: NullableHandle,
980 pub object_type: ObjectType,
981 pub rights: Rights,
982
983 pub(crate) _unused: u32,
985}
986
987static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
988static_assertions::const_assert_eq!(
989 std::mem::offset_of!(HandleInfo, handle),
990 std::mem::offset_of!(sys::zx_handle_info_t, handle)
991);
992static_assertions::const_assert_eq!(
993 std::mem::offset_of!(HandleInfo, object_type),
994 std::mem::offset_of!(sys::zx_handle_info_t, ty)
995);
996static_assertions::const_assert_eq!(
997 std::mem::offset_of!(HandleInfo, rights),
998 std::mem::offset_of!(sys::zx_handle_info_t, rights)
999);
1000static_assertions::const_assert_eq!(
1001 std::mem::offset_of!(HandleInfo, _unused),
1002 std::mem::offset_of!(sys::zx_handle_info_t, unused)
1003);
1004
1005impl HandleInfo {
1006 pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
1008 Self { handle, object_type, rights, _unused: 0 }
1009 }
1010
1011 pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
1019 HandleInfo::new(
1020 unsafe { NullableHandle::from_raw(raw.handle) },
1022 ObjectType::from_raw(raw.ty),
1023 Rights::from_bits_retain(raw.rights),
1024 )
1025 }
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030 use super::*;
1031 use zx::{
1034 Channel, HandleDisposition, HandleInfo, HandleOp, Name, NullableHandle, ObjectType, Rights,
1035 Vmo,
1036 };
1037 use zx_sys as sys;
1038
1039 #[test]
1040 fn into_raw() {
1041 let vmo = Vmo::create(1).unwrap();
1042 let h = vmo.into_raw();
1043 let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
1044 assert!(vmo2.write(b"1", 0).is_ok());
1045 }
1046
1047 #[test]
1048 fn check_raw_valid() {
1049 assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
1050 let vmo = Vmo::create(1).unwrap();
1051 let vmo_raw = vmo.raw_handle();
1052 assert!(Handle::check_raw_valid(vmo_raw).is_ok());
1053 drop(vmo);
1054 assert!(Handle::check_raw_valid(vmo_raw).is_err());
1055 }
1056
1057 #[test]
1059 fn duplicate() {
1060 let hello_length: usize = 5;
1061
1062 let vmo = Vmo::create(hello_length as u64).unwrap();
1064 assert!(vmo.write(b"hello", 0).is_ok());
1065
1066 let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
1068 let mut read_vec = vec![0; hello_length];
1070 assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1071 assert_eq!(read_vec, b"hello");
1072 assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1073
1074 assert!(vmo.write(b"bye", 0).is_ok());
1076 assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1077 assert_eq!(read_vec, b"byelo");
1078 }
1079
1080 #[test]
1082 fn replace() {
1083 let hello_length: usize = 5;
1084
1085 let vmo = Vmo::create(hello_length as u64).unwrap();
1087 assert!(vmo.write(b"hello", 0).is_ok());
1088
1089 let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
1091 let mut read_vec = vec![0; hello_length];
1093 assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
1094 assert_eq!(read_vec, b"hello");
1095 assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
1096 }
1097
1098 #[test]
1099 fn set_get_name() {
1100 let vmo = Vmo::create(1).unwrap();
1102 let short_name = Name::new("v").unwrap();
1103 assert!(vmo.set_name(&short_name).is_ok());
1104 assert_eq!(vmo.get_name().unwrap(), short_name);
1105 }
1106
1107 #[test]
1108 fn set_get_max_len_name() {
1109 let vmo = Vmo::create(1).unwrap();
1110 let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); assert!(vmo.set_name(&max_len_name).is_ok());
1112 assert_eq!(vmo.get_name().unwrap(), max_len_name);
1113 }
1114
1115 #[test]
1116 fn basic_info_channel() {
1117 let (side1, side2) = Channel::create();
1118 let info1 = side1.basic_info().expect("side1 basic_info failed");
1119 let info2 = side2.basic_info().expect("side2 basic_info failed");
1120
1121 assert_eq!(info1.koid, info2.related_koid);
1122 assert_eq!(info2.koid, info1.related_koid);
1123
1124 for info in &[info1, info2] {
1125 assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
1126 assert_eq!(info.object_type, ObjectType::CHANNEL);
1127 assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
1128 }
1129
1130 let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
1131 let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
1132 assert_eq!(info1_repl.koid, info1.koid);
1133 assert_eq!(info1_repl.rights, Rights::READ);
1134 }
1135
1136 #[test]
1137 fn basic_info_vmar() {
1138 let root_vmar = fuchsia_runtime::vmar_root_self();
1140 let info = root_vmar.basic_info().expect("vmar basic_info failed");
1141 assert_eq!(info.object_type, ObjectType::VMAR);
1142 assert!(!info.rights.contains(Rights::WAIT));
1143 }
1144
1145 #[test]
1146 fn count_info() {
1147 let vmo0 = Vmo::create(1).unwrap();
1148 let count_info = vmo0.count_info().expect("vmo0 count_info failed");
1149 assert_eq!(count_info.handle_count, 1);
1150
1151 let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
1152 let count_info = vmo1.count_info().expect("vmo1 count_info failed");
1153 assert_eq!(count_info.handle_count, 2);
1154 }
1155
1156 #[test]
1157 fn raw_handle_disposition() {
1158 const RAW_HANDLE: sys::zx_handle_t = 1;
1159 let hd = HandleDisposition::new(
1160 HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
1161 ObjectType::VMO,
1162 Rights::EXECUTE,
1163 Status::OK,
1164 );
1165 let raw_hd = hd.into_raw();
1166 assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
1167 assert_eq!(raw_hd.handle, RAW_HANDLE);
1168 assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
1169 assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
1170 assert_eq!(raw_hd.result, sys::ZX_OK);
1171 }
1172
1173 #[test]
1174 fn regression_nullable_handle_into_raw_recursion() {
1175 let h = NullableHandle::invalid();
1176 assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
1178
1179 let vmo = Vmo::create(1).unwrap();
1180 let raw = vmo.raw_handle();
1181 let h = vmo.into_handle();
1182 assert_eq!(h.into_raw(), raw);
1184 }
1185
1186 #[test]
1187 fn handle_info_from_raw() {
1188 const RAW_HANDLE: sys::zx_handle_t = 1;
1189 let raw_hi = sys::zx_handle_info_t {
1190 handle: RAW_HANDLE,
1191 ty: sys::ZX_OBJ_TYPE_VMO,
1192 rights: sys::ZX_RIGHT_EXECUTE,
1193 unused: 128,
1194 };
1195 let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1196 assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1197 assert_eq!(hi.object_type, ObjectType::VMO);
1198 assert_eq!(hi.rights, Rights::EXECUTE);
1199 }
1200
1201 #[test]
1202 fn basic_peer_closed() {
1203 let (lhs, rhs) = crate::EventPair::create();
1204 assert!(!lhs.is_closed().unwrap());
1205 assert!(!rhs.is_closed().unwrap());
1206 drop(rhs);
1207 assert!(lhs.is_closed().unwrap());
1208 }
1209
1210 #[test]
1211 fn poisoned_drops_without_closing() {
1212 let handle = Handle::poison();
1213 assert!(handle.is_poison());
1214 drop(handle);
1215 }
1216
1217 #[test]
1218 fn valid_handles_not_poisoned() {
1219 let event = zx::Event::create();
1220 let event: zx::Handle = event.try_into().unwrap();
1221 assert!(!event.is_poison());
1222 }
1223}