Fix all borrow errors
This commit is contained in:
parent
124e9bedfe
commit
eaa40ff3bc
@ -12,9 +12,12 @@
|
||||
//! ## Exports
|
||||
//!
|
||||
//! See [`lb_fslib`] for items exported by this library.
|
||||
use derive_more::From;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::{path::PathBuf, time::SystemTime};
|
||||
use std::{
|
||||
cell::{BorrowError, BorrowMutError, RefCell},
|
||||
path::PathBuf,
|
||||
time::SystemTime,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can be thrown by this library.
|
||||
@ -23,6 +26,12 @@ use thiserror::Error;
|
||||
/// using [`pcall(f, ...)`](https://www.lua.org/manual/5.1/manual.html#pdf-pcall).
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Attempt to access an object while it is being modified.
|
||||
#[error("cannot access object while it is being modified")]
|
||||
Borrow(#[from] BorrowError),
|
||||
/// Attempt to modify an object while it is in use
|
||||
#[error("cannot modify object while it is in use")]
|
||||
BorrowMut(#[from] BorrowMutError),
|
||||
/// I/O error.
|
||||
#[error("{0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
@ -54,38 +63,85 @@ impl lb_fslib {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Reads the entire contents of a file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file does not exist or cannot be read.
|
||||
pub async extern "Lua-C" fn read(path: &str) -> Result<Vec<u8>> {
|
||||
Ok(tokio::fs::read(path).await?)
|
||||
}
|
||||
|
||||
/// Reads the entire contents of a file synchronously.
|
||||
///
|
||||
/// This is a synchronous complement to [`read`](Self::read).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file does not exist or cannot be read.
|
||||
pub extern "Lua-C" fn read_sync(path: &str) -> Result<Vec<u8>> {
|
||||
Ok(std::fs::read(path)?)
|
||||
}
|
||||
|
||||
/// Writes the given contents to a file, replacing its contents if it exists.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file cannot be written.
|
||||
pub async extern "Lua-C" fn write(path: &str, contents: &[u8]) -> Result<()> {
|
||||
Ok(tokio::fs::write(path, contents).await?)
|
||||
}
|
||||
|
||||
/// Writes the given contents to a file synchronously, replacing its contents if it exists.
|
||||
///
|
||||
/// This is a synchronous complement to [`write`](Self::write).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file cannot be written.
|
||||
pub extern "Lua-C" fn write_sync(path: &str, contents: &[u8]) -> Result<()> {
|
||||
Ok(std::fs::write(path, contents)?)
|
||||
}
|
||||
|
||||
/// Reads the entries in a directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
pub async extern "Lua-C" fn read_dir(path: &str) -> Result<lb_read_dir> {
|
||||
Ok(tokio::fs::read_dir(path).await?.into())
|
||||
Ok(lb_read_dir::new(tokio::fs::read_dir(path).await?))
|
||||
}
|
||||
|
||||
/// Reads the entries in a directory synchronously.
|
||||
///
|
||||
/// This is a synchronous complement to [`read_dir`](Self::read_dir).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
pub extern "Lua-C" fn read_dir_sync(path: &str) -> Result<lb_read_dir_sync> {
|
||||
Ok(std::fs::read_dir(path)?.into())
|
||||
Ok(lb_read_dir_sync::new(std::fs::read_dir(path)?))
|
||||
}
|
||||
|
||||
/// Recursively walks a directory, yielding all entries within it.
|
||||
pub extern "Lua-C" fn walk_dir(path: &str) -> lb_walk_dir {
|
||||
walkdir::WalkDir::new(path).into_iter().into()
|
||||
lb_walk_dir::new(walkdir::WalkDir::new(path).into_iter())
|
||||
}
|
||||
|
||||
pub extern "Lua-C" fn glob(pattern: &str) -> Result<lb_glob_dir> {
|
||||
/// Returns an iterator over all files matching a glob pattern in the current directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the pattern is invalid.
|
||||
pub extern "Lua" fn glob(pattern: &str) -> Result<lb_glob_dir> {
|
||||
Self::glob_dir(".", pattern)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all files matching a glob pattern in the given directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the pattern is invalid.
|
||||
pub extern "Lua-C" fn glob_dir(path: &str, pattern: &str) -> Result<lb_glob_dir> {
|
||||
let prefix = PathBuf::from(path);
|
||||
let iter = walkdir::WalkDir::new(path).min_depth(1).into_iter();
|
||||
@ -93,76 +149,128 @@ impl lb_fslib {
|
||||
.add(globset::Glob::new(pattern)?)
|
||||
.build()?;
|
||||
|
||||
Ok(lb_glob_dir {
|
||||
iter,
|
||||
matcher,
|
||||
prefix,
|
||||
})
|
||||
Ok(lb_glob_dir::new(iter, matcher, prefix))
|
||||
}
|
||||
|
||||
/// Creates a new temporary directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the temporary directory cannot be created.
|
||||
pub extern "Lua-C" fn temp_dir() -> Result<lb_temp_dir> {
|
||||
Ok(tempfile::tempdir()?.into())
|
||||
Ok(lb_temp_dir::new(tempfile::tempdir()?))
|
||||
}
|
||||
|
||||
/// Creates a new temporary directory inside the specified path.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the temporary directory cannot be created.
|
||||
pub extern "Lua-C" fn temp_dir_in(path: &str) -> Result<lb_temp_dir> {
|
||||
Ok(tempfile::tempdir_in(path)?.into())
|
||||
Ok(lb_temp_dir::new(tempfile::tempdir_in(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over the entries in a directory.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_read_dir(#[opaque] tokio::fs::ReadDir);
|
||||
pub struct lb_read_dir(#[opaque] RefCell<tokio::fs::ReadDir>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_read_dir {
|
||||
fn new(iter: tokio::fs::ReadDir) -> Self {
|
||||
Self(RefCell::new(iter))
|
||||
}
|
||||
|
||||
/// Returns the next entry in the directory, or `nil` if there are no more entries.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
#[call]
|
||||
pub async extern "Lua-C" fn next(&mut self) -> Result<Option<lb_dir_entry>> {
|
||||
Ok(self.0.next_entry().await?.map(Into::into))
|
||||
pub async extern "Lua-C" fn next(&self) -> Result<Option<lb_dir_entry>> {
|
||||
Ok(self
|
||||
.0
|
||||
.try_borrow_mut()?
|
||||
.next_entry()
|
||||
.await?
|
||||
.map(lb_dir_entry::new))
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous version of [`lb_read_dir`].
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_read_dir_sync(#[opaque] std::fs::ReadDir);
|
||||
pub struct lb_read_dir_sync(#[opaque] RefCell<std::fs::ReadDir>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_read_dir_sync {
|
||||
fn new(iter: std::fs::ReadDir) -> Self {
|
||||
Self(RefCell::new(iter))
|
||||
}
|
||||
|
||||
/// Returns the next entry in the directory, or `nil` if there are no more entries.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
#[call]
|
||||
pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_dir_entry_sync>> {
|
||||
Ok(self.0.next().transpose()?.map(Into::into))
|
||||
pub extern "Lua-C" fn next(&self) -> Result<Option<lb_dir_entry_sync>> {
|
||||
Ok(self
|
||||
.0
|
||||
.try_borrow_mut()?
|
||||
.next()
|
||||
.transpose()?
|
||||
.map(lb_dir_entry_sync::new))
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry inside of a directory on the filesystem.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_dir_entry(#[opaque] tokio::fs::DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_dir_entry {
|
||||
fn new(entry: tokio::fs::DirEntry) -> Self {
|
||||
Self(entry)
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
pub extern "Lua-C" fn path(&self) -> String {
|
||||
self.0.path().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the file name of this entry.
|
||||
pub extern "Lua-C" fn name(&self) -> String {
|
||||
self.0.file_name().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the type of this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file type cannot be determined.
|
||||
pub async extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(self.0.file_type().await?.into())
|
||||
Ok(lb_file_type::new(self.0.file_type().await?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata cannot be retrieved.
|
||||
pub async extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
Ok(self.0.metadata().await?.into())
|
||||
Ok(lb_file_meta::new(self.0.metadata().await?))
|
||||
}
|
||||
|
||||
/// Returns the inode number for this entry.
|
||||
#[cfg(unix)]
|
||||
pub extern "Lua-C" fn ino(&self) -> u64 {
|
||||
self.0.ino()
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
#[tostring]
|
||||
pub extern "Lua" fn tostring(&self) -> String {
|
||||
self.path()
|
||||
@ -170,34 +278,52 @@ impl lb_dir_entry {
|
||||
}
|
||||
|
||||
/// Synchronous version of [`lb_dir_entry`].
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_dir_entry_sync(#[opaque] std::fs::DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_dir_entry_sync {
|
||||
fn new(entry: std::fs::DirEntry) -> Self {
|
||||
Self(entry)
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
pub extern "Lua-C" fn path(&self) -> String {
|
||||
self.0.path().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the file name of this entry.
|
||||
pub extern "Lua-C" fn name(&self) -> String {
|
||||
self.0.file_name().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the type of this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file type cannot be determined.
|
||||
pub extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(self.0.file_type()?.into())
|
||||
Ok(lb_file_type::new(self.0.file_type()?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata cannot be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
Ok(self.0.metadata()?.into())
|
||||
Ok(lb_file_meta::new(self.0.metadata()?))
|
||||
}
|
||||
|
||||
/// Returns the inode number for this entry.
|
||||
#[cfg(unix)]
|
||||
pub extern "Lua-C" fn ino(&self) -> u64 {
|
||||
use std::os::unix::fs::DirEntryExt;
|
||||
self.0.ino()
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
#[tostring]
|
||||
pub extern "Lua" fn tostring(&self) -> String {
|
||||
self.path()
|
||||
@ -205,24 +331,33 @@ impl lb_dir_entry_sync {
|
||||
}
|
||||
|
||||
/// Structure representing the type of a file with accessors for each file type.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_type(#[opaque] std::fs::FileType);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_type {
|
||||
fn new(ty: std::fs::FileType) -> Self {
|
||||
Self(ty)
|
||||
}
|
||||
|
||||
/// Returns `true` if this file type is a directory.
|
||||
pub extern "Lua-C" fn is_dir(&self) -> bool {
|
||||
self.0.is_dir()
|
||||
}
|
||||
|
||||
/// Returns `true` if this file type is a regular file.
|
||||
pub extern "Lua-C" fn is_file(&self) -> bool {
|
||||
self.0.is_file()
|
||||
}
|
||||
|
||||
/// Returns `true` if this file type is a symbolic link.
|
||||
pub extern "Lua-C" fn is_symlink(&self) -> bool {
|
||||
self.0.is_file()
|
||||
}
|
||||
|
||||
/// Returns the string `"file"` if this is a regular file, `"dir"` if this is a directory,
|
||||
/// `"symlink"` if this is a symbolic link, or `"other"` if it is some other type of file.
|
||||
#[tostring]
|
||||
pub extern "Lua-C" fn tostring(&self) -> String {
|
||||
if self.0.is_file() {
|
||||
@ -239,36 +374,51 @@ impl lb_file_type {
|
||||
}
|
||||
|
||||
/// Metadata information about a file.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_meta(#[opaque] std::fs::Metadata);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_meta {
|
||||
fn new(meta: std::fs::Metadata) -> Self {
|
||||
Self(meta)
|
||||
}
|
||||
|
||||
/// Returns `true` if this file is a directory.
|
||||
pub extern "Lua-C" fn is_dir(&self) -> bool {
|
||||
self.0.is_dir()
|
||||
}
|
||||
|
||||
/// Returns `true` if this file is a regular file.
|
||||
pub extern "Lua-C" fn is_file(&self) -> bool {
|
||||
self.0.is_file()
|
||||
}
|
||||
|
||||
/// Returns `true` if this file is a symbolic link.
|
||||
pub extern "Lua-C" fn is_symlink(&self) -> bool {
|
||||
self.0.is_file()
|
||||
}
|
||||
|
||||
/// Returns the type of this file.
|
||||
pub extern "Lua-C" fn r#type(&self) -> lb_file_type {
|
||||
self.0.file_type().into()
|
||||
lb_file_type::new(self.0.file_type())
|
||||
}
|
||||
|
||||
/// Returns the size of this file in bytes.
|
||||
pub extern "Lua-C" fn size(&self) -> u64 {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Returns the permissions of this file.
|
||||
pub extern "Lua-C" fn perms(&self) -> lb_file_perms {
|
||||
self.0.permissions().into()
|
||||
lb_file_perms::new(self.0.permissions())
|
||||
}
|
||||
|
||||
/// Returns the creation time of this file as seconds since the Unix epoch.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the creation time cannot be retrieved.
|
||||
pub extern "Lua-C" fn created(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
@ -278,6 +428,11 @@ impl lb_file_meta {
|
||||
.unwrap_or(0.))
|
||||
}
|
||||
|
||||
/// Returns the modification time of this file as seconds since the Unix epoch.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the modification time cannot be retrieved.
|
||||
pub extern "Lua-C" fn modified(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
@ -287,6 +442,11 @@ impl lb_file_meta {
|
||||
.unwrap_or(0.))
|
||||
}
|
||||
|
||||
/// Returns the last access time of this file as seconds since the Unix epoch.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the access time cannot be retrieved.
|
||||
pub extern "Lua-C" fn accessed(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
@ -296,6 +456,7 @@ impl lb_file_meta {
|
||||
.unwrap_or(0.))
|
||||
}
|
||||
|
||||
/// Returns a string representation of this file's metadata.
|
||||
#[tostring]
|
||||
pub extern "Lua-C" fn tostring(&self) -> String {
|
||||
let ty = self.0.file_type();
|
||||
@ -312,71 +473,107 @@ impl lb_file_meta {
|
||||
}
|
||||
|
||||
/// Representation of the various permissions on a file.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_perms(#[opaque] std::fs::Permissions);
|
||||
pub struct lb_file_perms(#[opaque] RefCell<std::fs::Permissions>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_perms {
|
||||
pub extern "Lua-C" fn readonly(&self) -> bool {
|
||||
self.0.readonly()
|
||||
fn new(perms: std::fs::Permissions) -> Self {
|
||||
Self(RefCell::new(perms))
|
||||
}
|
||||
|
||||
pub extern "Lua-C" fn set_readonly(&mut self, readonly: bool) {
|
||||
self.0.set_readonly(readonly);
|
||||
/// Returns `true` if the readonly flag is set.
|
||||
pub extern "Lua-C" fn readonly(&self) -> bool {
|
||||
self.0.borrow().readonly()
|
||||
}
|
||||
|
||||
/// Sets the readonly flag.
|
||||
pub extern "Lua-C" fn set_readonly(&self, readonly: bool) {
|
||||
self.0.borrow_mut().set_readonly(readonly);
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator for recursively descending into a directory.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_walk_dir(#[opaque] walkdir::IntoIter);
|
||||
pub struct lb_walk_dir(#[opaque] RefCell<walkdir::IntoIter>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_walk_dir {
|
||||
fn new(iter: walkdir::IntoIter) -> Self {
|
||||
Self(RefCell::new(iter))
|
||||
}
|
||||
|
||||
/// Returns the next entry in the walk, or `nil` if there are no more entries.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
#[call]
|
||||
pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_walk_dir_entry>> {
|
||||
Ok(self.0.next().transpose()?.map(Into::into))
|
||||
pub extern "Lua-C" fn next(&self) -> Result<Option<lb_walk_dir_entry>> {
|
||||
Ok(self
|
||||
.0
|
||||
.try_borrow_mut()?
|
||||
.next()
|
||||
.transpose()?
|
||||
.map(lb_walk_dir_entry::new))
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry inside of a directory on the filesystem obtained from [`lb_walk_dir`].
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_walk_dir_entry(#[opaque] walkdir::DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_walk_dir_entry {
|
||||
fn new(entry: walkdir::DirEntry) -> Self {
|
||||
Self(entry)
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
pub extern "Lua-C" fn path(&self) -> String {
|
||||
self.0.path().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the file name of this entry.
|
||||
pub extern "Lua-C" fn name(&self) -> String {
|
||||
self.0.file_name().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the type of this entry.
|
||||
pub extern "Lua-C" fn r#type(&self) -> lb_file_type {
|
||||
self.0.file_type().into()
|
||||
lb_file_type::new(self.0.file_type())
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata cannot be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
Ok(self.0.metadata()?.into())
|
||||
Ok(lb_file_meta::new(self.0.metadata()?))
|
||||
}
|
||||
|
||||
/// Returns `true` if this entry was created from a symbolic link.
|
||||
pub extern "Lua-C" fn is_symlink(&self) -> bool {
|
||||
self.0.path_is_symlink()
|
||||
}
|
||||
|
||||
/// Returns the depth of this entry in the walk.
|
||||
pub extern "Lua-C" fn depth(&self) -> u32 {
|
||||
self.0.depth() as u32
|
||||
}
|
||||
|
||||
/// Returns the inode number for this entry.
|
||||
#[cfg(unix)]
|
||||
pub extern "Lua-C" fn ino(&self) -> u64 {
|
||||
use walkdir::DirEntryExt;
|
||||
self.0.ino()
|
||||
}
|
||||
|
||||
/// Returns the full path of this entry.
|
||||
#[tostring]
|
||||
pub extern "Lua" fn tostring(&self) -> String {
|
||||
self.path()
|
||||
@ -388,7 +585,7 @@ impl lb_walk_dir_entry {
|
||||
#[cdef]
|
||||
pub struct lb_glob_dir {
|
||||
#[opaque]
|
||||
iter: walkdir::IntoIter,
|
||||
iter: RefCell<walkdir::IntoIter>,
|
||||
#[opaque]
|
||||
matcher: globset::GlobSet,
|
||||
#[opaque]
|
||||
@ -397,13 +594,26 @@ pub struct lb_glob_dir {
|
||||
|
||||
#[metatype]
|
||||
impl lb_glob_dir {
|
||||
fn new(iter: walkdir::IntoIter, matcher: globset::GlobSet, prefix: PathBuf) -> Self {
|
||||
Self {
|
||||
iter: RefCell::new(iter),
|
||||
matcher,
|
||||
prefix,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next entry matching the glob pattern, or `nil` if there are no more entries.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the directory cannot be read.
|
||||
#[call]
|
||||
pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_walk_dir_entry>> {
|
||||
while let Some(res) = self.iter.next() {
|
||||
pub extern "Lua-C" fn next(&self) -> Result<Option<lb_walk_dir_entry>> {
|
||||
while let Some(res) = self.iter.try_borrow_mut()?.next() {
|
||||
let entry = res?;
|
||||
let path = entry.path().strip_prefix(&self.prefix).unwrap();
|
||||
if self.matcher.is_match(path) {
|
||||
return Ok(Some(entry.into()));
|
||||
return Ok(Some(lb_walk_dir_entry::new(entry)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,16 +622,22 @@ impl lb_glob_dir {
|
||||
}
|
||||
|
||||
/// Directory in the filesystem that is automatically deleted when it is garbage-collected.
|
||||
#[derive(Debug, From)]
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_temp_dir(#[opaque] tempfile::TempDir);
|
||||
|
||||
#[metatype]
|
||||
impl lb_temp_dir {
|
||||
fn new(dir: tempfile::TempDir) -> Self {
|
||||
Self(dir)
|
||||
}
|
||||
|
||||
/// Returns the full path of this temporary directory.
|
||||
pub extern "Lua-C" fn path(&self) -> String {
|
||||
self.0.path().to_string_lossy().into()
|
||||
}
|
||||
|
||||
/// Returns the full path of this temporary directory.
|
||||
#[tostring]
|
||||
pub extern "Lua" fn tostring(&self) -> String {
|
||||
self.path()
|
||||
|
@ -9,7 +9,7 @@
|
||||
use derive_more::{From, FromStr};
|
||||
use luaffi::{cdef, marker::OneOf, metatype};
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut},
|
||||
net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
time::Duration,
|
||||
};
|
||||
@ -25,13 +25,19 @@ use tokio::{
|
||||
/// using [`pcall(f, ...)`](https://www.lua.org/manual/5.1/manual.html#pdf-pcall).
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Attempt to access an object while it is being modified.
|
||||
#[error("cannot access object while it is being modified")]
|
||||
Borrow(#[from] BorrowError),
|
||||
/// Attempt to modify an object while it is in use
|
||||
#[error("cannot modify object while it is in use")]
|
||||
BorrowMut(#[from] BorrowMutError),
|
||||
/// I/O error.
|
||||
#[error("{0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
/// IP or socket address syntax error.
|
||||
#[error("{0}")]
|
||||
InvalidAddr(#[from] AddrParseError),
|
||||
/// Socket was already converted and cannot be used anymore.
|
||||
/// Socket was already converted and can no longer be used.
|
||||
#[error("socket was already converted")]
|
||||
SocketConsumed,
|
||||
}
|
||||
@ -85,7 +91,7 @@ impl lb_netlib {
|
||||
///
|
||||
/// If `addr` is an [`lb_ipaddr`], a copy of that value is returned. If `addr` is an
|
||||
/// [`lb_socketaddr`], the IP part of the socket address is returned. Otherwise, parses `addr`
|
||||
/// as an IP address string. Both IPv4 or IPv6 addresses are accepted.
|
||||
/// as an IP address string. Both IPv4 and IPv6 addresses are accepted.
|
||||
///
|
||||
/// An address string may be something like `127.0.0.1`.
|
||||
///
|
||||
@ -303,7 +309,7 @@ impl lb_ipaddr {
|
||||
self.0.is_ipv6()
|
||||
}
|
||||
|
||||
/// Returns the string `"v4"` if this is an IPv4 address or `"v6"` if this is an IPv6 address.
|
||||
/// 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" }
|
||||
}
|
||||
@ -503,10 +509,12 @@ impl lb_socketaddr {
|
||||
self.0.port()
|
||||
}
|
||||
|
||||
/// Returns a new socket address with the given IP address and the same port.
|
||||
pub extern "Lua-C" fn with_ip(&self, ip: &lb_ipaddr) -> Self {
|
||||
SocketAddr::new(ip.0, self.port()).into()
|
||||
}
|
||||
|
||||
/// Returns a new socket address with the given port and the same IP address.
|
||||
pub extern "Lua-C" fn with_port(&self, port: u16) -> Self {
|
||||
SocketAddr::new(self.ip().0, port).into()
|
||||
}
|
||||
@ -547,7 +555,7 @@ impl lb_tcpsocket {
|
||||
Self(RefCell::new(Some(socket)))
|
||||
}
|
||||
|
||||
fn socket(&self) -> Result<Ref<TcpSocket>> {
|
||||
fn socket<'s>(&'s self) -> Result<Ref<'s, TcpSocket>> {
|
||||
let socket = self.0.borrow();
|
||||
match *socket {
|
||||
Some(_) => Ok(Ref::map(socket, |s| s.as_ref().unwrap())),
|
||||
@ -640,7 +648,7 @@ impl lb_tcpsocket {
|
||||
|
||||
/// Sets the value of the `TCP_NODELAY` option on this socket.
|
||||
///
|
||||
/// This enables or disables Nagle's algorithm which delays sending small packets.
|
||||
/// This enables or disables Nagle's algorithm, which delays sending small packets.
|
||||
pub extern "Lua-C" fn set_nodelay(&self, enabled: bool) -> Result<()> {
|
||||
Ok(self.socket()?.set_nodelay(enabled)?)
|
||||
}
|
||||
@ -682,71 +690,45 @@ impl lb_tcpsocket {
|
||||
/// TCP connection between a local and a remote socket.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_tcpstream(#[opaque] RefCell<TcpStream>);
|
||||
pub struct lb_tcpstream {
|
||||
#[opaque]
|
||||
read: RefCell<tokio::net::tcp::OwnedReadHalf>,
|
||||
#[opaque]
|
||||
write: RefCell<tokio::net::tcp::OwnedWriteHalf>,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lb_tcpstream {
|
||||
fn new(stream: TcpStream) -> Self {
|
||||
Self(RefCell::new(stream))
|
||||
let (read, write) = stream.into_split();
|
||||
Self {
|
||||
read: RefCell::new(read),
|
||||
write: RefCell::new(write),
|
||||
}
|
||||
}
|
||||
|
||||
fn stream(&self) -> Ref<TcpStream> {
|
||||
self.0.borrow()
|
||||
fn read_half<'s>(&'s self) -> Result<RefMut<'s, tokio::net::tcp::OwnedReadHalf>> {
|
||||
Ok(self.read.try_borrow_mut()?)
|
||||
}
|
||||
|
||||
fn stream_mut(&self) -> RefMut<TcpStream> {
|
||||
self.0.borrow_mut()
|
||||
fn write_half<'s>(&'s self) -> Result<RefMut<'s, tokio::net::tcp::OwnedWriteHalf>> {
|
||||
Ok(self.write.try_borrow_mut()?)
|
||||
}
|
||||
|
||||
/// Gets the remote address of this stream.
|
||||
pub extern "Lua-C" fn peer_addr(&self) -> Result<lb_socketaddr> {
|
||||
Ok(self.stream().peer_addr()?.into())
|
||||
Ok(self.read_half()?.peer_addr()?.into())
|
||||
}
|
||||
|
||||
/// Gets the local address of this stream.
|
||||
pub extern "Lua-C" fn local_addr(&self) -> Result<lb_socketaddr> {
|
||||
Ok(self.stream().local_addr()?.into())
|
||||
Ok(self.read_half()?.local_addr()?.into())
|
||||
}
|
||||
|
||||
/// Gets the value of the `SO_LINGER` option on this stream, in seconds.
|
||||
pub extern "Lua-C" fn linger(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.stream()
|
||||
.linger()?
|
||||
.map(|n| n.as_secs_f64())
|
||||
.unwrap_or(0.))
|
||||
}
|
||||
|
||||
/// Sets the value of the `SO_LINGER` option on this stream.
|
||||
pub extern "Lua-C" fn set_linger(&self, secs: f64) -> Result<()> {
|
||||
Ok(self
|
||||
.stream()
|
||||
.set_linger((secs != 0.).then_some(Duration::from_secs_f64(secs)))?)
|
||||
}
|
||||
|
||||
/// Gets the value of the `TCP_NODELAY` option on this stream.
|
||||
pub extern "Lua-C" fn nodelay(&self) -> Result<bool> {
|
||||
Ok(self.stream().nodelay()?)
|
||||
}
|
||||
|
||||
/// Sets the value of the `TCP_NODELAY` option on this stream.
|
||||
/// Waits for this stream to be ready in the given half.
|
||||
///
|
||||
/// This enables or disables Nagle's algorithm which delays sending small packets.
|
||||
pub extern "Lua-C" fn set_nodelay(&self, enabled: bool) -> Result<()> {
|
||||
Ok(self.stream().set_nodelay(enabled)?)
|
||||
}
|
||||
|
||||
/// Gets the value of the `IP_TTL` option on this stream.
|
||||
pub extern "Lua-C" fn ttl(&self) -> Result<u32> {
|
||||
Ok(self.stream().ttl()?)
|
||||
}
|
||||
|
||||
/// Sets the value of the `IP_TTL` option on this stream.
|
||||
pub extern "Lua-C" fn set_ttl(&self, ttl: u32) -> Result<()> {
|
||||
Ok(self.stream().set_ttl(ttl)?)
|
||||
}
|
||||
|
||||
/// Waits for the stream to be ready for the given half (`"read"`, `"write"`, or `nil` for both halves).
|
||||
/// `half` can be `"read"` for the readable half, `"write"` for the writable half, or `nil` for
|
||||
/// both.
|
||||
pub async extern "Lua-C" fn ready(&self, half: Option<&str>) -> Result<()> {
|
||||
let ty = match half {
|
||||
None => Interest::READABLE | Interest::WRITABLE,
|
||||
@ -758,29 +740,29 @@ impl lb_tcpstream {
|
||||
))?,
|
||||
};
|
||||
|
||||
self.stream().ready(ty).await?;
|
||||
self.read_half()?.ready(ty).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reads exactly `len` bytes from the stream. Returns None on EOF.
|
||||
/// Reads exactly `len` bytes from this stream.
|
||||
///
|
||||
/// If the connection was closed, this returns `nil`.
|
||||
pub async extern "Lua-C" fn read(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
let mut buf = vec![0; len as usize];
|
||||
match self.stream_mut().read_exact(&mut buf).await {
|
||||
match self.read_half()?.read_exact(&mut buf).await {
|
||||
Ok(_) => Ok(Some(buf)),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => Ok(None),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the given bytes to the stream.
|
||||
pub async extern "Lua-C" fn write(&self, buf: &[u8]) -> Result<()> {
|
||||
Ok(self.stream_mut().write_all(buf).await?)
|
||||
}
|
||||
|
||||
/// Reads up to `len` bytes from the stream. Returns None on EOF.
|
||||
/// Reads up to `len` bytes from this stream.
|
||||
///
|
||||
/// The returned bytes may be less than `len` in length if the stream had less data available in
|
||||
/// queue. If the connection was closed, this returns `nil`.
|
||||
pub async extern "Lua-C" fn read_partial(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
let mut buf = vec![0; len as usize];
|
||||
let n = self.stream_mut().read(&mut buf).await?;
|
||||
let n = self.read_half()?.read(&mut buf).await?;
|
||||
if n == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
@ -789,15 +771,13 @@ impl lb_tcpstream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the given bytes to the stream and returns the number of bytes successfully written.
|
||||
pub async extern "Lua-C" fn write_partial(&self, buf: &[u8]) -> Result<u32> {
|
||||
Ok(self.stream_mut().write(buf).await? as u32)
|
||||
}
|
||||
|
||||
/// Attempts to read up to `len` bytes from the stream without waiting. Returns None on EOF.
|
||||
/// Attempts to read up to `len` bytes from this stream without waiting.
|
||||
///
|
||||
/// The returned bytes may be less than `len` in length if the stream had less data available in
|
||||
/// queue. If there was no data available or the connection was closed, this returns `nil`.
|
||||
pub extern "Lua-C" fn try_read(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
match self.stream_mut().try_read(&mut buf) {
|
||||
let mut buf = vec![0; len as usize];
|
||||
match self.read_half()?.try_read(&mut buf) {
|
||||
Ok(0) => Ok(None),
|
||||
Ok(n) => {
|
||||
buf.truncate(n);
|
||||
@ -808,10 +788,23 @@ impl lb_tcpstream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Peeks up to `len` bytes at incoming data without consuming it. Returns None on EOF.
|
||||
/// Writes the given bytes to this stream.
|
||||
pub async extern "Lua-C" fn write(&self, buf: &[u8]) -> Result<()> {
|
||||
Ok(self.write_half()?.write_all(buf).await?)
|
||||
}
|
||||
|
||||
/// Writes the given bytes to this stream and returns the number of bytes successfully written.
|
||||
pub async extern "Lua-C" fn write_partial(&self, buf: &[u8]) -> Result<u32> {
|
||||
Ok(self.write_half()?.write(buf).await? as u32)
|
||||
}
|
||||
|
||||
/// Peeks up to `len` bytes at incoming data without consuming it.
|
||||
///
|
||||
/// Successive calls will return the same data until it is consumed by the [`read`](Self::read)
|
||||
/// family of functions.
|
||||
pub async extern "Lua-C" fn peek(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
let n = self.stream_mut().peek(&mut buf).await?;
|
||||
let mut buf = vec![0; len as usize];
|
||||
let n = self.read_half()?.peek(&mut buf).await?;
|
||||
if n == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
@ -822,11 +815,11 @@ impl lb_tcpstream {
|
||||
|
||||
/// Shuts down this connection.
|
||||
pub async extern "Lua-C" fn shutdown(&self) -> Result<()> {
|
||||
Ok(self.stream_mut().shutdown().await?)
|
||||
Ok(self.write_half()?.shutdown().await?)
|
||||
}
|
||||
|
||||
#[call]
|
||||
pub async extern "Lua" fn __call(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
pub async extern "Lua" fn call(&self, len: u32) -> Result<Option<Vec<u8>>> {
|
||||
self.read_partial(len)
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use luaffi::{
|
||||
metatype,
|
||||
};
|
||||
use luajit::{LUA_MULTRET, Type};
|
||||
use std::{ffi::c_int, time::Duration};
|
||||
use std::{cell::RefCell, ffi::c_int, time::Duration};
|
||||
use tokio::{task::JoinHandle, time::sleep};
|
||||
|
||||
/// Items exported by the `lb:task` library.
|
||||
@ -45,6 +45,10 @@ impl lb_tasklib {
|
||||
// this table is used from rust-side to call the function with its args, and it's also
|
||||
// reused to store its return values that the task handle can return when awaited. the ref
|
||||
// is owned by the task handle and unref'ed when it's gc'ed.
|
||||
assert(
|
||||
r#type(f) == "function",
|
||||
concat!("function expected in argument 'f', got ", r#type(f)),
|
||||
);
|
||||
Self::__spawn(__ref(__tpack(f, variadic!())))
|
||||
}
|
||||
|
||||
@ -69,10 +73,7 @@ impl lb_tasklib {
|
||||
let _ = arg.into_raw(); // the original ref is owned by the task handle and unref'ed there
|
||||
});
|
||||
|
||||
lb_task {
|
||||
handle: Some(handle),
|
||||
__ref: key,
|
||||
}
|
||||
lb_task::new(handle, key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,20 +81,27 @@ impl lb_tasklib {
|
||||
#[cdef]
|
||||
pub struct lb_task {
|
||||
#[opaque]
|
||||
handle: Option<JoinHandle<()>>,
|
||||
handle: RefCell<Option<JoinHandle<()>>>,
|
||||
__ref: c_int,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lb_task {
|
||||
fn new(handle: JoinHandle<()>, ref_key: c_int) -> Self {
|
||||
lb_task {
|
||||
handle: RefCell::new(Some(handle)),
|
||||
__ref: ref_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub async extern "Lua" fn r#await(&self) -> many {
|
||||
self.__await();
|
||||
let ret = __registry[self.__ref];
|
||||
__tunpack(ret, 1, ret.n)
|
||||
}
|
||||
|
||||
async extern "Lua-C" fn __await(&mut self) {
|
||||
if let Some(handle) = self.handle.take() {
|
||||
async extern "Lua-C" fn __await(&self) {
|
||||
if let Some(handle) = self.handle.borrow_mut().take() {
|
||||
handle
|
||||
.await
|
||||
.unwrap_or_else(|err| panic!("task handler panicked: {err}"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user