Compare commits
13 Commits
v0.0.1
...
bcb734846d
| Author | SHA1 | Date | |
|---|---|---|---|
|
bcb734846d
|
|||
|
2fe9515702
|
|||
|
f456a544e1
|
|||
|
ba969b9e56
|
|||
|
da5acd6bc8
|
|||
|
cbb47840e4
|
|||
|
2967513cbb
|
|||
|
014687068f
|
|||
|
85a0110e1a
|
|||
|
91302db725
|
|||
|
c249549b3c
|
|||
|
30596d9331
|
|||
|
530a1530ba
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1031,6 +1031,7 @@ dependencies = [
|
|||||||
"luaify",
|
"luaify",
|
||||||
"luajit",
|
"luajit",
|
||||||
"sysexits",
|
"sysexits",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ derive_more = { version = "2.0.1", features = ["full"] }
|
|||||||
luaffi = { path = "../luaffi" }
|
luaffi = { path = "../luaffi" }
|
||||||
luajit = { path = "../luajit" }
|
luajit = { path = "../luajit" }
|
||||||
sysexits = "0.9.0"
|
sysexits = "0.9.0"
|
||||||
|
thiserror = "2.0.12"
|
||||||
tokio = { version = "1.45.1", features = ["rt", "time", "fs", "net", "process", "signal", "tracing"] }
|
tokio = { version = "1.45.1", features = ["rt", "time", "fs", "net", "process", "signal", "tracing"] }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
use luaffi::{cdef, metatype};
|
use luaffi::{cdef, metatype};
|
||||||
|
|
||||||
#[cdef]
|
#[cdef]
|
||||||
pub struct lb_libchannel;
|
pub struct lb_chanlib;
|
||||||
|
|
||||||
#[metatype]
|
#[metatype]
|
||||||
impl lb_libchannel {
|
impl lb_chanlib {
|
||||||
#[new]
|
#[new]
|
||||||
extern "Lua-C" fn new() -> Self {
|
extern "Lua-C" fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
//! The `lb:fs` module provides utilities for interacting with the file system asynchronously.
|
//! The `lb:fs` library provides synchronous and asynchronous utilities for interacting with the
|
||||||
|
//! file system.
|
||||||
//!
|
//!
|
||||||
//! # Exports
|
//! # Exports
|
||||||
//!
|
//!
|
||||||
//! See [`lb_libfs`] for items exported by this module.
|
//! See [`lb_fslib`] for items exported by this library.
|
||||||
use luaffi::{cdef, metatype};
|
use luaffi::{cdef, metatype};
|
||||||
use std::io;
|
use std::io;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
/// Items exported by the `lb:fs` module.
|
/// Items exported by the `lb:fs` library.
|
||||||
///
|
///
|
||||||
/// This module can be obtained by calling `require` in Lua.
|
/// This library can be obtained by calling `require` in Lua.
|
||||||
///
|
///
|
||||||
/// ```lua
|
/// ```lua
|
||||||
/// local fs = require("lb:fs");
|
/// local fs = require("lb:fs");
|
||||||
/// ```
|
/// ```
|
||||||
#[cdef]
|
#[cdef]
|
||||||
pub struct lb_libfs;
|
pub struct lb_fslib;
|
||||||
|
|
||||||
#[metatype]
|
#[metatype]
|
||||||
impl lb_libfs {
|
impl lb_fslib {
|
||||||
#[new]
|
#[new]
|
||||||
extern "Lua-C" fn new() -> Self {
|
extern "Lua-C" fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
@@ -31,4 +32,12 @@ impl lb_libfs {
|
|||||||
pub extern "Lua-C" fn read_sync(&self, path: &str) -> io::Result<Vec<u8>> {
|
pub extern "Lua-C" fn read_sync(&self, path: &str) -> io::Result<Vec<u8>> {
|
||||||
std::fs::read(path)
|
std::fs::read(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async extern "Lua-C" fn write(&self, path: &str, contents: &[u8]) -> io::Result<()> {
|
||||||
|
fs::write(path, contents).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "Lua-C" fn write_sync(&self, path: &str, contents: &[u8]) -> io::Result<()> {
|
||||||
|
std::fs::write(path, contents)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod channel;
|
pub mod chan;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|||||||
@@ -1,29 +1,47 @@
|
|||||||
//! The `lb:net` module provides an asynchronous network API for creating TCP or UDP servers and
|
//! The `lb:net` library provides an asynchronous network API for creating TCP or UDP servers and
|
||||||
//! clients.
|
//! clients.
|
||||||
//!
|
//!
|
||||||
//! # Exports
|
//! # Exports
|
||||||
//!
|
//!
|
||||||
//! See [`lb_libnet`] for items exported by this module.
|
//! See [`lb_netlib`] for items exported by this library.
|
||||||
use derive_more::{From, FromStr};
|
use derive_more::{From, FromStr};
|
||||||
use luaffi::{cdef, metatype};
|
use luaffi::{cdef, metatype};
|
||||||
use std::{
|
use std::{
|
||||||
io,
|
|
||||||
net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
use thiserror::Error;
|
||||||
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
||||||
|
|
||||||
/// Items exported by the `lb:net` module.
|
/// Errors that can be thrown by this library.
|
||||||
///
|
///
|
||||||
/// This module can be obtained by calling `require` in Lua.
|
/// Functions which return this error will **throw** in Lua. The error message can be caught by
|
||||||
|
/// using [`pcall(f, ...)`](https://www.lua.org/manual/5.1/manual.html#pdf-pcall).
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidAddr(#[from] AddrParseError),
|
||||||
|
#[error("socket was already converted")]
|
||||||
|
SocketConsumed,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
/// Items exported by the `lb:net` library.
|
||||||
|
///
|
||||||
|
/// This library can be obtained by calling
|
||||||
|
/// [`require("lb:net")`](https://www.lua.org/manual/5.1/manual.html#pdf-require) in Lua.
|
||||||
///
|
///
|
||||||
/// ```lua
|
/// ```lua
|
||||||
/// local net = require("lb:net");
|
/// local net = require("lb:net");
|
||||||
/// ```
|
/// ```
|
||||||
#[cdef]
|
#[cdef]
|
||||||
pub struct lb_libnet;
|
pub struct lb_netlib;
|
||||||
|
|
||||||
#[metatype]
|
#[metatype]
|
||||||
impl lb_libnet {
|
impl lb_netlib {
|
||||||
#[new]
|
#[new]
|
||||||
extern "Lua-C" fn new() -> Self {
|
extern "Lua-C" fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
@@ -59,11 +77,7 @@ impl lb_libnet {
|
|||||||
/// If `s` is an [`lb_ipaddr`], a copy of that value is returned. If `s` is an
|
/// 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
|
/// [`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.
|
/// `s` as an IP address string. Both IPv4 or IPv6 addresses are supported.
|
||||||
///
|
pub extern "Lua" fn ipaddr(&self, s: any) -> Result<lb_ipaddr> {
|
||||||
/// # 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) {
|
if __istype(__ct.lb_ipaddr, s) {
|
||||||
__new(__ct.lb_ipaddr, s) // copy constructor
|
__new(__ct.lb_ipaddr, s) // copy constructor
|
||||||
} else if __istype(__ct.lb_socketaddr, s) {
|
} else if __istype(__ct.lb_socketaddr, s) {
|
||||||
@@ -73,8 +87,8 @@ impl lb_libnet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Lua-C" fn __parse_ipaddr(&self, s: &str) -> Result<lb_ipaddr, AddrParseError> {
|
extern "Lua-C" fn __parse_ipaddr(&self, s: &str) -> Result<lb_ipaddr> {
|
||||||
s.parse()
|
Ok(s.parse()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`lb_socketaddr`] from the given input.
|
/// Creates an [`lb_socketaddr`] from the given input.
|
||||||
@@ -86,52 +100,67 @@ impl lb_libnet {
|
|||||||
/// socket address string. Both IPv4 and IPv6 addresses are supported.
|
/// socket address string. Both IPv4 and IPv6 addresses are supported.
|
||||||
///
|
///
|
||||||
/// If `port` is not specified, `0` is used as the default.
|
/// If `port` is not specified, `0` is used as the default.
|
||||||
///
|
pub extern "Lua" fn socketaddr(&self, s: any, port: any) -> Result<lb_socketaddr> {
|
||||||
/// # 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 != () {
|
if port != () {
|
||||||
self.__new_socketaddr(self.ipaddr(s), port)
|
self.__new_skaddr(self.ipaddr(s), port)
|
||||||
} else {
|
} else {
|
||||||
if __istype(__ct.lb_socketaddr, s) {
|
if __istype(__ct.lb_socketaddr, s) {
|
||||||
__new(__ct.lb_socketaddr, s) // copy constructor
|
__new(__ct.lb_socketaddr, s) // copy constructor
|
||||||
} else if __istype(__ct.lb_ipaddr, s) {
|
} else if __istype(__ct.lb_ipaddr, s) {
|
||||||
self.__new_socketaddr(s, 0) // default port 0
|
self.__new_skaddr(s, 0) // default port 0
|
||||||
} else {
|
} else {
|
||||||
self.__parse_socketaddr(s)
|
self.__parse_skaddr(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Lua-C" fn __new_socketaddr(&self, ip: &lb_ipaddr, port: u16) -> lb_socketaddr {
|
extern "Lua-C" fn __new_skaddr(&self, ip: &lb_ipaddr, port: u16) -> lb_socketaddr {
|
||||||
SocketAddr::new(ip.0, port).into()
|
SocketAddr::new(ip.0, port).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Lua-C" fn __parse_socketaddr(&self, s: &str) -> Result<lb_socketaddr, AddrParseError> {
|
extern "Lua-C" fn __parse_skaddr(&self, s: &str) -> Result<lb_socketaddr> {
|
||||||
s.parse()
|
Ok(s.parse()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new TCP socket configured for IPv4.
|
/// Creates a new TCP socket configured for IPv4.
|
||||||
///
|
///
|
||||||
/// See [`TcpSocket::new_v4`].
|
/// See [`TcpSocket::new_v4`].
|
||||||
///
|
pub extern "Lua-C" fn tcp(&self) -> Result<lb_tcpsocket> {
|
||||||
/// # Errors
|
Ok(Some(TcpSocket::new_v4()?).into())
|
||||||
///
|
|
||||||
/// Throws if an error was encountered during the socket creation.
|
|
||||||
pub extern "Lua-C" fn tcp_v4(&self) -> io::Result<lb_tcpsocket> {
|
|
||||||
TcpSocket::new_v4().map(lb_tcpsocket)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new TCP socket configured for IPv6.
|
/// Creates a new TCP socket configured for IPv6.
|
||||||
///
|
///
|
||||||
/// See [`TcpSocket::new_v6`].
|
/// See [`TcpSocket::new_v6`].
|
||||||
///
|
pub extern "Lua-C" fn tcp6(&self) -> Result<lb_tcpsocket> {
|
||||||
/// # Errors
|
Ok(Some(TcpSocket::new_v6()?).into())
|
||||||
///
|
}
|
||||||
/// Throws if an error was encountered during the socket creation.
|
|
||||||
pub extern "Lua-C" fn tcp_v6(&self) -> io::Result<lb_tcpsocket> {
|
pub extern "Lua" fn bind_tcp(&self, addr: any, port: any) -> Result<lb_tcpsocket> {
|
||||||
TcpSocket::new_v6().map(lb_tcpsocket)
|
let addr = self.socketaddr(addr, port);
|
||||||
|
let socket;
|
||||||
|
if addr.ip().is_v6() {
|
||||||
|
socket = self.tcp6();
|
||||||
|
} else {
|
||||||
|
socket = self.tcp();
|
||||||
|
}
|
||||||
|
socket.bind(addr);
|
||||||
|
socket
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "Lua" fn connect_tcp(&self, addr: any, port: any) -> Result<lb_tcpstream> {
|
||||||
|
let addr = self.socketaddr(addr, port);
|
||||||
|
let socket;
|
||||||
|
if addr.ip().is_v6() {
|
||||||
|
socket = self.tcp6();
|
||||||
|
} else {
|
||||||
|
socket = self.tcp();
|
||||||
|
}
|
||||||
|
socket.connect(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "Lua" fn listen_tcp(&self, addr: any, port: any) -> Result<lb_tcplistener> {
|
||||||
|
self.bind_tcp(addr, port).listen(1024)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +303,7 @@ impl lb_socketaddr {
|
|||||||
|
|
||||||
/// Sets the IP part of this address.
|
/// Sets the IP part of this address.
|
||||||
///
|
///
|
||||||
/// This function accepts the same arguments as [`ipaddr`](lb_libnet::ipaddr).
|
/// This function accepts the same arguments as [`ipaddr`](lb_netlib::ipaddr).
|
||||||
pub extern "Lua" fn set_ip(&mut self, s: any) -> &mut Self {
|
pub extern "Lua" fn set_ip(&mut self, s: any) -> &mut Self {
|
||||||
if __istype(__ct.lb_ipaddr, s) {
|
if __istype(__ct.lb_ipaddr, s) {
|
||||||
self.__set_ip(s);
|
self.__set_ip(s);
|
||||||
@@ -290,8 +319,8 @@ impl lb_socketaddr {
|
|||||||
self.0.set_ip(ip.0);
|
self.0.set_ip(ip.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "Lua-C" fn __set_ip_parse(&mut self, s: &str) -> Result<(), AddrParseError> {
|
extern "Lua-C" fn __set_ip_parse(&mut self, s: &str) -> Result<()> {
|
||||||
s.parse().map(|ip| self.0.set_ip(ip))
|
Ok(self.0.set_ip(s.parse()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the port part of this address.
|
/// Returns the port part of this address.
|
||||||
@@ -300,7 +329,7 @@ impl lb_socketaddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the port part of this address.
|
/// Sets the port part of this address.
|
||||||
pub extern "Lua" fn set_port(&mut self, port: number) -> &mut Self {
|
pub extern "Lua" fn set_port(&mut self, port: integer) -> &mut Self {
|
||||||
self.__set_port(port);
|
self.__set_port(port);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -316,13 +345,125 @@ impl lb_socketaddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A TCP socket which has not yet been converted to a [`lb_tcpstream`] or [`lb_tcplistener`].
|
/// A TCP socket which has not yet been converted to an [`lb_tcpstream`] or [`lb_tcplistener`].
|
||||||
#[derive(Debug, From)]
|
#[derive(Debug, From)]
|
||||||
#[cdef]
|
#[cdef]
|
||||||
pub struct lb_tcpsocket(#[opaque] TcpSocket);
|
pub struct lb_tcpsocket(#[opaque] Option<TcpSocket>);
|
||||||
|
|
||||||
#[metatype]
|
#[metatype]
|
||||||
impl lb_tcpsocket {}
|
impl lb_tcpsocket {
|
||||||
|
fn socket(&self) -> Result<&TcpSocket> {
|
||||||
|
self.0.as_ref().ok_or(Error::SocketConsumed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::keepalive`].
|
||||||
|
pub extern "Lua-C" fn keepalive(&self) -> Result<bool> {
|
||||||
|
Ok(self.socket()?.keepalive()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_keepalive`].
|
||||||
|
pub extern "Lua-C" fn set_keepalive(&self, enabled: bool) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_keepalive(enabled)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::reuseaddr`].
|
||||||
|
pub extern "Lua-C" fn reuseaddr(&self) -> Result<bool> {
|
||||||
|
Ok(self.socket()?.reuseaddr()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_reuseaddr`].
|
||||||
|
pub extern "Lua-C" fn set_reuseaddr(&self, enabled: bool) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_reuseaddr(enabled)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::reuseport`].
|
||||||
|
pub extern "Lua-C" fn reuseport(&self) -> Result<bool> {
|
||||||
|
Ok(self.socket()?.reuseport()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_reuseport`].
|
||||||
|
pub extern "Lua-C" fn set_reuseport(&self, enabled: bool) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_reuseport(enabled)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::send_buffer_size`].
|
||||||
|
pub extern "Lua-C" fn sendbuf(&self) -> Result<u32> {
|
||||||
|
Ok(self.socket()?.send_buffer_size()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_send_buffer_size`].
|
||||||
|
pub extern "Lua-C" fn set_sendbuf(&self, size: u32) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_send_buffer_size(size)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::recv_buffer_size`].
|
||||||
|
pub extern "Lua-C" fn recvbuf(&self) -> Result<u32> {
|
||||||
|
Ok(self.socket()?.recv_buffer_size()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_recv_buffer_size`].
|
||||||
|
pub extern "Lua-C" fn set_recvbuf(&self, size: u32) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_recv_buffer_size(size)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::linger`].
|
||||||
|
pub extern "Lua-C" fn linger(&self) -> Result<f64> {
|
||||||
|
Ok(self
|
||||||
|
.socket()?
|
||||||
|
.linger()?
|
||||||
|
.map(|n| n.as_secs_f64())
|
||||||
|
.unwrap_or(0.))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_linger`].
|
||||||
|
pub extern "Lua-C" fn set_linger(&self, secs: f64) -> Result<()> {
|
||||||
|
Ok(self
|
||||||
|
.socket()?
|
||||||
|
.set_linger((secs != 0.).then_some(Duration::from_secs_f64(secs)))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::nodelay`].
|
||||||
|
pub extern "Lua-C" fn nodelay(&self) -> Result<bool> {
|
||||||
|
Ok(self.socket()?.nodelay()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_nodelay`].
|
||||||
|
pub extern "Lua-C" fn set_nodelay(&self, enabled: bool) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_nodelay(enabled)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::tos`].
|
||||||
|
pub extern "Lua-C" fn tos(&self) -> Result<u32> {
|
||||||
|
Ok(self.socket()?.tos()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::set_tos`].
|
||||||
|
pub extern "Lua-C" fn set_tos(&self, tos: u32) -> Result<()> {
|
||||||
|
Ok(self.socket()?.set_tos(tos)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::local_addr`].
|
||||||
|
pub extern "Lua-C" fn local_addr(&self) -> Result<lb_socketaddr> {
|
||||||
|
Ok(self.socket()?.local_addr()?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::bind`].
|
||||||
|
pub extern "Lua-C" fn bind(&self, addr: &lb_socketaddr) -> Result<()> {
|
||||||
|
Ok(self.socket()?.bind(addr.0)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::connect`].
|
||||||
|
pub async extern "Lua-C" fn connect(&mut self, addr: &lb_socketaddr) -> Result<lb_tcpstream> {
|
||||||
|
let socket = self.0.take().ok_or(Error::SocketConsumed)?;
|
||||||
|
Ok(socket.connect(addr.0).await?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`TcpSocket::listen`].
|
||||||
|
pub extern "Lua-C" fn listen(&mut self, backlog: u32) -> Result<lb_tcplistener> {
|
||||||
|
let socket = self.0.take().ok_or(Error::SocketConsumed)?;
|
||||||
|
Ok(socket.listen(backlog)?.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, From)]
|
#[derive(Debug, From)]
|
||||||
#[cdef]
|
#[cdef]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{channel::lb_libchannel, fs::lb_libfs, net::lb_libnet, task::lb_libtask};
|
use crate::{chan::lb_chanlib, fs::lb_fslib, net::lb_netlib, task::lb_tasklib};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use luaffi::{Registry, Type};
|
use luaffi::{Registry, Type};
|
||||||
use luajit::{Chunk, State};
|
use luajit::{Chunk, State};
|
||||||
@@ -18,10 +18,10 @@ impl Builder {
|
|||||||
let mut registry = Registry::new();
|
let mut registry = Registry::new();
|
||||||
|
|
||||||
registry
|
registry
|
||||||
.preload::<lb_libtask>("lb:task")
|
.preload::<lb_tasklib>("lb:task")
|
||||||
.preload::<lb_libchannel>("lb:channel")
|
.preload::<lb_chanlib>("lb:channel")
|
||||||
.preload::<lb_libfs>("lb:fs")
|
.preload::<lb_fslib>("lb:fs")
|
||||||
.preload::<lb_libnet>("lb:net");
|
.preload::<lb_netlib>("lb:net");
|
||||||
|
|
||||||
Self { registry }
|
Self { registry }
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,7 @@ impl Builder {
|
|||||||
let mut s = State::new()?;
|
let mut s = State::new()?;
|
||||||
let mut chunk = Chunk::new(self.registry.done());
|
let mut chunk = Chunk::new(self.registry.done());
|
||||||
chunk.extend(include_bytes!("./runtime.lua"));
|
chunk.extend(include_bytes!("./runtime.lua"));
|
||||||
|
// println!("{chunk}");
|
||||||
s.eval(chunk.path("[luby]"), 0, 0)?;
|
s.eval(chunk.path("[luby]"), 0, 0)?;
|
||||||
s
|
s
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::{ffi::c_int, process};
|
|||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
|
|
||||||
#[cdef]
|
#[cdef]
|
||||||
pub struct lb_libtask;
|
pub struct lb_tasklib;
|
||||||
|
|
||||||
#[metatype]
|
#[metatype]
|
||||||
impl lb_libtask {
|
impl lb_tasklib {
|
||||||
#[new]
|
#[new]
|
||||||
extern "Lua-C" fn new() -> Self {
|
extern "Lua-C" fn new() -> Self {
|
||||||
Self
|
Self
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ authors.workspace = true
|
|||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
option_ref_abi = []
|
||||||
|
option_string_abi = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bstr = "1.12.0"
|
bstr = "1.12.0"
|
||||||
luaffi_impl = { path = "../luaffi_impl" }
|
luaffi_impl = { path = "../luaffi_impl" }
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ use std::{
|
|||||||
pub mod stub_types {
|
pub mod stub_types {
|
||||||
pub struct any;
|
pub struct any;
|
||||||
pub struct nil;
|
pub struct nil;
|
||||||
pub struct boolean;
|
pub type boolean = bool;
|
||||||
pub struct lightuserdata;
|
pub struct lightuserdata;
|
||||||
pub struct number;
|
pub struct number;
|
||||||
pub struct integer;
|
pub struct integer;
|
||||||
pub struct string;
|
pub type string = String;
|
||||||
pub struct table;
|
pub struct table;
|
||||||
pub struct function;
|
pub struct function;
|
||||||
pub struct userdata;
|
pub struct userdata;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
---@diagnostic disable
|
||||||
local LUA_REFNIL = -1 -- lib_aux.c
|
local LUA_REFNIL = -1 -- lib_aux.c
|
||||||
local FREELIST_REF = 0
|
local FREELIST_REF = 0
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ use std::{
|
|||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod future;
|
|
||||||
pub mod string;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[path = "./internal.rs"]
|
#[path = "./internal.rs"]
|
||||||
pub mod __internal;
|
pub mod __internal;
|
||||||
|
pub mod future;
|
||||||
|
pub mod option;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
|
pub mod string;
|
||||||
|
|
||||||
// Dummy function to ensure that strings passed to Rust via wrapper objects will not be
|
// Dummy function to ensure that strings passed to Rust via wrapper objects will not be
|
||||||
// garbage-collected until the end of the function (used in string.rs when string marshalling is
|
// garbage-collected until the end of the function (used in string.rs when string marshalling is
|
||||||
@@ -345,12 +345,12 @@ impl<'r> MetatypeBuilder<'r> {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
write!(self.lua, "__idx.{name} = ").unwrap();
|
write!(self.lua, "__idx.{name} = ").unwrap();
|
||||||
f(&mut MetatypeMethodBuilder::new(self));
|
f(&mut MetatypeMethodBuilder::new(self));
|
||||||
write!(self.lua, "; ").unwrap();
|
writeln!(self.lua, ";").unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index_raw(&mut self, name: impl Display, value: impl Display) -> &mut Self {
|
pub fn index_raw(&mut self, name: impl Display, value: impl Display) -> &mut Self {
|
||||||
write!(self.lua, "__idx.{name} = {value}; ").unwrap();
|
writeln!(self.lua, "__idx.{name} = {value};").unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,12 +361,12 @@ impl<'r> MetatypeBuilder<'r> {
|
|||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
write!(self.lua, "__mt.__{name} = ").unwrap();
|
write!(self.lua, "__mt.__{name} = ").unwrap();
|
||||||
f(&mut MetatypeMethodBuilder::new(self));
|
f(&mut MetatypeMethodBuilder::new(self));
|
||||||
write!(self.lua, "; ").unwrap();
|
writeln!(self.lua, ";").unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metatable_raw(&mut self, name: impl Display, value: impl Display) -> &mut Self {
|
pub fn metatable_raw(&mut self, name: impl Display, value: impl Display) -> &mut Self {
|
||||||
write!(self.lua, "__mt.__{name} = {value}; ").unwrap();
|
writeln!(self.lua, "__mt.__{name} = {value};").unwrap();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -857,7 +857,9 @@ macro_rules! impl_ptr_intoabi {
|
|||||||
|
|
||||||
impl_ptr_intoabi!(*const T);
|
impl_ptr_intoabi!(*const T);
|
||||||
impl_ptr_intoabi!(*mut T);
|
impl_ptr_intoabi!(*mut T);
|
||||||
|
#[cfg(feature = "option_ref_abi")] // disabled because it conflicts with the generic Option<T> impl
|
||||||
impl_ptr_intoabi!(Option<&'static T>);
|
impl_ptr_intoabi!(Option<&'static T>);
|
||||||
|
#[cfg(feature = "option_ref_abi")]
|
||||||
impl_ptr_intoabi!(Option<&'static mut T>);
|
impl_ptr_intoabi!(Option<&'static mut T>);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
84
crates/luaffi/src/option.rs
Normal file
84
crates/luaffi/src/option.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use crate::{
|
||||||
|
__internal::{disp, display},
|
||||||
|
Cdef, CdefBuilder, IntoFfi, KEEP_FN, Type, TypeBuilder, TypeType,
|
||||||
|
};
|
||||||
|
use std::{ffi::c_int, fmt::Display};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum lua_option<T> {
|
||||||
|
None, // __tag = 0
|
||||||
|
Some(T), // __tag = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Type> Type for lua_option<T> {
|
||||||
|
fn name() -> impl Display {
|
||||||
|
display!("option__{}", T::name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ty() -> TypeType {
|
||||||
|
TypeType::Aggregate
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cdecl(name: impl Display) -> impl Display {
|
||||||
|
display!("struct {} {name}", Self::name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(b: &mut TypeBuilder) {
|
||||||
|
b.cdef::<Self>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Type> Cdef for lua_option<T> {
|
||||||
|
fn build(b: &mut CdefBuilder) {
|
||||||
|
b.field::<c_int>("__tag");
|
||||||
|
(T::ty() != TypeType::Void).then(|| b.field::<T>("__value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: IntoFfi> IntoFfi for Option<T> {
|
||||||
|
type Into = lua_option<T::Into>;
|
||||||
|
|
||||||
|
fn convert(self) -> Self::Into {
|
||||||
|
match self {
|
||||||
|
Some(value) => lua_option::Some(T::convert(value)),
|
||||||
|
None => lua_option::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn require_owned() -> bool {
|
||||||
|
// lua_option is only used to transmit information about whether we have a value or not and
|
||||||
|
// is forgotten immediately after use, so there is no need for an owned option
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postlude(ret: &str) -> impl Display {
|
||||||
|
disp(move |f| {
|
||||||
|
write!(f, "if {ret}.__tag ~= 0 then ")?;
|
||||||
|
match T::Into::ty() {
|
||||||
|
TypeType::Void => write!(f, "{ret} = nil; ")?, // for void options, we don't have a __value
|
||||||
|
TypeType::Primitive => {
|
||||||
|
// can always copy primitives to stack
|
||||||
|
write!(f, "{ret} = {ret}.__value; {}", T::postlude(ret))?;
|
||||||
|
}
|
||||||
|
TypeType::Aggregate => {
|
||||||
|
let ct = T::Into::name();
|
||||||
|
if T::require_owned() {
|
||||||
|
// inner value requires ownership; copy it into its own cdata and forget
|
||||||
|
// option.
|
||||||
|
write!(f, "{ret} = __new(__ct.{ct}, {ret}.__value); ")?;
|
||||||
|
write!(f, "{}", T::postlude(ret))?;
|
||||||
|
} else {
|
||||||
|
// inner value is a "temporary" like an option itself and doesn't require
|
||||||
|
// full ownership of itself. we just need to keep the option object alive
|
||||||
|
// until its postlude completes.
|
||||||
|
write!(f, "local {ret}_keep = {ret}; {ret} = {ret}.__value; ")?;
|
||||||
|
write!(f, "do {}end; ", T::postlude(ret))?;
|
||||||
|
write!(f, "__C.{KEEP_FN}({ret}_keep); ")?; // keep original option alive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "else {ret} = nil; end; ")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,12 +72,12 @@ unsafe impl<T: IntoFfi, E: Display> IntoFfi for Result<T, E> {
|
|||||||
write!(f, "{ret} = __new(__ct.{ct}, {ret}.__value); ")?;
|
write!(f, "{ret} = __new(__ct.{ct}, {ret}.__value); ")?;
|
||||||
write!(f, "{}", T::postlude(ret))?;
|
write!(f, "{}", T::postlude(ret))?;
|
||||||
} else {
|
} else {
|
||||||
// inner value is a "temporary" itself and doesn't require full ownership of
|
// inner value is a "temporary" like a result itself and doesn't require
|
||||||
// itself. we just need to keep the result object alive until its postlude
|
// full ownership of itself. we just need to keep the result object alive
|
||||||
// completes.
|
// until its postlude completes.
|
||||||
write!(f, "local __{ret} = {ret}; {ret} = {ret}.__value; ")?;
|
write!(f, "local {ret}_keep = {ret}; {ret} = {ret}.__value; ")?;
|
||||||
write!(f, "do {}end; ", T::postlude(ret))?;
|
write!(f, "do {}end; ", T::postlude(ret))?;
|
||||||
write!(f, "__C.{KEEP_FN}(__{ret}); ")?; // keep original result alive
|
write!(f, "__C.{KEEP_FN}({ret}_keep); ")?; // keep original result alive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bstr::{BStr, BString};
|
use bstr::{BStr, BString};
|
||||||
use luaffi_impl::{cdef, metatype};
|
use luaffi_impl::{cdef, metatype};
|
||||||
use std::{fmt::Display, mem::ManuallyDrop, ptr, slice};
|
use std::{fmt::Display, mem::ManuallyDrop, slice};
|
||||||
|
|
||||||
pub(crate) const IS_UTF8_FN: &str = "luaffi_is_utf8";
|
pub(crate) const IS_UTF8_FN: &str = "luaffi_is_utf8";
|
||||||
pub(crate) const DROP_BUFFER_FN: &str = "luaffi_drop_buffer";
|
pub(crate) const DROP_BUFFER_FN: &str = "luaffi_drop_buffer";
|
||||||
@@ -42,6 +42,7 @@ impl lua_buf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "option_string_abi")]
|
||||||
pub(crate) fn null() -> Self {
|
pub(crate) fn null() -> Self {
|
||||||
Self {
|
Self {
|
||||||
__ptr: ptr::null(),
|
__ptr: ptr::null(),
|
||||||
@@ -71,6 +72,7 @@ impl lua_buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "option_string_abi")]
|
||||||
pub(crate) fn null() -> Self {
|
pub(crate) fn null() -> Self {
|
||||||
Self {
|
Self {
|
||||||
__ptr: ptr::null_mut(),
|
__ptr: ptr::null_mut(),
|
||||||
@@ -228,56 +230,64 @@ impl_into_via!(&'static str, &'static BStr);
|
|||||||
impl_into_via!(BString, Vec<u8>);
|
impl_into_via!(BString, Vec<u8>);
|
||||||
impl_into_via!(String, BString);
|
impl_into_via!(String, BString);
|
||||||
|
|
||||||
macro_rules! impl_optional_from {
|
// `Option<String>: From/IntoFfi` isn't implemented because it conflicts with the generic
|
||||||
($ty:ty) => {
|
// `Option<T>: From/IntoFfi` impl and rust doesn't have specialisation yet (and probably not anytime
|
||||||
unsafe impl<'s> FromFfi for Option<$ty> {
|
// soon). this is fine for now because we have specialisation for string-like parameters implemented
|
||||||
type From = <$ty as FromFfi>::From;
|
// in the #[metatype] macro already, and string returns wrapped in `Option<T>` isn't much additional
|
||||||
|
// overhead.
|
||||||
|
#[cfg(feature = "option_string_abi")]
|
||||||
|
mod impl_option_string {
|
||||||
|
macro_rules! impl_optional_from {
|
||||||
|
($ty:ty) => {
|
||||||
|
unsafe impl<'s> FromFfi for Option<$ty> {
|
||||||
|
type From = <$ty as FromFfi>::From;
|
||||||
|
|
||||||
fn require_keepalive() -> bool {
|
fn require_keepalive() -> bool {
|
||||||
<$ty as FromFfi>::require_keepalive()
|
<$ty as FromFfi>::require_keepalive()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prelude(arg: &str) -> impl Display {
|
fn prelude(arg: &str) -> impl Display {
|
||||||
// just pass a null pointer if argument is nil
|
// just pass a null pointer if argument is nil
|
||||||
display!(
|
display!(
|
||||||
"if {arg} ~= nil then {}end; ",
|
"if {arg} ~= nil then {}end; ",
|
||||||
<$ty as FromFfi>::prelude(arg)
|
<$ty as FromFfi>::prelude(arg)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert(from: Self::From) -> Self {
|
fn convert(from: Self::From) -> Self {
|
||||||
from.map(|s| <$ty as FromFfi>::convert(Some(s)))
|
from.map(|s| <$ty as FromFfi>::convert(Some(s)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
|
impl_optional_from!(&'s [u8]);
|
||||||
|
impl_optional_from!(&'s BStr);
|
||||||
|
impl_optional_from!(&'s str);
|
||||||
|
|
||||||
|
macro_rules! impl_optional_into {
|
||||||
|
($ty:ty, $null:expr) => {
|
||||||
|
unsafe impl IntoFfi for Option<$ty> {
|
||||||
|
type Into = <$ty as IntoFfi>::Into;
|
||||||
|
|
||||||
|
fn convert(self) -> Self::Into {
|
||||||
|
self.map_or($null, <$ty as IntoFfi>::convert)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn postlude(ret: &str) -> impl Display {
|
||||||
|
display!(
|
||||||
|
"if {ret}.__ptr == nil then {ret} = nil; else {}end; ",
|
||||||
|
<$ty as IntoFfi>::postlude(ret)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_optional_into!(&'static [u8], lua_buf::null());
|
||||||
|
impl_optional_into!(&'static BStr, lua_buf::null());
|
||||||
|
impl_optional_into!(&'static str, lua_buf::null());
|
||||||
|
impl_optional_into!(Vec<u8>, lua_buffer::null());
|
||||||
|
impl_optional_into!(BString, lua_buffer::null());
|
||||||
|
impl_optional_into!(String, lua_buffer::null());
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_optional_from!(&'s [u8]);
|
|
||||||
impl_optional_from!(&'s BStr);
|
|
||||||
impl_optional_from!(&'s str);
|
|
||||||
|
|
||||||
macro_rules! impl_optional_into {
|
|
||||||
($ty:ty, $null:expr) => {
|
|
||||||
unsafe impl IntoFfi for Option<$ty> {
|
|
||||||
type Into = <$ty as IntoFfi>::Into;
|
|
||||||
|
|
||||||
fn convert(self) -> Self::Into {
|
|
||||||
self.map_or($null, <$ty as IntoFfi>::convert)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn postlude(ret: &str) -> impl Display {
|
|
||||||
display!(
|
|
||||||
"if {ret}.__ptr == nil then {ret} = nil; else {}end; ",
|
|
||||||
<$ty as IntoFfi>::postlude(ret)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_optional_into!(&'static [u8], lua_buf::null());
|
|
||||||
impl_optional_into!(&'static BStr, lua_buf::null());
|
|
||||||
impl_optional_into!(&'static str, lua_buf::null());
|
|
||||||
impl_optional_into!(Vec<u8>, lua_buffer::null());
|
|
||||||
impl_optional_into!(BString, lua_buffer::null());
|
|
||||||
impl_optional_into!(String, lua_buffer::null());
|
|
||||||
|
|||||||
@@ -763,13 +763,13 @@ fn inject_merged_drop(registry: &mut Registry, lua: Option<&LuaFunction>) -> Res
|
|||||||
|
|
||||||
fn document_ffi_function(func: &mut ImplItemFn) {
|
fn document_ffi_function(func: &mut ImplItemFn) {
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
func.attrs.insert(0, parse_quote!(#[doc =
|
||||||
r#"<span class="stab" title="This is a C/FFI function." style="float: right; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;">FFI</span>"#
|
r#"<span class="stab" title="This function is implemented in Rust and called via FFI." style="float: right; background: #fff5d6; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;">FFI</span>"#
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_lua_function(func: &mut ImplItemFn) {
|
fn document_lua_function(func: &mut ImplItemFn) {
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
func.attrs.insert(0, parse_quote!(#[doc =
|
||||||
r#"<span class="stab" title="This is a Lua function." style="float: right; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;">Lua</span>"#
|
r#"<span class="stab" title="This function is implemented in Lua." style="float: right; background: #ebf5ff; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;">Lua</span>"#
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,6 +799,10 @@ fn document_metamethod(func: &mut ImplItemFn, method: Metamethod) {
|
|||||||
_ => format!("This is a metamethod and cannot be called directly."),
|
_ => format!("This is a metamethod and cannot be called directly."),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
func.attrs.insert(0, parse_quote!(#[doc =
|
||||||
|
r#"<span class="stab" title="This function is a metamethod." style="float: right; background: #ebf5ff; margin-left: 3px; padding-left: 5px; padding-right: 5px;">Metamethod</span>"#
|
||||||
|
]));
|
||||||
|
|
||||||
func.attrs.push(parse_quote!(#[doc = ""]));
|
func.attrs.push(parse_quote!(#[doc = ""]));
|
||||||
func.attrs.push(parse_quote!(#[doc = #s]));
|
func.attrs.push(parse_quote!(#[doc = #s]));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
pub use lb::fs;
|
pub use lb::*;
|
||||||
pub use lb::net;
|
|
||||||
|
|||||||
42
src/main.rs
42
src/main.rs
@@ -1,7 +1,9 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use mimalloc::MiMalloc;
|
use mimalloc::MiMalloc;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use std::{backtrace::Backtrace, fmt::Display, net::SocketAddr, num::NonZero, panic, thread};
|
use std::{
|
||||||
|
backtrace::Backtrace, fmt::Display, net::SocketAddr, num::NonZero, panic, process, thread,
|
||||||
|
};
|
||||||
use sysexits::ExitCode;
|
use sysexits::ExitCode;
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
@@ -20,21 +22,23 @@ fn panic_cb(panic: &panic::PanicHookInfo) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
eprint!(
|
eprint!(
|
||||||
"{}:\n{trace}",
|
"{}\n{trace}",
|
||||||
format_args!(
|
format_args!(
|
||||||
"thread '{}' panicked at {location}: {msg}",
|
"thread '{}' panicked at {location}: {msg}",
|
||||||
thread::current().name().unwrap_or("<unnamed>")
|
thread::current().name().unwrap_or("<unnamed>")
|
||||||
)
|
)
|
||||||
.red()
|
.red()
|
||||||
|
.bold()
|
||||||
);
|
);
|
||||||
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}",
|
"{}",
|
||||||
format_args!(
|
format_args!(
|
||||||
"This is a bug in luby. Please kindly report this at {}.",
|
"luby should never panic. Please kindly report this bug at {}.",
|
||||||
env!("CARGO_PKG_REPOSITORY")
|
env!("CARGO_PKG_REPOSITORY")
|
||||||
)
|
)
|
||||||
.yellow()
|
.yellow()
|
||||||
|
.bold()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +97,15 @@ struct Args {
|
|||||||
)]
|
)]
|
||||||
console_addr: SocketAddr,
|
console_addr: SocketAddr,
|
||||||
|
|
||||||
|
/// Dump internal data.
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
help_heading = "Debugging",
|
||||||
|
value_name = "DATA",
|
||||||
|
value_parser = ["cdef"]
|
||||||
|
)]
|
||||||
|
dump: Vec<String>,
|
||||||
|
|
||||||
/// Print version.
|
/// Print version.
|
||||||
#[clap(long, short = 'V')]
|
#[clap(long, short = 'V')]
|
||||||
version: bool,
|
version: bool,
|
||||||
@@ -110,17 +123,17 @@ impl Args {
|
|||||||
|
|
||||||
fn exit_err<T, E: Display>(code: ExitCode) -> impl FnOnce(E) -> T {
|
fn exit_err<T, E: Display>(code: ExitCode) -> impl FnOnce(E) -> T {
|
||||||
move |err| {
|
move |err| {
|
||||||
eprintln!("{}", err.red());
|
eprintln!("{}", err.red().bold());
|
||||||
code.exit()
|
code.exit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), ExitCode> {
|
fn main() {
|
||||||
panic::set_hook(Box::new(panic_cb));
|
panic::set_hook(Box::new(panic_cb));
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
if args.version {
|
if args.version {
|
||||||
return Ok(print_version());
|
return print_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
init_logger(&args);
|
init_logger(&args);
|
||||||
@@ -194,6 +207,11 @@ fn init_tokio(args: &Args) -> tokio::runtime::Runtime {
|
|||||||
|
|
||||||
fn init_lua(args: &Args) -> lb::runtime::Runtime {
|
fn init_lua(args: &Args) -> lb::runtime::Runtime {
|
||||||
let rt = lb::runtime::Builder::new();
|
let rt = lb::runtime::Builder::new();
|
||||||
|
|
||||||
|
if args.dump.iter().find(|s| *s == "cdef").is_some() {
|
||||||
|
print!("{}", rt.registry());
|
||||||
|
}
|
||||||
|
|
||||||
let mut rt = rt.build().unwrap_or_else(exit_err(ExitCode::Software));
|
let mut rt = rt.build().unwrap_or_else(exit_err(ExitCode::Software));
|
||||||
|
|
||||||
for arg in args.jit.iter() {
|
for arg in args.jit.iter() {
|
||||||
@@ -232,13 +250,13 @@ fn parse_jitlib_cmd(s: &str) -> Option<(&str, &str)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn main_async(args: Args, state: &mut luajit::State) -> Result<(), ExitCode> {
|
async fn main_async(args: Args, state: &mut luajit::State) {
|
||||||
for ref path in args.path {
|
for ref path in args.path {
|
||||||
let mut s = state.guard();
|
let mut s = state.guard();
|
||||||
let chunk = match std::fs::read(path) {
|
let chunk = match std::fs::read(path) {
|
||||||
Ok(chunk) => chunk,
|
Ok(chunk) => chunk,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("{}", format_args!("{path}: {err}").red());
|
eprintln!("{}", format_args!("{path}: {err}").red().bold());
|
||||||
ExitCode::NoInput.exit();
|
ExitCode::NoInput.exit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -248,13 +266,11 @@ async fn main_async(args: Args, state: &mut luajit::State) -> Result<(), ExitCod
|
|||||||
|
|
||||||
if let Err(err) = s.call_async(0, 0).await {
|
if let Err(err) = s.call_async(0, 0).await {
|
||||||
match err.trace() {
|
match err.trace() {
|
||||||
Some(trace) => eprintln!("{}\n{trace}", err.red()), // runtime error
|
Some(trace) => eprintln!("{}\n{trace}", err.red().bold()),
|
||||||
None => eprintln!("{}", err.red()),
|
None => eprintln!("{}", err.red().bold()),
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitCode::DataErr.exit();
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
21
test.lua
21
test.lua
@@ -1,6 +1,19 @@
|
|||||||
local ffi = require("ffi")
|
local fs = require("lb:fs")
|
||||||
local lb = ffi.new("struct lb_core")
|
|
||||||
|
|
||||||
print(lb)
|
-- do
|
||||||
|
-- local start = os.clock()
|
||||||
|
-- for i = 1, 50000 do
|
||||||
|
-- fs:read("crates/luaffi_impl/src/metatype.rs")
|
||||||
|
-- end
|
||||||
|
-- local finish = os.clock()
|
||||||
|
-- print("finish in " .. (finish - start))
|
||||||
|
-- end
|
||||||
|
|
||||||
lb.spawn("")
|
do
|
||||||
|
local start = os.clock()
|
||||||
|
for i = 1, 30000 do
|
||||||
|
fs:read_sync("bacon.toml")
|
||||||
|
end
|
||||||
|
local finish = os.clock()
|
||||||
|
print("finish in " .. (finish - start))
|
||||||
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user