Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't pass Content argument to next template #134

Open
drehren opened this issue Aug 11, 2023 · 3 comments
Open

Can't pass Content argument to next template #134

drehren opened this issue Aug 11, 2023 · 3 comments

Comments

@drehren
Copy link

drehren commented Aug 11, 2023

Hi, consider the following two templates

first_template.rs.html:

@use super::next_template_html;

@(content: Content)

@:next_template_html(content)

next_template.rs.html:

@(content: Content)

<div>
  <p>Here be content!</p>
@:content()
</div>

Compilation fails with the following:

error[E0277]: expected a `FnOnce<(&mut &mut W,)>` closure, found `impl FnOnce(&mut W) -> io::Result<()>`
  --> ructe_ex\target\debug\build\ructe_next-a19889e173553d57\out\templates\template_first_template_html.rs:12:42
   |
12 | next_template_html(_ructe_out_.by_ref(), content)?;
   | ------------------                       ^^^^^^^ expected an `FnOnce<(&mut &mut W,)>` closure, found `impl FnOnce(&mut W) -> io::Result<()>`
   | |
   | required by a bound introduced by this call
   |
   = note: expected a closure with arguments `(&mut W,)`
              found a closure with arguments `(&mut &mut W,)`
note: required by a bound in `next_template_html`
  --> ructe_ex\target\debug\build\ructe_next-a19889e173553d57\out\templates\template_next_template_html.rs:9:98
   |
9  |              pub fn next_template_html<W>(#[allow(unused_mut)] mut _ructe_out_: W, content: impl FnOnce(&mut W) -> io::Result<()>) -> io::Result<()>
   |                                                                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `next_template_html`

For more information about this error, try `rustc --explain E0277`.

Is it possible to pass Content from a template to the next ?

Thanks !

@kaj
Copy link
Owner

kaj commented Aug 14, 2023

Yes, I have also seen some problem related to this in the last release, after merging #125 .

@kornelski , could you take a look at this, could the type for content be written in a better way to solve this?

@kornelski
Copy link
Contributor

The problem here is that by_ref() is required, but it also increases level of indirection. Then every time you nest template calls, the by_ref() adds one more &mut, but the sub-templates should ideally all only require &mut W.

So when calling a template, there needs to be something anti-by-ref that decreases levels of indirection.

This hack works:

@use super::contentcallnext_html;

@(content: Content)

@:contentcallnext_html((|w|content(*w)))

Here's a minimal example:

use std::io::{self, Write};

pub fn contentcall_html<W>(#[allow(unused_mut)] mut _ructe_out_: W, content: impl FnOnce(&mut W) -> io::Result<()>) -> io::Result<()>
where W: Write {
    contentcallnext_html(_ructe_out_.by_ref(), |w| content(*w))?;
    Ok(())
}

pub fn contentcallnext_html<W>(#[allow(unused_mut)] mut _ructe_out_: W, content: impl FnOnce(&mut W) -> io::Result<()>) -> io::Result<()>
where W: Write {
    content(_ructe_out_.by_ref())?;
    Ok(())
}

@kaj Are you able to detect when argument to @:sub_template is a Content? If so, wrap arg as |w| arg(*w).

@kornelski
Copy link
Contributor

I wonder if ructe could define its own trait that calls things, so that dealing with W vs &mut W vs &dyn W distinction could be left to Rust's auto-deref method resolution magic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants