Repository: mitsuhiko/minijinja
Pull request #493 (2024-04-11 13:45:53)

Ranges are now iterables
This makes ranges lazy.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2af3cad..18324f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -52,6 +52,7 @@ For upgrade instructions read the [UPDATING](UPDATING.md) guide.
 - The parser no longer panics when using dotted assignments in unexpected places. #479
 - The CLI now enables unicode support by default.
 - `Value::from_serializable` is now `Value::from_serialize`.
+- Ranges are now iterables and no longer sequences. #493
 
 ## 1.0.20
 
diff --git a/minijinja/src/functions.rs b/minijinja/src/functions.rs
index 2bbbfd9..58abe1e 100644
--- a/minijinja/src/functions.rs
+++ b/minijinja/src/functions.rs
@@ -281,15 +281,17 @@ mod builtins {
     ///
     /// This function will refuse to create ranges over 10.000 items.
     #[cfg_attr(docsrs, doc(cfg(feature = "builtins")))]
-    pub fn range(lower: u32, upper: Option<u32>, step: Option<u32>) -> Result<Vec<u32>, Error> {
-        fn to_result<I: ExactSizeIterator<Item = u32>>(i: I) -> Result<Vec<u32>, Error> {
-            if i.len() > 10000 {
+    pub fn range(lower: u32, upper: Option<u32>, step: Option<u32>) -> Result<Value, Error> {
+        fn to_result<I: ExactSizeIterator<Item = u32> + Send + Sync + Clone + 'static>(
+            i: I,
+        ) -> Result<Value, Error> {
+            if i.len() > 100000 {
                 Err(Error::new(
                     ErrorKind::InvalidOperation,
                     "range has too many elements",
                 ))
             } else {
-                Ok(i.collect())
+                Ok(Value::make_iterable(move || i.clone()))
             }
         }
 


Test patch:
diff --git a/minijinja/tests/inputs/err_bad_range.txt b/minijinja/tests/inputs/err_bad_range.txt
index f298012..58c2ce7 100644
--- a/minijinja/tests/inputs/err_bad_range.txt
+++ b/minijinja/tests/inputs/err_bad_range.txt
@@ -1,3 +1,3 @@
 {}
 ---
-{{ range(10001) }}
\ No newline at end of file
+{{ range(100001) }}
\ No newline at end of file
diff --git a/minijinja/tests/inputs/functions.txt b/minijinja/tests/inputs/functions.txt
new file mode 100644
index 0000000..733a402
--- /dev/null
+++ b/minijinja/tests/inputs/functions.txt
@@ -0,0 +1,5 @@
+{}
+---
+short-range: {{ range(10) }}
+range-is-iterable: {{ range(10) is iterable }}
+range-is-not-a-sequence: {{ range(10) is not sequence }}
\ No newline at end of file
diff --git a/minijinja/tests/snapshots/test_templates__vm@err_bad_range.txt.snap b/minijinja/tests/snapshots/test_templates__vm@err_bad_range.txt.snap
index d450b15..e5eab94 100644
--- a/minijinja/tests/snapshots/test_templates__vm@err_bad_range.txt.snap
+++ b/minijinja/tests/snapshots/test_templates__vm@err_bad_range.txt.snap
@@ -1,6 +1,6 @@
 ---
 source: minijinja/tests/test_templates.rs
-description: "{{ range(10001) }}"
+description: "{{ range(100001) }}"
 info: {}
 input_file: minijinja/tests/inputs/err_bad_range.txt
 ---
@@ -15,11 +15,10 @@ Error {
 
 invalid operation: range has too many elements (in err_bad_range.txt:1)
 ------------------------------ err_bad_range.txt ------------------------------
-   1 > {{ range(10001) }}
-     i    ^^^^^^^^^^^^ invalid operation
+   1 > {{ range(100001) }}
+     i    ^^^^^^^^^^^^^ invalid operation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Referenced variables: {
     range: minijinja::functions::builtins::range,
 }
 -------------------------------------------------------------------------------
-
diff --git a/minijinja/tests/snapshots/test_templates__vm@functions.txt.snap b/minijinja/tests/snapshots/test_templates__vm@functions.txt.snap
new file mode 100644
index 0000000..62e0a08
--- /dev/null
+++ b/minijinja/tests/snapshots/test_templates__vm@functions.txt.snap
@@ -0,0 +1,9 @@
+---
+source: minijinja/tests/test_templates.rs
+description: "short-range: {{ range(10) }}\nrange-is-iterable: {{ range(10) is iterable }}\nrange-is-not-a-sequence: {{ range(10) is not sequence }}"
+info: {}
+input_file: minijinja/tests/inputs/functions.txt
+---
+short-range: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+range-is-iterable: true
+range-is-not-a-sequence: true