Repository: djc/askama (rust)

Issue:
Add support for reference operator (i.e. `{% let x = &y %}`)
Sometimes while working with deeply nested structures, it would be useful to create an alias to a field, like say `{% let h = &parent.child.hash %}`

At the moment the `&` unary operator is not supported.


Pull request description:
Add automatic borrowing to `let` statements
Adds automatic borrowing to `let` statements if value isn't "copyable". Eases #330.

Patch:
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 65136c6..df15bdc 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -916,7 +916,14 @@ impl<'a> Generator<'a> {
         };
 
         let mut expr_buf = Buffer::new(0);
+        let borrow_val = !is_copyable(val);
+        if borrow_val {
+            expr_buf.write("&(");
+        }
         self.visit_expr(&mut expr_buf, val)?;
+        if borrow_val {
+            expr_buf.write(")");
+        }
 
         let shadowed = self.is_shadowing_variable(&l.var)?;
         if shadowed {
@@ -1945,7 +1952,7 @@ fn is_copyable_within_op(expr: &Expr<'_>, within_op: bool) -> bool {
 pub(crate) fn is_attr_self(expr: &Expr<'_>) -> bool {
     match expr {
         Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Var("self")) => true,
-        Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => is_attr_self(expr),
+        Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => is_attr_self(obj),
         _ => false,
     }
 }


Test patch:
diff --git a/testing/tests/calls.rs b/testing/tests/calls.rs
index 052f34f..28d7491 100644
--- a/testing/tests/calls.rs
+++ b/testing/tests/calls.rs
@@ -80,3 +80,22 @@ fn test_one_func_binop() {
     };
     assert_eq!(t.render().unwrap(), "246");
 }
+
+fn double_attr_arg_helper(x: u32) -> u32 {
+    x * x + x
+}
+
+#[derive(askama::Template)]
+#[template(
+    source = "{{ self::double_attr_arg_helper(self.x.0 + 2) }}",
+    ext = "txt"
+)]
+struct DoubleAttrArg {
+    x: (u32,),
+}
+
+#[test]
+fn test_double_attr_arg() {
+    let t = DoubleAttrArg { x: (10,) };
+    assert_eq!(t.render().unwrap(), "156");
+}
diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs
index f0f0a26..55353f5 100644
--- a/testing/tests/simple.rs
+++ b/testing/tests/simple.rs
@@ -484,3 +484,17 @@ fn test_num_literals() {
         "[90, -90, 90, 2, 56, 240, 10.5, 10.5, 100000000000, 105000000000]",
     );
 }
+
+#[derive(askama::Template)]
+#[template(source = "{% let word = s %}{{ word }}", ext = "html")]
+struct LetBorrow {
+    s: String,
+}
+
+#[test]
+fn test_let_borrow() {
+    let template = LetBorrow {
+        s: "hello".to_owned(),
+    };
+    assert_eq!(template.render().unwrap(), "hello")
+}