//! The `lb:net` library provides an asynchronous network API for creating TCP or UDP servers and //! clients. //! //! # Exports //! //! See [`lb_libnet`] for items exported by this library. use derive_more::{From, FromStr}; use luaffi::{cdef, metatype}; use std::{ io, net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, }; use tokio::net::{TcpListener, TcpSocket, TcpStream}; /// Items exported by the `lb:net` library. /// /// This library can be obtained by calling `require` in Lua. /// /// ```lua /// local net = require("lb:net"); /// ``` #[cdef] pub struct lb_libnet; #[metatype] impl lb_libnet { #[new] extern "Lua-C" fn new() -> Self { Self } /// See [`Ipv4Addr::LOCALHOST`]. pub extern "Lua-C" fn localhost_v4(&self) -> lb_ipaddr { lb_ipaddr(Ipv4Addr::LOCALHOST.into()) } /// See [`Ipv6Addr::LOCALHOST`]. pub extern "Lua-C" fn localhost_v6(&self) -> lb_ipaddr { lb_ipaddr(Ipv6Addr::LOCALHOST.into()) } /// See [`Ipv4Addr::UNSPECIFIED`]. pub extern "Lua-C" fn unspecified_v4(&self) -> lb_ipaddr { lb_ipaddr(Ipv4Addr::UNSPECIFIED.into()) } /// See [`Ipv6Addr::UNSPECIFIED`]. pub extern "Lua-C" fn unspecified_v6(&self) -> lb_ipaddr { lb_ipaddr(Ipv6Addr::UNSPECIFIED.into()) } /// See [`Ipv4Addr::BROADCAST`]. pub extern "Lua-C" fn broadcast_v4(&self) -> lb_ipaddr { lb_ipaddr(Ipv4Addr::BROADCAST.into()) } /// Creates an [`lb_ipaddr`] from the given input. /// /// If `s` is an [`lb_ipaddr`], a copy of that value is returned. If `s` is an /// [`lb_socketaddr`], the IP address part of the socket address is returned. Otherwise, parses /// `s` as an IP address string. Both IPv4 or IPv6 addresses are supported. /// /// # Errors /// /// Throws if `s` cannot be parsed as an IP address. pub extern "Lua" fn ipaddr(&self, s: any) -> lb_ipaddr { if __istype(__ct.lb_ipaddr, s) { __new(__ct.lb_ipaddr, s) // copy constructor } else if __istype(__ct.lb_socketaddr, s) { s.ip() } else { self.__parse_ipaddr(s) } } extern "Lua-C" fn __parse_ipaddr(&self, s: &str) -> Result { s.parse() } /// Creates an [`lb_socketaddr`] from the given input. /// /// A socket address is an IP address with a port number. /// /// If `s` is an [`lb_socketaddr`], a copy of that value is returned. If `s` is an /// [`lb_ipaddr`], a socket address with that IP address is returned. Otherwise, parses `s` as a /// socket address string. Both IPv4 and IPv6 addresses are supported. /// /// If `port` is not specified, `0` is used as the default. /// /// # Errors /// /// Throws if `s` cannot be parsed as an IP or socket address. pub extern "Lua" fn socketaddr(&self, s: any, port: any) -> lb_socketaddr { if port != () { self.__new_socketaddr(self.ipaddr(s), port) } else { if __istype(__ct.lb_socketaddr, s) { __new(__ct.lb_socketaddr, s) // copy constructor } else if __istype(__ct.lb_ipaddr, s) { self.__new_socketaddr(s, 0) // default port 0 } else { self.__parse_socketaddr(s) } } } extern "Lua-C" fn __new_socketaddr(&self, ip: &lb_ipaddr, port: u16) -> lb_socketaddr { SocketAddr::new(ip.0, port).into() } extern "Lua-C" fn __parse_socketaddr(&self, s: &str) -> Result { s.parse() } /// Creates a new TCP socket configured for IPv4. /// /// See [`TcpSocket::new_v4`]. /// /// # Errors /// /// Throws if an error was encountered during the socket creation. pub extern "Lua-C" fn tcp_v4(&self) -> io::Result { TcpSocket::new_v4().map(lb_tcpsocket) } /// Creates a new TCP socket configured for IPv6. /// /// See [`TcpSocket::new_v6`]. /// /// # Errors /// /// Throws if an error was encountered during the socket creation. pub extern "Lua-C" fn tcp_v6(&self) -> io::Result { TcpSocket::new_v6().map(lb_tcpsocket) } } /// An IP address, either IPv4 or IPv6. /// /// # Example /// /// This example creates an [`lb_ipaddr`] by parsing an IP address string. /// /// ```lua /// local net = require("lb:net"); /// local addr = net:ipaddr("127.0.0.1"); -- ipv4 loopback address /// /// assert(addr:is_v4()); /// assert(addr:is_loopback()); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, From, FromStr)] #[cdef] pub struct lb_ipaddr(#[opaque] IpAddr); #[metatype] impl lb_ipaddr { /// See [`IpAddr::is_unspecified`]. pub extern "Lua-C" fn is_unspecified(&self) -> bool { self.0.is_unspecified() } /// See [`IpAddr::is_loopback`]. pub extern "Lua-C" fn is_loopback(&self) -> bool { self.0.is_loopback() } /// See [`IpAddr::is_multicast`]. pub extern "Lua-C" fn is_multicast(&self) -> bool { self.0.is_multicast() } /// Returns the string `"v4"` if this is an IPv4 address or `"v6"` if this is an IPv6 address. pub extern "Lua" fn family(&self) -> string { if self.is_v6() { "v6" } else { "v4" } } /// Returns `true` if this is an IPv4 address. pub extern "Lua-C" fn is_v4(&self) -> bool { self.0.is_ipv4() } /// See [`Ipv4Addr::is_private`]. pub extern "Lua-C" fn is_v4_private(&self) -> bool { match self.0 { IpAddr::V4(v4) => v4.is_private(), IpAddr::V6(_) => false, } } /// See [`Ipv4Addr::is_link_local`]. pub extern "Lua-C" fn is_v4_link_local(&self) -> bool { match self.0 { IpAddr::V4(v4) => v4.is_link_local(), IpAddr::V6(_) => false, } } /// See [`Ipv4Addr::is_broadcast`]. pub extern "Lua-C" fn is_v4_broadcast(&self) -> bool { match self.0 { IpAddr::V4(v4) => v4.is_broadcast(), IpAddr::V6(_) => false, } } /// See [`Ipv4Addr::is_documentation`]. pub extern "Lua-C" fn is_v4_documentation(&self) -> bool { match self.0 { IpAddr::V4(v4) => v4.is_documentation(), IpAddr::V6(_) => false, } } /// Returns `true` if this is an IPv6 address. pub extern "Lua-C" fn is_v6(&self) -> bool { self.0.is_ipv6() } /// See [`Ipv6Addr::is_unique_local`]. pub extern "Lua-C" fn is_v6_unique_local(&self) -> bool { match self.0 { IpAddr::V4(_) => false, IpAddr::V6(v6) => v6.is_unique_local(), } } /// See [`Ipv6Addr::is_unicast_link_local`]. pub extern "Lua-C" fn is_v6_unicast_link_local(&self) -> bool { match self.0 { IpAddr::V4(_) => false, IpAddr::V6(v6) => v6.is_unicast_link_local(), } } /// See [`Ipv4Addr::to_ipv6_compatible`]. pub extern "Lua-C" fn to_v6_compat(&self) -> Self { match self.0 { IpAddr::V4(v4) => Self(v4.to_ipv6_compatible().into()), IpAddr::V6(_) => *self, } } /// See [`Ipv4Addr::to_ipv6_mapped`]. pub extern "Lua-C" fn to_v6_mapped(&self) -> Self { match self.0 { IpAddr::V4(v4) => Self(v4.to_ipv6_mapped().into()), IpAddr::V6(_) => *self, } } /// See [`IpAddr::to_canonical`]. pub extern "Lua-C" fn canonical(&self) -> Self { self.0.to_canonical().into() } /// Returns the string representation of this address. #[tostring] pub extern "Lua-C" fn tostring(&self) -> String { self.0.to_string() } } /// A socket address, which is an IP address with a port number. #[derive(Debug, Clone, Copy, PartialEq, Eq, From, FromStr)] #[cdef] pub struct lb_socketaddr(#[opaque] SocketAddr); #[metatype] impl lb_socketaddr { /// Returns the IP part of this address. pub extern "Lua-C" fn ip(&self) -> lb_ipaddr { self.0.ip().into() } /// Sets the IP part of this address. /// /// This function accepts the same arguments as [`ipaddr`](lb_libnet::ipaddr). pub extern "Lua" fn set_ip(&mut self, s: any) -> &mut Self { if __istype(__ct.lb_ipaddr, s) { self.__set_ip(s); } else if __istype(__ct.lb_socketaddr, s) { self.__set_ip(s.ip()); } else { self.__set_ip_parse(s); } self } extern "Lua-C" fn __set_ip(&mut self, ip: &lb_ipaddr) { self.0.set_ip(ip.0); } extern "Lua-C" fn __set_ip_parse(&mut self, s: &str) -> Result<(), AddrParseError> { s.parse().map(|ip| self.0.set_ip(ip)) } /// Returns the port part of this address. pub extern "Lua-C" fn port(&self) -> u16 { self.0.port() } /// Sets the port part of this address. pub extern "Lua" fn set_port(&mut self, port: number) -> &mut Self { self.__set_port(port); self } extern "Lua-C" fn __set_port(&mut self, port: u16) { self.0.set_port(port) } /// Returns the string representation of this address. #[tostring] pub extern "Lua-C" fn tostring(&self) -> String { self.0.to_string() } } /// A TCP socket which has not yet been converted to a [`lb_tcpstream`] or [`lb_tcplistener`]. #[derive(Debug, From)] #[cdef] pub struct lb_tcpsocket(#[opaque] TcpSocket); #[metatype] impl lb_tcpsocket {} #[derive(Debug, From)] #[cdef] pub struct lb_tcpstream(#[opaque] TcpStream); #[metatype] impl lb_tcpstream {} #[derive(Debug, From)] #[cdef] pub struct lb_tcplistener(#[opaque] TcpListener); #[metatype] impl lb_tcplistener {}