Skip to main content

dope_core/platform/
channel.rs

1use std::{
2    cell, marker,
3    os::fd::{self, AsFd as _},
4};
5
6use dope_sys::io::socket::{
7    How, Socket,
8    record::{self, Fault, Record, Transport as _},
9};
10
11use crate::{Backend, Errno, platform::Flags};
12
13/// One exclusively used endpoint of a reliable local channel carrying u32 records.
14/// Ownership may transfer during startup; shared cross-thread access is excluded.
15#[derive(Debug)]
16pub struct Channel(fd::OwnedFd, marker::PhantomData<cell::Cell<()>>);
17
18impl Channel {
19    pub fn pair() -> Result<(Self, Self), Create> {
20        let (left, right) = Backend::pair().map_err(Create::from_native)?;
21        Ok((
22            Self(left, marker::PhantomData),
23            Self(right, marker::PhantomData),
24        ))
25    }
26
27    /// A failed send is terminal: a stream may already have transferred a prefix.
28    pub fn send(&self, value: u32) -> Result<(), Fault> {
29        <Backend as Socket>::Records::send(value, |bytes| {
30            Backend::send_quiet::<Errno>(self.0.as_fd(), bytes)
31        })
32    }
33
34    /// Receives one exact record, retaining native packet or stream framing.
35    /// A syscall error is terminal: a stream may already have transferred a prefix.
36    pub fn recv(&self) -> Record {
37        <Backend as Socket>::Records::recv(|bytes| Backend::recv::<0, Errno>(self.0.as_fd(), bytes))
38    }
39
40    pub fn shutdown(&self) -> Result<(), Errno> {
41        Backend::shutdown::<Errno>(self.0.as_fd(), How::WRITE)
42    }
43}
44
45impl fd::AsFd for Channel {
46    fn as_fd(&self) -> fd::BorrowedFd<'_> {
47        self.0.as_fd()
48    }
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum Create {
53    Open(Errno),
54    Cloexec { end: record::End, error: Flags },
55    Sigpipe { end: record::End, error: Errno },
56}
57
58impl Create {
59    fn from_native(error: record::Error) -> Self {
60        match error {
61            record::Error::Open(error) => Self::Open(error),
62            record::Error::Cloexec { end, error } => Self::Cloexec {
63                end,
64                error: Flags::cloexec(error),
65            },
66            record::Error::Sigpipe { end, error } => Self::Sigpipe { end, error },
67        }
68    }
69}