blob: bc637aa53b416f1b9a541e4c55ed13716e7dd97b [file] [log] [blame]
//! The following is derived from Rust's
//! library/std/src/os/windows/io/socket.rs
//! at revision
//! 4f9b394c8a24803e57ba892fa00e539742ebafc0.
//!
//! All code in this file is licensed MIT or Apache 2.0 at your option.
use super::raw::*;
use crate::backend::c;
use crate::backend::fd::LibcFd as LibcSocket;
use core::fmt;
use core::marker::PhantomData;
use core::mem::forget;
/// A borrowed socket.
///
/// This has a lifetime parameter to tie it to the lifetime of something that
/// owns the socket.
///
/// This uses `repr(transparent)` and has the representation of a host socket,
/// so it can be used in FFI in places where a socket is passed as an argument,
/// it is not captured or consumed, and it never has the value
/// `INVALID_SOCKET`.
///
/// This type's `.to_owned()` implementation returns another `BorrowedSocket`
/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw
/// socket, which is then borrowed under the same lifetime.
#[derive(Copy, Clone)]
#[repr(transparent)]
#[cfg_attr(staged_api, rustc_layout_scalar_valid_range_start(0))]
// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
#[cfg_attr(
all(staged_api, target_pointer_width = "32"),
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)
)]
#[cfg_attr(
all(staged_api, target_pointer_width = "64"),
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
)]
#[cfg_attr(staged_api, rustc_nonnull_optimization_guaranteed)]
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
pub struct BorrowedSocket<'socket> {
socket: RawSocket,
_phantom: PhantomData<&'socket OwnedSocket>,
}
/// An owned socket.
///
/// This closes the socket on drop.
///
/// This uses `repr(transparent)` and has the representation of a host socket,
/// so it can be used in FFI in places where a socket is passed as a consumed
/// argument or returned as an owned value, and it never has the value
/// `INVALID_SOCKET`.
#[repr(transparent)]
#[cfg_attr(staged_api, rustc_layout_scalar_valid_range_start(0))]
// This is -2, in two's complement. -1 is `INVALID_SOCKET`.
#[cfg_attr(
all(staged_api, target_pointer_width = "32"),
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)
)]
#[cfg_attr(
all(staged_api, target_pointer_width = "64"),
rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE)
)]
#[cfg_attr(staged_api, rustc_nonnull_optimization_guaranteed)]
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
pub struct OwnedSocket {
socket: RawSocket,
}
impl BorrowedSocket<'_> {
/// Return a `BorrowedSocket` holding the given raw socket.
///
/// # Safety
///
/// The resource pointed to by `raw` must remain open for the duration of
/// the returned `BorrowedSocket`, and it must not have the value
/// `INVALID_SOCKET`.
#[inline]
#[cfg_attr(
staged_api,
rustc_const_stable(feature = "io_safety", since = "1.63.0")
)]
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
pub const unsafe fn borrow_raw(socket: RawSocket) -> Self {
assert!(socket != c::INVALID_SOCKET as RawSocket);
Self {
socket,
_phantom: PhantomData,
}
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl AsRawSocket for BorrowedSocket<'_> {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl AsRawSocket for OwnedSocket {
#[inline]
fn as_raw_socket(&self) -> RawSocket {
self.socket
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl IntoRawSocket for OwnedSocket {
#[inline]
fn into_raw_socket(self) -> RawSocket {
let socket = self.socket;
forget(self);
socket
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl FromRawSocket for OwnedSocket {
#[inline]
unsafe fn from_raw_socket(socket: RawSocket) -> Self {
debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket);
Self { socket }
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl Drop for OwnedSocket {
#[inline]
fn drop(&mut self) {
unsafe {
let _ = c::closesocket(self.socket as LibcSocket);
}
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl fmt::Debug for BorrowedSocket<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BorrowedSocket")
.field("socket", &self.socket)
.finish()
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl fmt::Debug for OwnedSocket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedSocket")
.field("socket", &self.socket)
.finish()
}
}
/// A trait to borrow the socket from an underlying object.
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
pub trait AsSocket {
/// Borrows the socket.
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
fn as_socket(&self) -> BorrowedSocket<'_>;
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl<T: AsSocket> AsSocket for &T {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
T::as_socket(self)
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl<T: AsSocket> AsSocket for &mut T {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
T::as_socket(self)
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl AsSocket for BorrowedSocket<'_> {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
*self
}
}
#[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))]
impl AsSocket for OwnedSocket {
#[inline]
fn as_socket(&self) -> BorrowedSocket<'_> {
// Safety: `OwnedSocket` and `BorrowedSocket` have the same validity
// invariants, and the `BorrowdSocket` is bounded by the lifetime
// of `&self`.
unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) }
}
}