Restructure fslib
This commit is contained in:
parent
fc4d27abf1
commit
e03ef8a495
@ -1,645 +0,0 @@
|
||||
//! Filesystem library.
|
||||
//!
|
||||
//! The `lb:fs` library provides synchronous and asynchronous utilities for interacting with the
|
||||
//! filesystem.
|
||||
//!
|
||||
//! ## Asynchronous by default
|
||||
//!
|
||||
//! Filesystem operations are blocking by nature; to provide asynchronicity, luby performs blocking
|
||||
//! operations in a background thread pool by default. Synchronous complements to all asynchronous
|
||||
//! functions are always provided.
|
||||
//!
|
||||
//! ## Exports
|
||||
//!
|
||||
//! See [`lb_fslib`] for items exported by this library.
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::{
|
||||
cell::{BorrowError, BorrowMutError, RefCell},
|
||||
path::PathBuf,
|
||||
time::SystemTime,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can be thrown by this library.
|
||||
///
|
||||
/// Functions which return this error will **throw**. 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 {
|
||||
/// 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),
|
||||
/// Walk directory error.
|
||||
#[error("{0}")]
|
||||
Walk(#[from] walkdir::Error),
|
||||
/// Glob pattern error.
|
||||
#[error("{0}")]
|
||||
Glob(#[from] globset::Error),
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Items exported by the `lb:fs` library.
|
||||
///
|
||||
/// This library can be acquired by calling
|
||||
/// [`require("lb:fs")`](https://www.lua.org/manual/5.1/manual.html#pdf-require).
|
||||
///
|
||||
/// ```lua
|
||||
/// local fs = require("lb:fs");
|
||||
/// ```
|
||||
#[cdef(module = "lb:fs")]
|
||||
pub struct lb_fslib;
|
||||
|
||||
#[metatype]
|
||||
impl lb_fslib {
|
||||
#[new]
|
||||
extern "Lua-C" fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Reads the entire contents of a file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file does not exist or could not 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 could not 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 could not 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 could not 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 could not be read.
|
||||
pub async extern "Lua-C" fn read_dir(path: &str) -> Result<lb_read_dir> {
|
||||
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 could not be read.
|
||||
pub extern "Lua-C" fn read_dir_sync(path: &str) -> Result<lb_read_dir_sync> {
|
||||
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 {
|
||||
lb_walk_dir::new(walkdir::WalkDir::new(path).into_iter())
|
||||
}
|
||||
|
||||
/// 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();
|
||||
let matcher = globset::GlobSet::builder()
|
||||
.add(globset::Glob::new(pattern)?)
|
||||
.build()?;
|
||||
|
||||
Ok(lb_glob_dir::new(iter, matcher, prefix))
|
||||
}
|
||||
|
||||
/// Creates a new temporary directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the temporary directory could not be created.
|
||||
pub extern "Lua-C" fn temp_dir() -> Result<lb_temp_dir> {
|
||||
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 could not be created.
|
||||
pub extern "Lua-C" fn temp_dir_in(path: &str) -> Result<lb_temp_dir> {
|
||||
Ok(lb_temp_dir::new(tempfile::tempdir_in(path)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over the entries in a directory.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
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 could not be read.
|
||||
#[call]
|
||||
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)]
|
||||
#[cdef]
|
||||
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 could not be read.
|
||||
#[call]
|
||||
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)]
|
||||
#[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 could not be determined.
|
||||
pub async extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(lb_file_type::new(self.0.file_type().await?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub async extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous version of [`lb_dir_entry`].
|
||||
#[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 could not be determined.
|
||||
pub extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(lb_file_type::new(self.0.file_type()?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure representing the type of a file with accessors for each file type.
|
||||
#[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() {
|
||||
"file"
|
||||
} else if self.0.is_dir() {
|
||||
"dir"
|
||||
} else if self.0.is_symlink() {
|
||||
"symlink"
|
||||
} else {
|
||||
"other"
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata information about a file.
|
||||
#[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 {
|
||||
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 {
|
||||
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 could not be retrieved.
|
||||
pub extern "Lua-C" fn created(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.created()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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 could not be retrieved.
|
||||
pub extern "Lua-C" fn modified(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.modified()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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 could not be retrieved.
|
||||
pub extern "Lua-C" fn accessed(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.accessed()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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();
|
||||
if ty.is_file() {
|
||||
format!("file {}", self.0.len())
|
||||
} else if ty.is_dir() {
|
||||
"dir".into()
|
||||
} else if ty.is_symlink() {
|
||||
"symlink".into()
|
||||
} else {
|
||||
"other".into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of the various permissions on a file.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_perms(#[opaque] RefCell<std::fs::Permissions>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_perms {
|
||||
fn new(perms: std::fs::Permissions) -> Self {
|
||||
Self(RefCell::new(perms))
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
#[cdef]
|
||||
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 could not be read.
|
||||
#[call]
|
||||
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)]
|
||||
#[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 {
|
||||
lb_file_type::new(self.0.file_type())
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator that yields paths from the filesystem that match a particular pattern.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_glob_dir {
|
||||
#[opaque]
|
||||
iter: RefCell<walkdir::IntoIter>,
|
||||
#[opaque]
|
||||
matcher: globset::GlobSet,
|
||||
#[opaque]
|
||||
prefix: PathBuf,
|
||||
}
|
||||
|
||||
#[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 could not be read.
|
||||
#[call]
|
||||
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(lb_walk_dir_entry::new(entry)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Directory in the filesystem that is automatically deleted when it is garbage-collected.
|
||||
#[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()
|
||||
}
|
||||
}
|
83
crates/lb/src/fs/async.rs
Normal file
83
crates/lb/src/fs/async.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use super::*;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::cell::RefCell;
|
||||
use tokio::fs::{DirEntry, ReadDir};
|
||||
|
||||
/// Iterator over the entries in a directory.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_read_dir(#[opaque] RefCell<ReadDir>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_read_dir {
|
||||
pub(super) fn new(iter: 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 could not be read.
|
||||
#[call]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry inside of a directory on the filesystem.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_dir_entry(#[opaque] DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_dir_entry {
|
||||
pub(super) fn new(entry: 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 could not be determined.
|
||||
pub async extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(lb_file_type::new(self.0.file_type().await?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub async extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
46
crates/lb/src/fs/glob.rs
Normal file
46
crates/lb/src/fs/glob.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use super::*;
|
||||
use globset::GlobSet;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::cell::RefCell;
|
||||
use walkdir::IntoIter;
|
||||
|
||||
/// Iterator that yields paths from the filesystem that match a particular pattern.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_glob_dir {
|
||||
#[opaque]
|
||||
iter: RefCell<IntoIter>,
|
||||
#[opaque]
|
||||
matcher: GlobSet,
|
||||
#[opaque]
|
||||
prefix: PathBuf,
|
||||
}
|
||||
|
||||
#[metatype]
|
||||
impl lb_glob_dir {
|
||||
pub(super) fn new(iter: IntoIter, matcher: 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 could not be read.
|
||||
#[call]
|
||||
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(lb_walk_dir_entry::new(entry)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
190
crates/lb/src/fs/mod.rs
Normal file
190
crates/lb/src/fs/mod.rs
Normal file
@ -0,0 +1,190 @@
|
||||
//! Filesystem library.
|
||||
//!
|
||||
//! The `lb:fs` library provides synchronous and asynchronous utilities for interacting with the
|
||||
//! filesystem.
|
||||
//!
|
||||
//! ## Asynchronous by default
|
||||
//!
|
||||
//! Filesystem operations are blocking by nature; to provide asynchronicity, luby performs blocking
|
||||
//! operations in a background thread pool by default. Synchronous complements to all asynchronous
|
||||
//! functions are always provided.
|
||||
//!
|
||||
//! ## Exports
|
||||
//!
|
||||
//! See [`lb_fslib`] for items exported by this library.
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::{
|
||||
cell::{BorrowError, BorrowMutError},
|
||||
path::PathBuf,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
mod r#async;
|
||||
mod glob;
|
||||
mod sync;
|
||||
mod temp;
|
||||
mod walk;
|
||||
|
||||
pub use r#async::*;
|
||||
pub use glob::*;
|
||||
pub use sync::*;
|
||||
pub use temp::*;
|
||||
pub use walk::*;
|
||||
|
||||
/// Errors that can be thrown by this library.
|
||||
///
|
||||
/// Functions which return this error will **throw**. 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 {
|
||||
/// 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),
|
||||
/// Walk directory error.
|
||||
#[error("{0}")]
|
||||
Walk(#[from] walkdir::Error),
|
||||
/// Glob pattern error.
|
||||
#[error("{0}")]
|
||||
Glob(#[from] globset::Error),
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Items exported by the `lb:fs` library.
|
||||
///
|
||||
/// This library can be acquired by calling
|
||||
/// [`require("lb:fs")`](https://www.lua.org/manual/5.1/manual.html#pdf-require).
|
||||
///
|
||||
/// ```lua
|
||||
/// local fs = require("lb:fs")
|
||||
/// ```
|
||||
#[cdef(module = "lb:fs")]
|
||||
pub struct lb_fslib;
|
||||
|
||||
#[metatype]
|
||||
impl lb_fslib {
|
||||
#[new]
|
||||
extern "Lua-C" fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Reads the entire contents of a file.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the file does not exist or could not 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 could not 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 could not 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 could not 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 could not be read.
|
||||
pub async extern "Lua-C" fn read_dir(path: &str) -> Result<lb_read_dir> {
|
||||
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 could not be read.
|
||||
pub extern "Lua-C" fn read_dir_sync(path: &str) -> Result<lb_read_dir_sync> {
|
||||
Ok(lb_read_dir_sync::new(std::fs::read_dir(path)?))
|
||||
}
|
||||
|
||||
/// Recursively walks the current directory, yielding all entries within it.
|
||||
pub extern "Lua" fn walk(pattern: &str) -> Result<lb_walk_dir> {
|
||||
Self::walk_dir(".")
|
||||
}
|
||||
|
||||
/// Recursively walks a directory, yielding all entries within it.
|
||||
pub extern "Lua-C" fn walk_dir(path: &str) -> lb_walk_dir {
|
||||
lb_walk_dir::new(walkdir::WalkDir::new(path).into_iter())
|
||||
}
|
||||
|
||||
/// Recursively walks the current directory, yielding all entries within it that match the given
|
||||
/// glob pattern.
|
||||
///
|
||||
/// # 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)
|
||||
}
|
||||
|
||||
/// Recursively walks a directory, yielding all entries within it that match the given glob
|
||||
/// pattern.
|
||||
///
|
||||
/// # 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();
|
||||
let matcher = globset::GlobSet::builder()
|
||||
.add(globset::Glob::new(pattern)?)
|
||||
.build()?;
|
||||
|
||||
Ok(lb_glob_dir::new(iter, matcher, prefix))
|
||||
}
|
||||
|
||||
/// Creates a new temporary directory.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the temporary directory could not be created.
|
||||
pub extern "Lua-C" fn temp_dir() -> Result<lb_temp_dir> {
|
||||
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 could not be created.
|
||||
pub extern "Lua-C" fn temp_dir_in(path: &str) -> Result<lb_temp_dir> {
|
||||
Ok(lb_temp_dir::new(tempfile::tempdir_in(path)?))
|
||||
}
|
||||
}
|
251
crates/lb/src/fs/sync.rs
Normal file
251
crates/lb/src/fs/sync.rs
Normal file
@ -0,0 +1,251 @@
|
||||
use super::*;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fs::{DirEntry, FileType, Metadata, Permissions, ReadDir},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
/// Structure representing the type of a file with accessors for each file type.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_type(#[opaque] FileType);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_type {
|
||||
pub(super) fn new(ty: 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() {
|
||||
"file"
|
||||
} else if self.0.is_dir() {
|
||||
"dir"
|
||||
} else if self.0.is_symlink() {
|
||||
"symlink"
|
||||
} else {
|
||||
"other"
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata information about a file.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_meta(#[opaque] Metadata);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_meta {
|
||||
pub(super) fn new(meta: 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 {
|
||||
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 {
|
||||
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 could not be retrieved.
|
||||
pub extern "Lua-C" fn created(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.created()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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 could not be retrieved.
|
||||
pub extern "Lua-C" fn modified(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.modified()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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 could not be retrieved.
|
||||
pub extern "Lua-C" fn accessed(&self) -> Result<f64> {
|
||||
Ok(self
|
||||
.0
|
||||
.accessed()?
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map(|dur| dur.as_secs_f64())
|
||||
.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();
|
||||
if ty.is_file() {
|
||||
format!("file {}", self.0.len())
|
||||
} else if ty.is_dir() {
|
||||
"dir".into()
|
||||
} else if ty.is_symlink() {
|
||||
"symlink".into()
|
||||
} else {
|
||||
"other".into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of the various permissions on a file.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_file_perms(#[opaque] RefCell<Permissions>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_file_perms {
|
||||
pub(super) fn new(perms: Permissions) -> Self {
|
||||
Self(RefCell::new(perms))
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous version of [`lb_read_dir`].
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_read_dir_sync(#[opaque] RefCell<ReadDir>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_read_dir_sync {
|
||||
pub(super) fn new(iter: 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 could not be read.
|
||||
#[call]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronous version of [`lb_dir_entry`].
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_dir_entry_sync(#[opaque] DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_dir_entry_sync {
|
||||
pub(super) fn new(entry: 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 could not be determined.
|
||||
pub extern "Lua-C" fn r#type(&self) -> Result<lb_file_type> {
|
||||
Ok(lb_file_type::new(self.0.file_type()?))
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
25
crates/lb/src/fs/temp.rs
Normal file
25
crates/lb/src/fs/temp.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use luaffi::{cdef, metatype};
|
||||
use tempfile::TempDir;
|
||||
|
||||
/// Directory in the filesystem that is automatically deleted when it is garbage-collected.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_temp_dir(#[opaque] TempDir);
|
||||
|
||||
#[metatype]
|
||||
impl lb_temp_dir {
|
||||
pub(super) fn new(dir: 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()
|
||||
}
|
||||
}
|
90
crates/lb/src/fs/walk.rs
Normal file
90
crates/lb/src/fs/walk.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use super::*;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::cell::RefCell;
|
||||
use walkdir::{DirEntry, IntoIter};
|
||||
|
||||
/// Iterator for recursively descending into a directory.
|
||||
#[derive(Debug)]
|
||||
#[cdef]
|
||||
pub struct lb_walk_dir(#[opaque] RefCell<IntoIter>);
|
||||
|
||||
#[metatype]
|
||||
impl lb_walk_dir {
|
||||
pub(super) fn new(iter: 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 could not be read.
|
||||
#[call]
|
||||
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)]
|
||||
#[cdef]
|
||||
pub struct lb_walk_dir_entry(#[opaque] DirEntry);
|
||||
|
||||
#[metatype]
|
||||
impl lb_walk_dir_entry {
|
||||
pub(super) fn new(entry: 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 {
|
||||
lb_file_type::new(self.0.file_type())
|
||||
}
|
||||
|
||||
/// Returns the metadata for this entry.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function may throw if the metadata could not be retrieved.
|
||||
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
|
||||
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()
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ use luaffi::{cdef, metatype};
|
||||
/// [`require("lb:sqlite")`](https://www.lua.org/manual/5.1/manual.html#pdf-require).
|
||||
///
|
||||
/// ```lua
|
||||
/// local sqlite = require("lb:sqlite");
|
||||
/// local sqlite = require("lb:sqlite")
|
||||
/// ```
|
||||
#[cdef(module = "lb:time")]
|
||||
pub struct lb_sqlitelib;
|
||||
|
Loading…
x
Reference in New Issue
Block a user