How Can I get this generic function to work with rayon?

use std::slice::Iter;

use rayon::prelude::*;

pub struct ResourcePartInfo {
    pub positives: Option<String>,
    pub negatives: Option<String>,
    pub effects: Option<String>,
}

pub trait SearchablePart {
    fn name(&self) -> &str;

    fn info(&self) -> &ResourcePartInfo;
}

pub trait SearchableCategorizedParts {
    type PartType: SearchablePart + Sync;

    fn category(&self) -> &str;

    fn parts(&self) -> Iter<Self::PartType>;
}

pub fn filter_parts<'a, T>(
    search_query: &str,
    parts: &'a Vec<T>,
) -> Vec<&'a <T as SearchableCategorizedParts>::PartType>
where
    &'a Vec<T>: IntoParallelIterator,
    <&'a Vec<T> as IntoParallelIterator>::Item: SearchableCategorizedParts,
    T: SearchableCategorizedParts,
    Vec<&'a <T as SearchableCategorizedParts>::PartType>: FromIterator<
        &'a <<&'a Vec<T> as IntoParallelIterator>::Item as SearchableCategorizedParts>::PartType,
    >,
{
    let search_query = search_query.trim().to_lowercase();

    parts
        .par_iter()
        .map(|cat_p: <&'a Vec<T> as IntoParallelIterator>::Item| {
            if cat_p.category().to_lowercase().contains(&search_query) {
                cat_p
                    .parts()
                    .collect::<Vec<&'a <T as SearchableCategorizedParts>::PartType>>()
            } else {
                cat_p
                    .parts()
                    .filter(|p| {
                        p.name().to_lowercase().contains(&search_query)
                            || p.info()
                                .positives
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                            || p.info()
                                .negatives
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                            || p.info()
                                .effects
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                    })
                    .collect::<Vec<&'a <T as SearchableCategorizedParts>::PartType>>()
            }
        })
        .flatten()
        .collect::<Vec<_>>()
}

fn main() {
}

(Playground)

I think the compiler is unable to reason with the abstract Item, maybe for variance or something, but it works if you restrict this to a "normal" &Vec<T> iterator:

where
    &'a Vec<T>: IntoParallelIterator<Item = &'a T>,
    &'a T: SearchableCategorizedParts,
    // etc

You could even remove the IntoParallelIterator constraint altogether and just use T: Sync.

Thanks for your help, I got this working by changing the function to the code below:

pub fn filter_parts<'a, T>(
    search_query: &str,
    parts: &'a Vec<T>,
) -> Vec<&'a <T as SearchableCategorizedParts>::PartType>
where
    T: SearchableCategorizedParts + Sync,
{
    let search_query = search_query.trim().to_lowercase();

    parts
        .into_par_iter()
        .map(|cat_p| {
            if cat_p.category().to_lowercase().contains(&search_query) {
                cat_p
                    .parts()
                    .collect::<Vec<_>>()
            } else {
                cat_p
                    .parts()
                    .filter(|p| {
                        p.name().to_lowercase().contains(&search_query)
                            || p.info()
                                .positives
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                            || p.info()
                                .negatives
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                            || p.info()
                                .effects
                                .iter()
                                .any(|p| p.to_lowercase().contains(&search_query))
                    })
                    .collect::<Vec<_>>()
            }
        })
        .flatten()
        .collect::<Vec<_>>()
}```

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.