Skip to main content

dolang_rpc/
handle.rs

1//! Native operating-system handles attached directly to RPC messages.
2//!
3//! [`OsHandle`] transfers a file descriptor (Unix) or handle (Windows) as a message attachment. It
4//! requires a supported transport.
5
6use std::{cell::Cell, fmt, io};
7
8#[cfg(unix)]
9use std::os::fd::{AsFd, OwnedFd};
10
11#[cfg(windows)]
12use std::os::windows::io::{AsHandle, OwnedHandle};
13
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16/// The platform's default owned native handle type.
17#[cfg(unix)]
18pub type DefaultHandle = OwnedFd;
19
20/// The platform's default owned native handle type.
21#[cfg(windows)]
22pub type DefaultHandle = std::os::windows::io::OwnedHandle;
23
24/// Supplies native handles encountered during serialization.
25pub(crate) trait PutHandle {
26    #[cfg(unix)]
27    fn put_handle(&mut self, handle: &dyn ErasedHandle) -> io::Result<u32>;
28    #[cfg(windows)]
29    fn put_handle(&mut self, handle: &dyn ErasedHandle) -> io::Result<usize>;
30    /// Records a session opaque encountered during serialization, returning
31    /// its wire `(owner, id)`.
32    fn put_opaque(&mut self, opaque: &crate::session::Inner) -> io::Result<(u8, u64)>;
33}
34
35pub(crate) trait ErasedHandle {
36    #[cfg(unix)]
37    fn steal_handle(&self) -> Option<OwnedFd>;
38    #[cfg(windows)]
39    fn steal_handle(&self) -> Option<OwnedHandle>;
40}
41
42/// Consumes native handles encountered during deserialization.
43pub(crate) trait TakeHandle {
44    #[cfg(unix)]
45    fn take_handle(&mut self, index: u32) -> io::Result<OwnedFd>;
46    #[cfg(windows)]
47    fn take_handle(&mut self, value: usize) -> io::Result<OwnedHandle>;
48
49    fn finish(&mut self) -> io::Result<()> {
50        Ok(())
51    }
52    /// Resolves an arriving wire `(owner, id)` in a position declared to hold
53    /// a [`Gift`](crate::session::Gift) against the receiving session.
54    fn take_gift(&mut self, owner: u8, id: u64) -> io::Result<crate::session::Inner>;
55
56    /// Resolves an arriving wire `(owner, id)` in a position declared to hold
57    /// a [`Cite`](crate::session::Cite) against the receiving session.
58    ///
59    /// `marker` is the [`TypeId`](std::any::TypeId) of the marker type the
60    /// wire position declares, which the session checks against its own
61    /// registration for the id.
62    fn take_cite(
63        &mut self,
64        owner: u8,
65        id: u64,
66        marker: std::any::TypeId,
67    ) -> io::Result<crate::session::Inner>;
68}
69
70/// A native operating system handle attachment.
71///
72/// Only compatible with the [`Builder`](crate::Builder) Unix-socket constructors on Unix or
73/// named-pipe constructors on Windows. Serializing it over a generic byte stream fails the call
74/// with an error.
75pub struct OsHandle<T = DefaultHandle>(Cell<Option<T>>);
76
77impl<T> fmt::Debug for OsHandle<T> {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.write_str("OsHandle(..)")
80    }
81}
82
83impl<T> OsHandle<T> {
84    /// Wraps a native handle-like value for message attachment.
85    pub fn new(value: T) -> Self {
86        Self(Cell::new(Some(value)))
87    }
88
89    /// Returns the wrapped value.
90    ///
91    /// # Panics
92    ///
93    /// Panics if successful serialization already consumed the handle.
94    pub fn into_inner(self) -> T {
95        self.0
96            .into_inner()
97            .expect("operating-system handle was already consumed")
98    }
99}
100
101impl<T> From<T> for OsHandle<T> {
102    fn from(value: T) -> Self {
103        Self::new(value)
104    }
105}
106
107#[cfg(unix)]
108impl<T: AsFd + Into<OwnedFd>> ErasedHandle for OsHandle<T> {
109    fn steal_handle(&self) -> Option<OwnedFd> {
110        self.0.take().map(Into::into)
111    }
112}
113
114#[cfg(unix)]
115impl<T: AsFd + Into<OwnedFd>> Serialize for OsHandle<T> {
116    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117        crate::serde::serialize_handle(self, serializer)
118    }
119}
120
121#[cfg(unix)]
122impl<'de, T: From<OwnedFd>> Deserialize<'de> for OsHandle<T> {
123    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
124        crate::serde::deserialize_handle(deserializer).map(|handle| OsHandle::new(T::from(handle)))
125    }
126}
127
128#[cfg(windows)]
129impl<T: AsHandle + Into<OwnedHandle>> ErasedHandle for OsHandle<T> {
130    fn steal_handle(&self) -> Option<OwnedHandle> {
131        self.0.take().map(Into::into)
132    }
133}
134
135#[cfg(windows)]
136impl<T: AsHandle + Into<OwnedHandle>> Serialize for OsHandle<T> {
137    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
138        crate::serde::serialize_handle(self, serializer)
139    }
140}
141
142#[cfg(windows)]
143impl<'de, T: From<OwnedHandle>> Deserialize<'de> for OsHandle<T> {
144    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
145        crate::serde::deserialize_handle(deserializer).map(|handle| OsHandle::new(T::from(handle)))
146    }
147}