//! 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 = std::result::Result; /// 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> { 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> { 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 { 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 { 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 { 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 { 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 { 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 { 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 { Ok(lb_temp_dir::new(tempfile::tempdir_in(path)?)) } }