Skip to main content
Module

x/deno/core/extensions.rs

A modern runtime for JavaScript and TypeScript.
Go to Latest
File
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.use crate::OpState;use anyhow::Error;use std::task::Context;
pub type SourcePair = (&'static str, Box<SourceLoadFn>);pub type SourceLoadFn = dyn Fn() -> Result<String, Error>;pub type OpFnRef = v8::FunctionCallback;pub type OpMiddlewareFn = dyn Fn(OpDecl) -> OpDecl;pub type OpStateFn = dyn Fn(&mut OpState) -> Result<(), Error>;pub type OpEventLoopFn = dyn Fn(&mut OpState, &mut Context) -> bool;
#[derive(Clone, Copy)]pub struct OpDecl { pub name: &'static str, pub v8_fn_ptr: OpFnRef, pub enabled: bool, pub is_async: bool, // TODO(@AaronO): enum sync/async/fast ? pub is_unstable: bool,}
impl OpDecl { pub fn enabled(self, enabled: bool) -> Self { Self { enabled, ..self } }
pub fn disable(self) -> Self { self.enabled(false) }}
#[derive(Default)]pub struct Extension { js_files: Option<Vec<SourcePair>>, ops: Option<Vec<OpDecl>>, opstate_fn: Option<Box<OpStateFn>>, middleware_fn: Option<Box<OpMiddlewareFn>>, event_loop_middleware: Option<Box<OpEventLoopFn>>, initialized: bool, enabled: bool,}
// Note: this used to be a trait, but we "downgraded" it to a single concrete type// for the initial iteration, it will likely become a trait in the futureimpl Extension { pub fn builder() -> ExtensionBuilder { Default::default() }
/// returns JS source code to be loaded into the isolate (either at snapshotting, /// or at startup). as a vector of a tuple of the file name, and the source code. pub fn init_js(&self) -> &[SourcePair] { match &self.js_files { Some(files) => files, None => &[], } }
/// Called at JsRuntime startup to initialize ops in the isolate. pub fn init_ops(&mut self) -> Option<Vec<OpDecl>> { // TODO(@AaronO): maybe make op registration idempotent if self.initialized { panic!("init_ops called twice: not idempotent or correct"); } self.initialized = true;
let mut ops = self.ops.take()?; for op in ops.iter_mut() { op.enabled = self.enabled && op.enabled; } Some(ops) }
/// Allows setting up the initial op-state of an isolate at startup. pub fn init_state(&self, state: &mut OpState) -> Result<(), Error> { match &self.opstate_fn { Some(ofn) => ofn(state), None => Ok(()), } }
/// init_middleware lets us middleware op registrations, it's called before init_ops pub fn init_middleware(&mut self) -> Option<Box<OpMiddlewareFn>> { self.middleware_fn.take() }
pub fn init_event_loop_middleware(&mut self) -> Option<Box<OpEventLoopFn>> { self.event_loop_middleware.take() }
pub fn run_event_loop_middleware( &self, op_state: &mut OpState, cx: &mut Context, ) -> bool { self .event_loop_middleware .as_ref() .map(|f| f(op_state, cx)) .unwrap_or(false) }
pub fn enabled(self, enabled: bool) -> Self { Self { enabled, ..self } }
pub fn disable(self) -> Self { self.enabled(false) }}
// Provides a convenient builder pattern to declare Extensions#[derive(Default)]pub struct ExtensionBuilder { js: Vec<SourcePair>, ops: Vec<OpDecl>, state: Option<Box<OpStateFn>>, middleware: Option<Box<OpMiddlewareFn>>, event_loop_middleware: Option<Box<OpEventLoopFn>>,}
impl ExtensionBuilder { pub fn js(&mut self, js_files: Vec<SourcePair>) -> &mut Self { self.js.extend(js_files); self }
pub fn ops(&mut self, ops: Vec<OpDecl>) -> &mut Self { self.ops.extend(ops); self }
pub fn state<F>(&mut self, opstate_fn: F) -> &mut Self where F: Fn(&mut OpState) -> Result<(), Error> + 'static, { self.state = Some(Box::new(opstate_fn)); self }
pub fn middleware<F>(&mut self, middleware_fn: F) -> &mut Self where F: Fn(OpDecl) -> OpDecl + 'static, { self.middleware = Some(Box::new(middleware_fn)); self }
pub fn event_loop_middleware<F>(&mut self, middleware_fn: F) -> &mut Self where F: Fn(&mut OpState, &mut Context) -> bool + 'static, { self.event_loop_middleware = Some(Box::new(middleware_fn)); self }
pub fn build(&mut self) -> Extension { let js_files = Some(std::mem::take(&mut self.js)); let ops = Some(std::mem::take(&mut self.ops)); Extension { js_files, ops, opstate_fn: self.state.take(), middleware_fn: self.middleware.take(), event_loop_middleware: self.event_loop_middleware.take(), initialized: false, enabled: true, } }}/// Helps embed JS files in an extension. Returns Vec<(&'static str, Box<SourceLoadFn>)>/// representing the filename and source code. This is only meant for extensions/// that will be snapshotted, as code will be loaded at runtime.////// Example:/// ```ignore/// include_js_files!(/// prefix "deno:extensions/hello",/// "01_hello.js",/// "02_goodbye.js",/// )/// ```#[macro_export]macro_rules! include_js_files { (prefix $prefix:literal, $($file:literal,)+) => { vec![ $(( concat!($prefix, "/", $file), Box::new(|| { let c = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); let path = c.join($file); println!("cargo:rerun-if-changed={}", path.display()); let src = std::fs::read_to_string(path)?; Ok(src) }), ),)+ ] };}