Fix unique filter implementation

This commit is contained in:
Guillaume Gomez 2025-04-22 23:04:39 +02:00 committed by René Kijewski
parent 7fccbdf1d7
commit a5b43c0aa2

View File

@ -1,3 +1,4 @@
use core::convert::Infallible;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::hash::Hash; use std::hash::Hash;
@ -9,8 +10,7 @@ use std::rc::Rc;
/// the data is wrapped inside `Rc`. /// the data is wrapped inside `Rc`.
/// ///
/// ``` /// ```
/// # #[cfg(feature = "code-in-doc")] { /// # use askama::Template;
/// # use askama::{Template, filters};
/// #[derive(Template)] /// #[derive(Template)]
/// #[template(ext = "html", source = "{% for elem in example|unique %}{{ elem }},{% endfor %}")] /// #[template(ext = "html", source = "{% for elem in example|unique %}{{ elem }},{% endfor %}")]
/// struct Example<'a> { /// struct Example<'a> {
@ -19,14 +19,15 @@ use std::rc::Rc;
/// ///
/// assert_eq!( /// assert_eq!(
/// Example { example: vec!["a", "b", "a", "c"] }.to_string(), /// Example { example: vec!["a", "b", "a", "c"] }.to_string(),
/// "a,b,c" /// "a,b,c,"
/// ); /// );
/// # }
/// ``` /// ```
pub fn unique<T: Hash + Eq>(it: impl IntoIterator<Item = T>) -> impl Iterator<Item = Rc<T>> { pub fn unique<T: Hash + Eq>(
it: impl IntoIterator<Item = T>,
) -> Result<impl Iterator<Item = Rc<T>>, Infallible> {
let mut set = HashMap::new(); let mut set = HashMap::new();
it.into_iter().filter_map(move |elem| { Ok(it.into_iter().filter_map(move |elem| {
// To prevent cloning the data, we need to use `Rc`, like that we can clone `elem` as // To prevent cloning the data, we need to use `Rc`, like that we can clone `elem` as
// key of the `HashSet` and return it. // key of the `HashSet` and return it.
if let Entry::Vacant(entry) = set.entry(Rc::new(elem)) { if let Entry::Vacant(entry) = set.entry(Rc::new(elem)) {
@ -34,7 +35,7 @@ pub fn unique<T: Hash + Eq>(it: impl IntoIterator<Item = T>) -> impl Iterator<It
} else { } else {
None None
} }
}) }))
} }
#[cfg(test)] #[cfg(test)]
@ -47,15 +48,15 @@ mod test {
#[test] #[test]
fn test_unique() { fn test_unique() {
assert_eq!( assert_eq!(
unique(["a", "b", "a", "c"]).collect::<Vec<_>>(), unique(["a", "b", "a", "c"]).unwrap().collect::<Vec<_>>(),
vec![Rc::new("a"), Rc::new("b"), Rc::new("c")] vec![Rc::new("a"), Rc::new("b"), Rc::new("c")]
); );
assert_eq!( assert_eq!(
unique([1, 1, 1, 2, 1]).collect::<Vec<_>>(), unique([1, 1, 1, 2, 1]).unwrap().collect::<Vec<_>>(),
vec![Rc::new(1), Rc::new(2)] vec![Rc::new(1), Rc::new(2)]
); );
assert_eq!( assert_eq!(
unique("hello".chars()).collect::<Vec<_>>(), unique("hello".chars()).unwrap().collect::<Vec<_>>(),
vec![Rc::new('h'), Rc::new('e'), Rc::new('l'), Rc::new('o')] vec![Rc::new('h'), Rc::new('e'), Rc::new('l'), Rc::new('o')]
); );
} }