use core::mem::ManuallyDrop;
use std::io;
use std::net::SocketAddr;
use super::opt;
use super::socket::{raw_of, std_from_raw};
use crate::io::raw::{Owned, Raw};
use crate::io::source::Kind;
use crate::io::{Handle, sys};
pub struct UdpSocketBuilder {
socket: Owned,
}
super::sockopt::socket_options!(UdpSocketBuilder);
impl UdpSocketBuilder {
pub fn new_v4() -> io::Result<UdpSocketBuilder> {
Self::new(false)
}
pub fn new_v6() -> io::Result<UdpSocketBuilder> {
Self::new(true)
}
fn new(v6: bool) -> io::Result<UdpSocketBuilder> {
#[cfg(unix)]
let socket = sys::socket(
if v6 { libc::AF_INET6 } else { libc::AF_INET },
libc::SOCK_DGRAM,
)?;
#[cfg(windows)]
let socket = sys::udp_socket(if v6 {
crate::syscore::windows::AF_INET6
} else {
crate::syscore::windows::AF_INET
})?;
Ok(UdpSocketBuilder { socket })
}
fn raw(&self) -> Raw {
raw_of(&self.socket)
}
fn as_std(&self) -> ManuallyDrop<std::net::UdpSocket> {
ManuallyDrop::new(unsafe { std_from_raw(self.raw()) })
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.as_std().local_addr()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.as_std().take_error()
}
pub fn bind(self, addr: SocketAddr) -> io::Result<super::UdpSocket> {
sys::bind_inet(self.raw(), &addr)?;
let socket = std::net::UdpSocket::from(self.socket);
Ok(Handle::from_nonblocking(socket, Kind::Udp))
}
}
impl core::fmt::Debug for UdpSocketBuilder {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("UdpSocketBuilder")
.field("socket", &self.raw())
.finish_non_exhaustive()
}
}
#[cfg(unix)]
impl std::os::fd::AsRawFd for UdpSocketBuilder {
fn as_raw_fd(&self) -> std::os::fd::RawFd {
self.raw()
}
}
#[cfg(unix)]
impl std::os::fd::AsFd for UdpSocketBuilder {
fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
std::os::fd::AsFd::as_fd(&self.socket)
}
}
#[cfg(windows)]
impl std::os::windows::io::AsRawSocket for UdpSocketBuilder {
fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
self.raw()
}
}
#[cfg(windows)]
impl std::os::windows::io::AsSocket for UdpSocketBuilder {
fn as_socket(&self) -> std::os::windows::io::BorrowedSocket<'_> {
std::os::windows::io::AsSocket::as_socket(&self.socket)
}
}