Skip to content

Add unique filter#405

Merged
Kijewski merged 5 commits intoaskama-rs:masterfrom
GuillaumeGomez:unique-filter
Apr 22, 2025
Merged

Add unique filter#405
Kijewski merged 5 commits intoaskama-rs:masterfrom
GuillaumeGomez:unique-filter

Conversation

@GuillaumeGomez
Copy link
Copy Markdown
Collaborator

Part of the missing jinja filters.

Implementation-wise, it's the best I could come up with.

@GuillaumeGomez GuillaumeGomez force-pushed the unique-filter branch 2 times, most recently from 9475376 to 6fd12db Compare April 18, 2025 19:24
@Kijewski
Copy link
Copy Markdown
Member

Kijewski commented Apr 18, 2025

The filter must be added to the BUILTIN_FILTERS list, otherwise it won't be accessible. I am confused as to why the doc test of fn unique() passed? Could you please add a wrong assertion to it to test if it is actually invoked?

I didn't come up with a better implementation. I tried if it was possible to insert the element into a HashMap<I::Item, ()> and return a reference to the newly added key (→ VacantEntry::insert_entry()), but I couldn't get the lifetimes to work. :(

(Also, it's odd that HashMap is in std, not alloc.)

Comment thread askama/src/filters/std.rs Outdated
Comment on lines +24 to +37
let mut set = HashSet::new();

it.into_iter().filter_map(move |elem| {
// To prevent cloning the data, we need to use `Rc`, like that we can clone `elem` as
// key of the `HashSet` and return it.
let elem = Rc::new(elem);

if set.insert(Rc::clone(&elem)) {
Some(elem)
} else {
None
}
})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we increase the msrv to 1.83, then we could use VacantEntry::insert_entry(). This way the Rc only needs to be cloned if the key is actually absent from the list ↓. What do you think? Would it be worth it?

let mut set = HashMap::new();

it.into_iter().filter_map(move |elem| {
    // To prevent cloning the data, we need to use `Rc`, like that we can clone `elem` as
    // key of the `HashSet` and return it.
    if let Entry::Vacant(entry) = set.entry(Rc::new(elem)) {
        Some(Rc::clone(entry.insert_entry(()).key()))
    } else {
        None
    }
})

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huuuuuum... Ok let's go!

@GuillaumeGomez
Copy link
Copy Markdown
Collaborator Author

The filter must be added to the BUILTIN_FILTERS list, otherwise it won't be accessible. I am confused as to why the doc test of fn unique() passed? Could you please add a wrong assertion to it to test if it is actually invoked?

I didn't come up with a better implementation. I tried if it was possible to insert the element into a HashMap<I::Item, ()> and return a reference to the newly added key (→ VacantEntry::insert_entry()), but I couldn't get the lifetimes to work. :(

(Also, it's odd that HashMap is in std, not alloc.)

I tried a lot of approaches, even to have a struct containing the hashmap and the iterator etc. But performance wise, it was always terrible hence why I used Rc in the end. With generators, this code will be much better. :3

And yep, it's odd but I think it's to keep only the minimum necessary inside alloc I guess?

@GuillaumeGomez
Copy link
Copy Markdown
Collaborator Author

It should fail CI this time.

@GuillaumeGomez GuillaumeGomez force-pushed the unique-filter branch 2 times, most recently from 595cbbf to 34b3297 Compare April 18, 2025 22:19
@GuillaumeGomez
Copy link
Copy Markdown
Collaborator Author

Seems like the version wasn't updated in the fuzzer but can't figure out where the rust version is defined for it... Any idea @Kijewski ?

@Kijewski
Copy link
Copy Markdown
Member

Hm, I didn't find a switch for that. Let's see if adding a "rust-toolchain.toml" works: 27f7357

@Kijewski Kijewski force-pushed the unique-filter branch 2 times, most recently from 40306f0 to 7bab174 Compare April 19, 2025 15:09
@Kijewski Kijewski added this to the askama v0.14.0 milestone Apr 19, 2025
@Kijewski
Copy link
Copy Markdown
Member

Looks like set change has to be made in oss-fuzz:

I'll open a PR.

DavidKorczynski pushed a commit to google/oss-fuzz that referenced this pull request Apr 21, 2025
The next version of askama (v0.14) will need at least rust 1.83 to
compile. The current toolchain shipped in docker is rust 1.81, so the
project could not get fuzzed anymore.

This PR sets the used toolchain to 1.83.

Cc @GuillaumeGomez

Related issue: <askama-rs/askama#405>
@Kijewski
Copy link
Copy Markdown
Member

Looks like google/oss-fuzz#13237 worked! Needs rebasing because of #403.

Comment thread askama/src/filters/std.rs
///
/// assert_eq!(
/// Example { example: vec!["a", "b", "a", "c"] }.to_string(),
/// "a,b,c"
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is supposed to fail btw.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look like my usage of cargo nextest is wrong. Because of you I think using nextest is not needed anymore. :) You could please try if replacing cargo nextest run with cargo test in the CI config causes a failure as it should?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gladly. :D

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I forgot about that before merging. :/

Copy link
Copy Markdown

@jorgehermo9 jorgehermo9 Apr 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, sorry for jumping in.
nextest does not support doctests nextest-rs/nextest#16

What people usually do (and what nextest maintainers recommend at the issue) is to run nextest as you did before in CI, and add another step just for doctests with cargo test --doc

Comment thread .github/workflows/rust.yml Outdated
- uses: Swatinem/rust-cache@v2
- run: cargo build --all-targets --features full
- run: cargo nextest run --all-targets --no-tests=warn --features full
- run: cargo test run --all-targets --no-tests=warn --features full
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%s/cargo test run/cargo test/

Copy link
Copy Markdown
Member

@Kijewski Kijewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Kijewski Kijewski merged commit 7fccbdf into askama-rs:master Apr 22, 2025
41 checks passed
@GuillaumeGomez GuillaumeGomez deleted the unique-filter branch April 22, 2025 10:32
srividya-p pushed a commit to srividya-p/oss-fuzz that referenced this pull request Apr 27, 2025
The next version of askama (v0.14) will need at least rust 1.83 to
compile. The current toolchain shipped in docker is rust 1.81, so the
project could not get fuzzed anymore.

This PR sets the used toolchain to 1.83.

Cc @GuillaumeGomez

Related issue: <askama-rs/askama#405>
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

Successfully merging this pull request may close these issues.

3 participants