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

Iterate over NewType Vec<T> #207

Closed
JulianSza opened this issue Feb 13, 2019 · 10 comments
Closed

Iterate over NewType Vec<T> #207

JulianSza opened this issue Feb 13, 2019 · 10 comments

Comments

@JulianSza
Copy link

Can I use a NewType wrapper around Vec<T> in for x in y template file?

If I use something like struct X {values: Vec<Y>} then I can easily get its data using for x in values. This template will compile to for (_loop_index, x) in (&self.values).iter_into().enumerate().

But I want to use NewType instead of a normal struct.

So I need to iterate over self.0 -> how do I write template for that?

for x in self.0 returns or (_loop_index, x) in (&self.self.0).into_iter().enumerate()

for x in 0 returns for (_loop_index, x) in (&0).into_iter().enumerate()

Is there something obvious that I am missing?

This is the struct I am playing with and the template in question:

#[derive(Template)]
#[template(path = "handlers.html", print="all")]
struct VA ( Vec<A>);

impl std::ops::DerefMut for VA {
    fn deref_mut(&mut self) -> &mut Vec<A>{
        &mut self.0
    }
}
{% for a in ??? %}
...
{% endfor %}
@djc
Copy link
Owner

djc commented Feb 13, 2019

Try implementing IntoIter for your newtype?

@kellenff
Copy link
Contributor

kellenff commented Feb 13, 2019

@JulianSza from the Rust IntoIterator trait docs, this should work:

#[derive(Template)]
#[template(path = "handlers.html", print="all")]
struct VA(Vec<A>);

impl IntoIterator for VA {
    type Item = A;
    type IntoIter = std::vec::IntoIter<A>;
    
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

Playground link

And then you'd use it like so in the template:

{% for a in va %}
...
{% endfor %}

@JulianSza
Copy link
Author

Thanks for quick responses and forgive the stupidity; this is my first time in Rust.

I think my problem is more basic than that; I am struggling to find a iterator's 'handle' from the template.

Even after implementing IntoIter I do not know 'what' I am supposed to iterate.

The code below will fail with error[E0609]: no field va on type &VA. Which I think makes sense. But iterating va, VA, self.0, 0, _ (yes, I am trying anything at this point) does not make it better.

#[macro_use]
extern crate askama;
use askama::Template;

#[derive(Template)]
#[template(path = "handlers.html", print="all")]
struct VA(Vec<A>);
type A = String;

impl VA {
    fn new () -> VA {
        VA(Vec::new())
    }
}

impl IntoIterator for VA {
    type Item = A;
    type IntoIter = std::vec::IntoIter<A>;
    
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl std::ops::Deref for VA {
    type Target = Vec<A>;
    fn deref(&self) -> &Vec<A> {
        &self.0
    }
}

impl std::ops::DerefMut for VA {
    fn deref_mut(&mut self) -> &mut Vec<A>{
        &mut self.0
    }
}

fn main() {
    let va = VA::new();
    dbg!(va.render().unwrap());
}

//handlers.html
// {% for a in va %}             <<---- this is the line that makes me cry
// {{ a }}
// {% endfor %}

@djc
Copy link
Owner

djc commented Feb 13, 2019

In this case your variable va in the context of main will be self in the template content. Try for a in self? (I'm not a 100% sure that works, but at least it hopefully makes it clearer what is going on.)

@JulianSza
Copy link
Author

JulianSza commented Feb 13, 2019

Yup, tried that too, this one will result in self.self

for (_loop_index, a) in (&self.self).into_iter().enumerate()

Compiler will say no field self on type &VA.

Which led me into thinking I need to iterate 0. But then I get this: for (_loop_index, a) in (&0).into_iter().enumerate()

Edit:

I should mention that I am looking to get for (_loop_index, a) in (&self.0).into_iter().enumerate() as the outcome of the template macro. I verified that replacing Template macro with the actual generated code + changing self.self to self.0 gives me the proper result

@kellenff
Copy link
Contributor

Is there a reason it needs to be a NewType and not a struct with a single field?

@JulianSza
Copy link
Author

Yes, it is because I want it this way:)

Using a struct with single field works fine. But it looks ugly in my opinion.

If the answer is 'you cannot have it' then I am fine with it. But if NewType is supported by askama then I would like to figure out how to use it

@kellenff
Copy link
Contributor

Totally understand, just curious :)

@djc
Copy link
Owner

djc commented Feb 13, 2019

Yeah, so this is not quite well supported right now. It would probably be fairly easy to fix it, though, such that self can be used correctly (it involves adding self as a known local variable in the code generator).

@JulianSza
Copy link
Author

Thank you thank you thank you, this is exactly how I wanted to use it!

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