Skip to content

Commit

Permalink
Allow passing a context object to external functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mdecimus committed Sep 26, 2023
1 parent 886956e commit 529ad02
Show file tree
Hide file tree
Showing 35 changed files with 324 additions and 299 deletions.
2 changes: 1 addition & 1 deletion src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl Compiler {
})
}

pub fn register_functions(mut self, fnc_map: &mut FunctionMap) -> Self {
pub fn register_functions<C>(mut self, fnc_map: &mut FunctionMap<C>) -> Self {
self.functions = std::mem::take(&mut fnc_map.map);
self
}
Expand Down
18 changes: 10 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,16 +312,16 @@ pub struct Compiler {
pub(crate) functions: AHashMap<String, (u32, u32)>,
}

pub type Function = for<'x> fn(&'x Context<'x>, Vec<Variable<'x>>) -> Variable<'x>;
pub type Function<C> = for<'x> fn(&'x Context<'x, C>, Vec<Variable<'x>>) -> Variable<'x>;

#[derive(Default, Clone)]
pub struct FunctionMap {
pub struct FunctionMap<C> {
pub(crate) map: AHashMap<String, (u32, u32)>,
pub(crate) functions: Vec<Function>,
pub(crate) functions: Vec<Function<C>>,
}

#[derive(Debug, Clone)]
pub struct Runtime {
pub struct Runtime<C> {
pub(crate) allowed_capabilities: AHashSet<Capability>,
pub(crate) valid_notification_uris: AHashSet<Cow<'static, str>>,
pub(crate) valid_ext_lists: AHashSet<Cow<'static, str>>,
Expand All @@ -330,7 +330,7 @@ pub struct Runtime {
pub(crate) metadata: Vec<(Metadata<String>, Cow<'static, str>)>,
pub(crate) include_scripts: AHashMap<String, Arc<Sieve>>,
pub(crate) local_hostname: Cow<'static, str>,
pub(crate) functions: Vec<Function>,
pub(crate) functions: Vec<Function<C>>,

pub(crate) max_nested_includes: usize,
pub(crate) cpu_limit: usize,
Expand All @@ -346,14 +346,16 @@ pub struct Runtime {
pub(crate) vacation_use_orig_rcpt: bool,
pub(crate) vacation_default_subject: Cow<'static, str>,
pub(crate) vacation_subject_prefix: Cow<'static, str>,

pub(crate) context: C,
}

#[derive(Clone, Debug)]
pub struct Context<'x> {
pub struct Context<'x, C> {
#[cfg(test)]
pub(crate) runtime: Runtime,
pub(crate) runtime: Runtime<C>,
#[cfg(not(test))]
pub(crate) runtime: &'x Runtime,
pub(crate) runtime: &'x Runtime<C>,
pub(crate) user_address: Cow<'x, str>,
pub(crate) user_full_name: Cow<'x, str>,
pub(crate) current_time: i64,
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/actions/action_convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ enum Conversion {
}

impl Convert {
pub(crate) fn exec(&self, ctx: &mut Context) -> TestResult {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) -> TestResult {
let from_media_type = ctx.eval_value(&self.from_media_type).into_cow();
let to_media_type = ctx.eval_value(&self.to_media_type).into_cow();

Expand Down
6 changes: 3 additions & 3 deletions src/runtime/actions/action_editheader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::{
};

impl AddHeader {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let header_name_ = ctx.eval_value(&self.field_name).into_cow();
let mut header_name = String::with_capacity(header_name_.len());

Expand Down Expand Up @@ -68,7 +68,7 @@ impl AddHeader {
}

impl DeleteHeader {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let header_name = if let Some(header_name) =
HeaderName::parse(ctx.eval_value(&self.field_name).into_cow())
{
Expand Down Expand Up @@ -175,7 +175,7 @@ impl RemoveCrLf for &str {
}
}

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn insert_header(
&mut self,
part_id: usize,
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/actions/action_fileinto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
use crate::{compiler::grammar::actions::action_fileinto::FileInto, Context, Event};

impl FileInto {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let folder = ctx.eval_value(&self.folder).into_string();
let mut events = Vec::with_capacity(2);
if let Some(event) = ctx.build_message_id() {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/actions/action_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
};

impl EditFlags {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let mut var_name_ = None;
let var_name = self.name.as_ref().unwrap_or_else(|| {
var_name_.get_or_insert_with(|| VariableType::Global("__flags".to_string()))
Expand Down Expand Up @@ -103,7 +103,7 @@ impl EditFlags {
}
}

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn tokenize_flags(
&self,
strings: &[Value],
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/actions/action_include.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub(crate) enum IncludeResult {
}

impl Include {
pub(crate) fn exec(&self, ctx: &Context) -> IncludeResult {
pub(crate) fn exec<C>(&self, ctx: &Context<C>) -> IncludeResult {
let script_name = ctx.eval_value(&self.value);
if !script_name.is_empty() {
let script_name = if self.location == Location::Global {
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/actions/action_mime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use super::action_editheader::RemoveCrLf;
use mail_builder::headers::message_id::generate_message_id_header;

impl Replace {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
// Delete children parts
let mut part_ids = ctx.find_nested_parts_ids(false);
part_ids.sort_unstable_by_key(|a| Reverse(*a));
Expand Down Expand Up @@ -182,7 +182,7 @@ impl Replace {
}

impl Enclose {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let body = ctx.eval_value(&self.value).into_string();
let subject = self
.subject
Expand Down Expand Up @@ -341,7 +341,7 @@ impl Enclose {
}

impl ExtractText {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let mut value = String::new();

if !ctx.part_iter_stack.is_empty() {
Expand Down Expand Up @@ -400,7 +400,7 @@ enum StackItem<'x> {
None,
}

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn build_message_id(&mut self) -> Option<Event> {
if self.has_changes {
self.last_message_id += 1;
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/actions/action_notify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::{
use super::action_vacation::MAX_SUBJECT_LEN;

impl Notify {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
// Do not notify on Auto-Submitted messages
for header in &ctx.message.parts[0].headers {
if matches!(&header.name, HeaderName::Other(name) if name.eq_ignore_ascii_case("Auto-Submitted"))
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/actions/action_redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
};

impl Redirect {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
if let Some(address) = sanitize_address(ctx.eval_value(&self.address).into_cow().as_ref()) {
if ctx.num_redirects < ctx.runtime.max_redirects
&& ctx.num_out_messages < ctx.runtime.max_out_messages
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/actions/action_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use crate::{
use std::fmt::Write;

impl Set {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let mut value = ctx.eval_value(&self.value).into_owned();
for modifier in &self.modifiers {
value = modifier.apply(value.into_cow().as_ref(), ctx).into();
Expand All @@ -42,7 +42,7 @@ impl Set {
}
}

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn set_variable(&mut self, var_name: &VariableType, mut variable: Variable<'x>) {
if variable.len() > self.runtime.max_variable_size {
let mut new_variable = String::with_capacity(self.runtime.max_variable_size);
Expand Down Expand Up @@ -100,7 +100,7 @@ impl<'x> Context<'x> {
}

impl Modifier {
pub(crate) fn apply(&self, input: &str, ctx: &Context) -> String {
pub(crate) fn apply<C>(&self, input: &str, ctx: &Context<C>) -> String {
let max_len = ctx.runtime.max_variable_size;
match self {
Modifier::Lower => input.to_lowercase(),
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/actions/action_vacation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::{
pub(crate) const MAX_SUBJECT_LEN: usize = 256;

impl TestVacation {
pub(crate) fn exec(&self, ctx: &mut Context) -> TestResult {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) -> TestResult {
let mut from = String::new();
let mut user_addresses = Vec::new();

Expand Down Expand Up @@ -177,7 +177,7 @@ impl TestVacation {
}

impl Vacation {
pub(crate) fn exec(&self, ctx: &mut Context) {
pub(crate) fn exec<C>(&self, ctx: &mut Context<C>) {
let mut vacation_to = Cow::from("");

for (name, value) in &ctx.envelope {
Expand Down
10 changes: 8 additions & 2 deletions src/runtime/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ pub(crate) struct ScriptStack {
pub(crate) prev_vars_match: Vec<Variable<'static>>,
}

impl<'x> Context<'x> {
pub(crate) fn new(runtime: &'x Runtime, message: Message<'x>) -> Self {
impl<'x, C: Clone> Context<'x, C> {
pub(crate) fn new(runtime: &'x Runtime<C>, message: Message<'x>) -> Self {
Context {
#[cfg(test)]
runtime: runtime.clone(),
Expand Down Expand Up @@ -90,7 +90,9 @@ impl<'x> Context<'x> {
spam_status: SpamStatus::Unknown,
}
}
}

impl<'x, C> Context<'x, C> {
#[allow(clippy::while_let_on_iterator)]
pub fn run(&mut self, input: Input) -> Option<Result<Event, RuntimeError>> {
match input {
Expand Down Expand Up @@ -632,4 +634,8 @@ impl<'x> Context<'x> {
pub fn part(&self) -> usize {
self.part
}

pub fn context(&self) -> &C {
&self.runtime.context
}
}
2 changes: 1 addition & 1 deletion src/runtime/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use crate::{

use super::Variable;

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn variable<'y: 'x>(&'y self, var: &VariableType) -> Option<Variable<'x>> {
match var {
VariableType::Local(var_num) => self.vars_local.get(*var_num).map(|v| v.as_ref()),
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{compiler::Number, runtime::Variable, Context};

use crate::compiler::grammar::expr::{BinaryOperator, Constant, Expression, UnaryOperator};

impl<'x> Context<'x> {
impl<'x, C> Context<'x, C> {
pub(crate) fn eval_expression<'y: 'x>(
&'y self,
expr: &'x [Expression],
Expand Down
Loading

0 comments on commit 529ad02

Please sign in to comment.