mirror of
https://github.com/denoland/deno.git
synced 2024-12-26 09:10:40 -05:00
chore(ext/fs): decouple fs trait from deno_core (#18732)
This commit removes the dependencies on `deno_core` for the Fs trait. This allows to move the trait into a different crate that does not depend on core in the limit. This adds a new `bounds` field to `deno_core::extension!` that expands to `where` clauses on the generated code. This allows to add bounds to the extension parameters, such as `Fs::File: Resource`.
This commit is contained in:
parent
bad4b7554b
commit
bcbdaac7e6
4 changed files with 104 additions and 72 deletions
|
@ -165,6 +165,7 @@ macro_rules! ops {
|
|||
///
|
||||
/// * deps: a comma-separated list of module dependencies, eg: `deps = [ my_other_extension ]`
|
||||
/// * parameters: a comma-separated list of parameters and base traits, eg: `parameters = [ P: MyTrait ]`
|
||||
/// * bounds: a comma-separated list of additional type bounds, eg: `bounds = [ P::MyAssociatedType: MyTrait ]`
|
||||
/// * ops: a comma-separated list of [`OpDecl`]s to provide, eg: `ops = [ op_foo, op_bar ]`
|
||||
/// * esm: a comma-separated list of ESM module filenames (see [`include_js_files`]), eg: `esm = [ dir "dir", "my_file.js" ]`
|
||||
/// * esm_setup_script: see [`ExtensionBuilder::esm_setup_script`]
|
||||
|
@ -179,6 +180,7 @@ macro_rules! extension {
|
|||
$name:ident
|
||||
$(, deps = [ $( $dep:ident ),* ] )?
|
||||
$(, parameters = [ $( $param:ident : $type:ident ),+ ] )?
|
||||
$(, bounds = [ $( $bound:path : $bound_type:ident ),+ ] )?
|
||||
$(, ops_fn = $ops_symbol:ident $( < $ops_param:ident > )? )?
|
||||
$(, ops = [ $( $(#[$m:meta])* $( $op:ident )::+ $( < $( $op_param:ident ),* > )? ),+ $(,)? ] )?
|
||||
$(, esm_entry_point = $esm_entry_point:literal )?
|
||||
|
@ -229,7 +231,9 @@ macro_rules! extension {
|
|||
// If ops were specified, add those ops to the extension.
|
||||
#[inline(always)]
|
||||
#[allow(unused_variables)]
|
||||
fn with_ops $( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder) {
|
||||
fn with_ops $( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder)
|
||||
$( where $( $bound : $bound_type ),+ )?
|
||||
{
|
||||
// If individual ops are specified, roll them up into a vector and apply them
|
||||
$(
|
||||
ext.ops(vec![
|
||||
|
@ -247,7 +251,9 @@ macro_rules! extension {
|
|||
// Includes the state and middleware functions, if defined.
|
||||
#[inline(always)]
|
||||
#[allow(unused_variables)]
|
||||
fn with_state_and_middleware$( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder, $( $( $options_id : $options_type ),* )? ) {
|
||||
fn with_state_and_middleware$( < $( $param : $type + 'static ),+ > )?(ext: &mut $crate::ExtensionBuilder, $( $( $options_id : $options_type ),* )? )
|
||||
$( where $( $bound : $bound_type ),+ )?
|
||||
{
|
||||
$crate::extension!(! __config__ ext $( parameters = [ $( $param : $type ),* ] )? $( config = { $( $options_id : $options_type ),* } )? $( state_fn = $state_fn )? );
|
||||
|
||||
$(
|
||||
|
@ -267,7 +273,9 @@ macro_rules! extension {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn init_js_only $( < $( $param : $type + 'static ),* > )? () -> $crate::Extension {
|
||||
pub fn init_js_only $( < $( $param : $type + 'static ),* > )? () -> $crate::Extension
|
||||
$( where $( $bound : $bound_type ),+ )?
|
||||
{
|
||||
let mut ext = Self::ext();
|
||||
// If esm or JS was specified, add JS files
|
||||
Self::with_js(&mut ext);
|
||||
|
@ -277,7 +285,9 @@ macro_rules! extension {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn init_ops_and_esm $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension {
|
||||
pub fn init_ops_and_esm $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
|
||||
$( where $( $bound : $bound_type ),+ )?
|
||||
{
|
||||
let mut ext = Self::ext();
|
||||
// If esm or JS was specified, add JS files
|
||||
Self::with_js(&mut ext);
|
||||
|
@ -288,7 +298,9 @@ macro_rules! extension {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn init_ops $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension {
|
||||
pub fn init_ops $( < $( $param : $type + 'static ),+ > )? ( $( $( $options_id : $options_type ),* )? ) -> $crate::Extension
|
||||
$( where $( $bound : $bound_type ),+ )?
|
||||
{
|
||||
let mut ext = Self::ext();
|
||||
Self::with_ops $( ::< $( $param ),+ > )?(&mut ext);
|
||||
Self::with_state_and_middleware $( ::< $( $param ),+ > )?(&mut ext, $( $( $options_id , )* )? );
|
||||
|
|
|
@ -5,32 +5,8 @@ use std::path::Path;
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use deno_core::error::not_supported;
|
||||
use deno_core::error::resource_unavailable;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::Resource;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use tokio::task::JoinError;
|
||||
|
||||
pub trait FsPermissions {
|
||||
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_blind(
|
||||
&mut self,
|
||||
p: &Path,
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_blind(
|
||||
&mut self,
|
||||
p: &Path,
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Clone, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -74,21 +50,6 @@ impl OpenOptions {
|
|||
mode,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check<P: FsPermissions>(
|
||||
&self,
|
||||
permissions: &mut P,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
if self.read {
|
||||
permissions.check_read(path, api_name)?;
|
||||
}
|
||||
if self.write || self.append {
|
||||
permissions.check_write(path, api_name)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FsStat {
|
||||
|
@ -141,28 +102,6 @@ impl From<io::Error> for FsError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<JoinError> for FsError {
|
||||
fn from(err: JoinError) -> Self {
|
||||
if err.is_cancelled() {
|
||||
todo!("async tasks must not be cancelled")
|
||||
}
|
||||
if err.is_panic() {
|
||||
std::panic::resume_unwind(err.into_panic()); // resume the panic on the main thread
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FsError> for AnyError {
|
||||
fn from(err: FsError) -> Self {
|
||||
match err {
|
||||
FsError::Io(err) => AnyError::from(err),
|
||||
FsError::FileBusy => resource_unavailable(),
|
||||
FsError::NotSupported => not_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type FsResult<T> = Result<T, FsError>;
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
|
@ -214,7 +153,7 @@ pub trait File {
|
|||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
pub trait FileSystem: Clone {
|
||||
type File: File + Resource;
|
||||
type File: File;
|
||||
|
||||
fn cwd(&self) -> FsResult<PathBuf>;
|
||||
fn tmp_dir(&self) -> FsResult<PathBuf>;
|
||||
|
|
|
@ -9,7 +9,6 @@ pub use crate::interface::FileSystem;
|
|||
pub use crate::interface::FsDirEntry;
|
||||
pub use crate::interface::FsError;
|
||||
pub use crate::interface::FsFileType;
|
||||
pub use crate::interface::FsPermissions;
|
||||
pub use crate::interface::FsResult;
|
||||
pub use crate::interface::FsStat;
|
||||
pub use crate::interface::OpenOptions;
|
||||
|
@ -17,11 +16,48 @@ use crate::ops::*;
|
|||
|
||||
pub use crate::std_fs::StdFs;
|
||||
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::OpState;
|
||||
use deno_core::Resource;
|
||||
use std::cell::RefCell;
|
||||
use std::convert::From;
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub trait FsPermissions {
|
||||
fn check_read(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_read_blind(
|
||||
&mut self,
|
||||
p: &Path,
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
fn check_write(&mut self, p: &Path, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_all(&mut self, api_name: &str) -> Result<(), AnyError>;
|
||||
fn check_write_blind(
|
||||
&mut self,
|
||||
p: &Path,
|
||||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError>;
|
||||
|
||||
fn check(
|
||||
&mut self,
|
||||
open_options: &OpenOptions,
|
||||
path: &Path,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
if open_options.read {
|
||||
self.check_read(path, api_name)?;
|
||||
}
|
||||
if open_options.write || open_options.append {
|
||||
self.check_write(path, api_name)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct UnstableChecker {
|
||||
pub unstable: bool,
|
||||
}
|
||||
|
@ -52,6 +88,7 @@ pub(crate) fn check_unstable2(state: &Rc<RefCell<OpState>>, api_name: &str) {
|
|||
deno_core::extension!(deno_fs,
|
||||
deps = [ deno_web ],
|
||||
parameters = [Fs: FileSystem, P: FsPermissions],
|
||||
bounds = [Fs::File: Resource],
|
||||
ops = [
|
||||
op_cwd<Fs, P>,
|
||||
op_umask<Fs>,
|
||||
|
|
|
@ -9,18 +9,22 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::not_supported;
|
||||
use deno_core::error::resource_unavailable;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::op;
|
||||
use deno_core::CancelFuture;
|
||||
use deno_core::CancelHandle;
|
||||
use deno_core::OpState;
|
||||
use deno_core::Resource;
|
||||
use deno_core::ResourceId;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use rand::rngs::ThreadRng;
|
||||
use rand::thread_rng;
|
||||
use rand::Rng;
|
||||
use serde::Serialize;
|
||||
use tokio::task::JoinError;
|
||||
|
||||
use crate::check_unstable;
|
||||
use crate::check_unstable2;
|
||||
|
@ -33,6 +37,28 @@ use crate::FileSystem;
|
|||
use crate::FsPermissions;
|
||||
use crate::OpenOptions;
|
||||
|
||||
impl From<JoinError> for FsError {
|
||||
fn from(err: JoinError) -> Self {
|
||||
if err.is_cancelled() {
|
||||
todo!("async tasks must not be cancelled")
|
||||
}
|
||||
if err.is_panic() {
|
||||
std::panic::resume_unwind(err.into_panic()); // resume the panic on the main thread
|
||||
}
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FsError> for AnyError {
|
||||
fn from(err: FsError) -> Self {
|
||||
match err {
|
||||
FsError::Io(err) => AnyError::from(err),
|
||||
FsError::FileBusy => resource_unavailable(),
|
||||
FsError::NotSupported => not_supported(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_cwd<Fs, P>(state: &mut OpState) -> Result<String, AnyError>
|
||||
where
|
||||
|
@ -76,13 +102,14 @@ fn op_open_sync<Fs, P>(
|
|||
) -> Result<ResourceId, AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let options = options.unwrap_or_else(OpenOptions::read);
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
options.check(permissions, &path, "Deno.openSync()")?;
|
||||
permissions.check(&options, &path, "Deno.openSync()")?;
|
||||
|
||||
let fs = state.borrow::<Fs>();
|
||||
let file = fs.open_sync(&path, options).context_path("open", &path)?;
|
||||
|
@ -99,6 +126,7 @@ async fn op_open_async<Fs, P>(
|
|||
) -> Result<ResourceId, AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
P: FsPermissions + 'static,
|
||||
{
|
||||
let path = PathBuf::from(path);
|
||||
|
@ -107,7 +135,7 @@ where
|
|||
let fs = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
options.check(permissions, &path, "Deno.open()")?;
|
||||
permissions.check(&options, &path, "Deno.open()")?;
|
||||
state.borrow::<Fs>().clone()
|
||||
};
|
||||
let file = fs
|
||||
|
@ -1117,7 +1145,7 @@ where
|
|||
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
let options = OpenOptions::write(create, append, create_new, mode);
|
||||
options.check(permissions, &path, "Deno.writeFileSync()")?;
|
||||
permissions.check(&options, &path, "Deno.writeFileSync()")?;
|
||||
|
||||
let fs = state.borrow::<Fs>();
|
||||
|
||||
|
@ -1149,7 +1177,7 @@ where
|
|||
let (fs, cancel_handle) = {
|
||||
let mut state = state.borrow_mut();
|
||||
let permissions = state.borrow_mut::<P>();
|
||||
options.check(permissions, &path, "Deno.writeFile()")?;
|
||||
permissions.check(&options, &path, "Deno.writeFile()")?;
|
||||
let cancel_handle = cancel_rid
|
||||
.and_then(|rid| state.resource_table.get::<CancelHandle>(rid).ok());
|
||||
(state.borrow::<Fs>().clone(), cancel_handle)
|
||||
|
@ -1320,6 +1348,7 @@ fn op_seek_sync<Fs>(
|
|||
) -> Result<u64, AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let pos = to_seek_from(offset, whence)?;
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1336,6 +1365,7 @@ async fn op_seek_async<Fs>(
|
|||
) -> Result<u64, AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let pos = to_seek_from(offset, whence)?;
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1350,6 +1380,7 @@ fn op_fdatasync_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
file.datasync_sync()?;
|
||||
|
@ -1363,6 +1394,7 @@ async fn op_fdatasync_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
file.datasync_async().await?;
|
||||
|
@ -1376,6 +1408,7 @@ fn op_fsync_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
file.sync_sync()?;
|
||||
|
@ -1389,6 +1422,7 @@ async fn op_fsync_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
file.sync_async().await?;
|
||||
|
@ -1403,6 +1437,7 @@ fn op_fstat_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
let stat = file.stat_sync()?;
|
||||
|
@ -1418,6 +1453,7 @@ async fn op_fstat_async<Fs>(
|
|||
) -> Result<SerializableStat, AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
let stat = file.stat_async().await?;
|
||||
|
@ -1432,6 +1468,7 @@ fn op_flock_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
check_unstable(state, "Deno.flockSync");
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1447,6 +1484,7 @@ async fn op_flock_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
check_unstable2(&state, "Deno.flock");
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1461,6 +1499,7 @@ fn op_funlock_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
check_unstable(state, "Deno.funlockSync");
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1475,6 +1514,7 @@ async fn op_funlock_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
check_unstable2(&state, "Deno.funlock");
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
|
@ -1490,6 +1530,7 @@ fn op_ftruncate_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
file.truncate_sync(len)?;
|
||||
|
@ -1504,6 +1545,7 @@ async fn op_ftruncate_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
file.truncate_async(len).await?;
|
||||
|
@ -1521,6 +1563,7 @@ fn op_futime_sync<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.resource_table.get::<Fs::File>(rid)?;
|
||||
file.utime_sync(atime_secs, atime_nanos, mtime_secs, mtime_nanos)?;
|
||||
|
@ -1538,6 +1581,7 @@ async fn op_futime_async<Fs>(
|
|||
) -> Result<(), AnyError>
|
||||
where
|
||||
Fs: FileSystem + 'static,
|
||||
Fs::File: Resource,
|
||||
{
|
||||
let file = state.borrow().resource_table.get::<Fs::File>(rid)?;
|
||||
file
|
||||
|
|
Loading…
Reference in a new issue