use super::UnixNetwork;
use futures::Stream;
use std::fmt::{Debug, Formatter};
use std::io;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::task::{Context, Poll};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum UnixSocketAddr {
Pathname(PathBuf),
Abstract(Vec<u8>),
Unnamed,
}
impl UnixSocketAddr {
pub fn as_pathname(&self) -> Option<&Path> {
match self {
Self::Pathname(path) => Some(path),
_ => None,
}
}
pub fn as_abstract_name(&self) -> Option<&[u8]> {
match self {
Self::Abstract(name) => Some(name),
_ => None,
}
}
pub fn is_unnamed(&self) -> bool {
matches!(self, Self::Unnamed)
}
fn from_std(address: std::os::unix::net::SocketAddr) -> Self {
if let Some(path) = address.as_pathname() {
return Self::Pathname(path.to_owned());
}
if let Some(name) = std_abstract_name(&address) {
return Self::Abstract(name.to_vec());
}
Self::Unnamed
}
#[cfg(feature = "tokio")]
fn from_tokio(address: ::tokio::net::unix::SocketAddr) -> Self {
Self::from_std(address.into())
}
#[cfg(feature = "compio")]
fn from_compio(address: ::socket2::SockAddr) -> Self {
if let Some(path) = address.as_pathname() {
return Self::Pathname(path.to_owned());
}
if let Some(name) = address.as_abstract_namespace() {
return Self::Abstract(name.to_vec());
}
Self::Unnamed
}
}
impl From<std::os::unix::net::SocketAddr> for UnixSocketAddr {
fn from(address: std::os::unix::net::SocketAddr) -> Self {
Self::from_std(address)
}
}
#[cfg(feature = "tokio")]
impl From<::tokio::net::unix::SocketAddr> for UnixSocketAddr {
fn from(address: ::tokio::net::unix::SocketAddr) -> Self {
Self::from_tokio(address)
}
}
#[cfg(target_os = "linux")]
fn std_abstract_name(address: &std::os::unix::net::SocketAddr) -> Option<&[u8]> {
use std::os::linux::net::SocketAddrExt;
address.as_abstract_name()
}
#[cfg(target_os = "android")]
fn std_abstract_name(address: &std::os::unix::net::SocketAddr) -> Option<&[u8]> {
use std::os::android::net::SocketAddrExt;
address.as_abstract_name()
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn std_abstract_name(_: &std::os::unix::net::SocketAddr) -> Option<&[u8]> {
None
}
pub struct UnixStream {
pub(super) inner: UnixStreamInner,
}
pub(super) enum UnixStreamInner {
#[cfg(feature = "tokio")]
Tokio(::tokio::net::UnixStream),
#[cfg(feature = "smol")]
Smol(::smol::net::unix::UnixStream),
#[cfg(feature = "compio")]
Compio(Pin<Box<::compio::io::compat::AsyncStream<::compio::net::UnixStream>>>),
}
impl UnixStream {
pub async fn connect(path: impl AsRef<Path>) -> io::Result<Self> {
super::current().connect_unix(path).await
}
#[cfg(feature = "tokio")]
pub(super) fn from_tokio(stream: ::tokio::net::UnixStream) -> Self {
Self {
inner: UnixStreamInner::Tokio(stream),
}
}
#[cfg(feature = "smol")]
pub(super) fn from_smol(stream: ::smol::net::unix::UnixStream) -> Self {
Self {
inner: UnixStreamInner::Smol(stream),
}
}
#[cfg(feature = "compio")]
pub(super) fn from_compio(stream: ::compio::net::UnixStream) -> Self {
Self {
inner: UnixStreamInner::Compio(Box::pin(::compio::io::compat::AsyncStream::new(
stream,
))),
}
}
pub fn local_addr(&self) -> io::Result<UnixSocketAddr> {
match &self.inner {
#[cfg(feature = "tokio")]
UnixStreamInner::Tokio(stream) => stream.local_addr().map(UnixSocketAddr::from_tokio),
#[cfg(feature = "smol")]
UnixStreamInner::Smol(stream) => stream.local_addr().map(UnixSocketAddr::from_std),
#[cfg(feature = "compio")]
UnixStreamInner::Compio(stream) => compio_stream(stream)
.local_addr()
.map(UnixSocketAddr::from_compio),
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
}
}
pub fn peer_addr(&self) -> io::Result<UnixSocketAddr> {
match &self.inner {
#[cfg(feature = "tokio")]
UnixStreamInner::Tokio(stream) => stream.peer_addr().map(UnixSocketAddr::from_tokio),
#[cfg(feature = "smol")]
UnixStreamInner::Smol(stream) => stream.peer_addr().map(UnixSocketAddr::from_std),
#[cfg(feature = "compio")]
UnixStreamInner::Compio(stream) => compio_stream(stream)
.peer_addr()
.map(UnixSocketAddr::from_compio),
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
}
}
pub async fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
futures::io::AsyncReadExt::read(self, buffer).await
}
pub async fn read_exact(&mut self, buffer: &mut [u8]) -> io::Result<()> {
futures::io::AsyncReadExt::read_exact(self, buffer).await
}
pub async fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
futures::io::AsyncWriteExt::write(self, buffer).await
}
pub async fn write_all(&mut self, buffer: &[u8]) -> io::Result<()> {
futures::io::AsyncWriteExt::write_all(self, buffer).await
}
pub async fn flush(&mut self) -> io::Result<()> {
futures::io::AsyncWriteExt::flush(self).await
}
pub async fn shutdown(&mut self) -> io::Result<()> {
futures::io::AsyncWriteExt::close(self).await
}
}
#[cfg(feature = "compio")]
fn compio_stream(
stream: &Pin<Box<::compio::io::compat::AsyncStream<::compio::net::UnixStream>>>,
) -> &::compio::net::UnixStream {
stream.as_ref().get_ref().get_ref().0
}
impl Debug for UnixStream {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("UnixStream")
.field("local_addr", &self.local_addr())
.field("peer_addr", &self.peer_addr())
.finish()
}
}
pub struct UnixListener {
inner: UnixListenerInner,
}
enum UnixListenerInner {
#[cfg(feature = "tokio")]
Tokio(::tokio::net::UnixListener),
#[cfg(feature = "smol")]
Smol(::smol::net::unix::UnixListener),
#[cfg(feature = "compio")]
Compio(::compio::net::UnixListener),
}
impl UnixListener {
pub async fn bind(path: impl AsRef<Path>) -> io::Result<Self> {
super::current().bind_unix(path).await
}
#[cfg(feature = "tokio")]
pub(super) fn from_tokio(listener: ::tokio::net::UnixListener) -> Self {
Self {
inner: UnixListenerInner::Tokio(listener),
}
}
#[cfg(feature = "smol")]
pub(super) fn from_smol(listener: ::smol::net::unix::UnixListener) -> Self {
Self {
inner: UnixListenerInner::Smol(listener),
}
}
#[cfg(feature = "compio")]
pub(super) fn from_compio(listener: ::compio::net::UnixListener) -> Self {
Self {
inner: UnixListenerInner::Compio(listener),
}
}
pub async fn accept(&self) -> io::Result<(UnixStream, UnixSocketAddr)> {
match &self.inner {
#[cfg(feature = "tokio")]
UnixListenerInner::Tokio(listener) => {
let (stream, address) = listener.accept().await?;
Ok((UnixStream::from_tokio(stream), address.into()))
}
#[cfg(feature = "smol")]
UnixListenerInner::Smol(listener) => {
let (stream, address) = listener.accept().await?;
Ok((UnixStream::from_smol(stream), address.into()))
}
#[cfg(feature = "compio")]
UnixListenerInner::Compio(listener) => {
let (stream, address) = listener.accept().await?;
Ok((
UnixStream::from_compio(stream),
UnixSocketAddr::from_compio(address),
))
}
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
}
}
pub fn incoming(&self) -> UnixIncoming<'_> {
let inner = match &self.inner {
#[cfg(feature = "tokio")]
UnixListenerInner::Tokio(listener) => UnixIncomingInner::Tokio(listener),
#[cfg(feature = "smol")]
UnixListenerInner::Smol(listener) => UnixIncomingInner::Smol(listener.incoming()),
#[cfg(feature = "compio")]
UnixListenerInner::Compio(listener) => UnixIncomingInner::Compio(listener.incoming()),
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
};
UnixIncoming { inner }
}
pub fn local_addr(&self) -> io::Result<UnixSocketAddr> {
match &self.inner {
#[cfg(feature = "tokio")]
UnixListenerInner::Tokio(listener) => {
listener.local_addr().map(UnixSocketAddr::from_tokio)
}
#[cfg(feature = "smol")]
UnixListenerInner::Smol(listener) => {
listener.local_addr().map(UnixSocketAddr::from_std)
}
#[cfg(feature = "compio")]
UnixListenerInner::Compio(listener) => {
listener.local_addr().map(UnixSocketAddr::from_compio)
}
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
}
}
}
impl Debug for UnixListener {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("UnixListener")
.field("local_addr", &self.local_addr())
.finish()
}
}
pub struct UnixIncoming<'a> {
inner: UnixIncomingInner<'a>,
}
enum UnixIncomingInner<'a> {
#[cfg(feature = "tokio")]
Tokio(&'a ::tokio::net::UnixListener),
#[cfg(feature = "smol")]
Smol(::smol::net::unix::Incoming<'a>),
#[cfg(feature = "compio")]
Compio(::compio::net::UnixIncoming<'a>),
}
impl Stream for UnixIncoming<'_> {
type Item = io::Result<UnixStream>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match &mut self.get_mut().inner {
#[cfg(feature = "tokio")]
UnixIncomingInner::Tokio(listener) => listener
.poll_accept(cx)
.map(|result| Some(result.map(|(stream, _)| UnixStream::from_tokio(stream)))),
#[cfg(feature = "smol")]
UnixIncomingInner::Smol(incoming) => Pin::new(incoming)
.poll_next(cx)
.map(|item| item.map(|result| result.map(UnixStream::from_smol))),
#[cfg(feature = "compio")]
UnixIncomingInner::Compio(incoming) => Pin::new(incoming)
.poll_next(cx)
.map(|item| item.map(|result| result.map(UnixStream::from_compio))),
#[cfg(not(any(feature = "tokio", feature = "smol", feature = "compio")))]
_ => unreachable!(),
}
}
}