Repository: mitsuhiko/minijinja
Pull request #113 (2022-09-09 20:39:51)

Seal Filter/Test/Function
These traits were not intended to be implemented by users.

Refs #112


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c97b27e..9c9b9db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@ All notable changes to MiniJinja are documented here.
 - Added custom formatters.
 - Restructured engine internals for greater clarity.
 - Added support for rendering to `io::Write`.  (#111)
+- Make it impossible to implement `Fitler`, `Test`
+  or `Function` from outside the crate (sealed the traits).
 
 # 0.20.0
 
diff --git a/minijinja/src/filters.rs b/minijinja/src/filters.rs
index 1e1d13a..f034a92 100644
--- a/minijinja/src/filters.rs
+++ b/minijinja/src/filters.rs
@@ -60,6 +60,7 @@ use std::sync::Arc;
 use crate::defaults::escape_formatter;
 use crate::error::Error;
 use crate::output::Output;
+use crate::utils::SealedMarker;
 use crate::value::{ArgType, FunctionArgs, FunctionResult, Value};
 use crate::vm::State;
 use crate::AutoEscape;
@@ -103,7 +104,7 @@ pub(crate) struct BoxedFilter(Arc<FilterFunc>);
 pub trait Filter<V, Rv, Args>: Send + Sync + 'static {
     /// Applies a filter to value with the given arguments.
     #[doc(hidden)]
-    fn apply_to(&self, state: &State, value: V, args: Args) -> Rv;
+    fn apply_to(&self, state: &State, value: V, args: Args, _: SealedMarker) -> Rv;
 }
 
 macro_rules! tuple_impls {
@@ -115,7 +116,7 @@ macro_rules! tuple_impls {
             Rv: FunctionResult,
             $($name: for<'a> ArgType<'a>),*
         {
-            fn apply_to(&self, state: &State, value: V, args: ($($name,)*)) -> Rv {
+            fn apply_to(&self, state: &State, value: V, args: ($($name,)*), _: SealedMarker) -> Rv {
                 #[allow(non_snake_case)]
                 let ($($name,)*) = args;
                 (self)(state, value, $($name,)*)
@@ -145,6 +146,7 @@ impl BoxedFilter {
                     state,
                     ArgType::from_value(Some(value))?,
                     FunctionArgs::from_values(args)?,
+                    SealedMarker,
                 )
                 .into_result()
             },
diff --git a/minijinja/src/functions.rs b/minijinja/src/functions.rs
index 425b2c9..bc9779f 100644
--- a/minijinja/src/functions.rs
+++ b/minijinja/src/functions.rs
@@ -52,6 +52,7 @@ use std::fmt;
 use std::sync::Arc;
 
 use crate::error::Error;
+use crate::utils::SealedMarker;
 use crate::value::{ArgType, FunctionArgs, FunctionResult, Object, Value};
 use crate::vm::State;
 
@@ -98,7 +99,7 @@ pub(crate) struct BoxedFunction(Arc<FuncFunc>, &'static str);
 pub trait Function<Rv, Args>: Send + Sync + 'static {
     /// Calls a function with the given arguments.
     #[doc(hidden)]
-    fn invoke(&self, env: &State, args: Args) -> Rv;
+    fn invoke(&self, env: &State, args: Args, _: SealedMarker) -> Rv;
 }
 
 macro_rules! tuple_impls {
@@ -109,7 +110,7 @@ macro_rules! tuple_impls {
             Rv: FunctionResult,
             $($name: for<'a> ArgType<'a>),*
         {
-            fn invoke(&self, state: &State, args: ($($name,)*)) -> Rv {
+            fn invoke(&self, state: &State, args: ($($name,)*), _: SealedMarker) -> Rv {
                 #[allow(non_snake_case)]
                 let ($($name,)*) = args;
                 (self)(state, $($name,)*)
@@ -134,7 +135,7 @@ impl BoxedFunction {
     {
         BoxedFunction(
             Arc::new(move |env, args| -> Result<Value, Error> {
-                f.invoke(env, FunctionArgs::from_values(args)?)
+                f.invoke(env, FunctionArgs::from_values(args)?, SealedMarker)
                     .into_result()
             }),
             std::any::type_name::<F>(),
diff --git a/minijinja/src/utils.rs b/minijinja/src/utils.rs
index 20c3810..155add2 100644
--- a/minijinja/src/utils.rs
+++ b/minijinja/src/utils.rs
@@ -9,6 +9,9 @@ use crate::error::{Error, ErrorKind};
 #[cfg(test)]
 use similar_asserts::assert_eq;
 
+/// internal marker to seal up some trait methods
+pub struct SealedMarker;
+
 pub fn memchr(haystack: &[u8], needle: u8) -> Option<usize> {
     haystack.iter().position(|&x| x == needle)
 }


Test patch:
diff --git a/minijinja/src/tests.rs b/minijinja/src/tests.rs
index 98738bc..b91b9f6 100644
--- a/minijinja/src/tests.rs
+++ b/minijinja/src/tests.rs
@@ -58,6 +58,7 @@
 use std::sync::Arc;
 
 use crate::error::Error;
+use crate::utils::SealedMarker;
 use crate::value::{ArgType, FunctionArgs, Value};
 use crate::vm::State;
 
@@ -126,7 +127,7 @@ impl TestResult for bool {
 pub trait Test<V, Rv, Args>: Send + Sync + 'static {
     /// Performs a test to value with the given arguments.
     #[doc(hidden)]
-    fn perform(&self, state: &State, value: V, args: Args) -> Rv;
+    fn perform(&self, state: &State, value: V, args: Args, _: SealedMarker) -> Rv;
 }
 
 macro_rules! tuple_impls {
@@ -138,7 +139,7 @@ macro_rules! tuple_impls {
             Rv: TestResult,
             $($name: for<'a> ArgType<'a>),*
         {
-            fn perform(&self, state: &State, value: V, args: ($($name,)*)) -> Rv {
+            fn perform(&self, state: &State, value: V, args: ($($name,)*), _: SealedMarker) -> Rv {
                 #[allow(non_snake_case)]
                 let ($($name,)*) = args;
                 (self)(state, value, $($name,)*)
@@ -168,6 +169,7 @@ impl BoxedTest {
                 state,
                 ArgType::from_value(value)?,
                 FunctionArgs::from_values(args)?,
+                SealedMarker,
             )
             .into_result()
         }))