From 0311bab45ba045106c4bcd96844a0f7afaab29d7 Mon Sep 17 00:00:00 2001
From: Chris Wong <lambda.fairy@gmail.com>
Date: Thu, 24 Sep 2015 11:50:33 +1200
Subject: [PATCH] Add `#call_box` instruction

---
 maud_macros/src/parse.rs   |  5 ++++
 maud_macros/src/render.rs  | 10 ++++++++
 maud_macros/tests/tests.rs | 47 +++++++++++++++++++++++---------------
 3 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs
index 68f6003..e575f60 100644
--- a/maud_macros/src/parse.rs
+++ b/maud_macros/src/parse.rs
@@ -158,6 +158,11 @@ impl<'cx, 'i> Parser<'cx, 'i> {
                 let func = try!(self.splice(sp));
                 self.render.emit_call(func);
             },
+            [pound!(), ident!(sp, name), ..] if name.name == "call_box" => {
+                self.shift(2);
+                let func = try!(self.splice(sp));
+                self.render.emit_call_box(func);
+            },
             // Splice
             [ref tt @ dollar!(), dollar!(), ..] => {
                 self.shift(2);
diff --git a/maud_macros/src/render.rs b/maud_macros/src/render.rs
index 36add0e..737ae8e 100644
--- a/maud_macros/src/render.rs
+++ b/maud_macros/src/render.rs
@@ -197,6 +197,16 @@ impl<'cx> Renderer<'cx> {
         let stmt = self.wrap_try(expr);
         self.push(stmt);
     }
+
+    pub fn emit_call_box(&mut self, func: P<Expr>) {
+        let w = self.writer;
+        let expr = quote_expr!(self.cx,
+            ::std::boxed::FnBox::call_box(
+                $func,
+                (&mut *$w as &mut ::std::fmt::Write,)));
+        let stmt = self.wrap_try(expr);
+        self.push(stmt);
+    }
 }
 
 fn html_escape(s: &str) -> String {
diff --git a/maud_macros/tests/tests.rs b/maud_macros/tests/tests.rs
index cbbb8d6..673f026 100644
--- a/maud_macros/tests/tests.rs
+++ b/maud_macros/tests/tests.rs
@@ -1,10 +1,8 @@
-#![feature(plugin)]
+#![feature(fnbox, plugin)]
 #![plugin(maud_macros)]
 
 extern crate maud;
 
-use std::fmt;
-
 #[test]
 fn literals() {
     let mut s = String::new();
@@ -274,22 +272,35 @@ mod issue_10 {
     }
 }
 
-#[test]
-fn call() {
+mod subtemplates {
+    use std::fmt;
+
     fn ducks(w: &mut fmt::Write) -> fmt::Result {
         write!(w, "Ducks")
     }
-    let mut s = String::new();
-    let swans = |yes|
-        if yes {
-            |w: &mut fmt::Write| write!(w, "Swans")
-        } else {
-            panic!("oh noes")
-        };
-    html!(s, {
-        #call ducks
-        #call (|w: &mut fmt::Write| write!(w, "Geese"))
-        #call swans(true)
-    }).unwrap();
-    assert_eq!(s, "DucksGeeseSwans");
+
+    #[test]
+    fn call() {
+        let mut s = String::new();
+        let swans = |yes|
+            if yes {
+                |w: &mut fmt::Write| write!(w, "Swans")
+            } else {
+                panic!("oh noes")
+            };
+        html!(s, {
+            #call ducks
+            #call (|w: &mut fmt::Write| write!(w, "Geese"))
+            #call swans(true)
+        }).unwrap();
+        assert_eq!(s, "DucksGeeseSwans");
+    }
+
+    #[test]
+    fn call_box() {
+        let mut s = String::new();
+        let ducks = Box::new(ducks);
+        html!(s, #call_box ducks).unwrap();
+        assert_eq!(s, "Ducks");
+    }
 }