use crate::{Document, Item, PropertyValue};
use std::collections::HashSet;
pub trait LanguageFilter: Sized {
fn matches_languages(&self, languages: &HashSet<&str>) -> bool;
fn filter_by_languages_set(&self, languages: &HashSet<&str>) -> Option<Self>;
}
pub trait FindItemByProperty {
fn find_items_with_matching_property_value_by<F>(&self, predicate: F) -> Vec<(String, Item)>
where
F: Fn(String, PropertyValue) -> bool + Copy;
fn find_items_with_matching_property_value(
&self,
needle: PropertyValue,
) -> Vec<(String, Item)> {
self.find_items_with_matching_property_value_by(|_name, property_value| {
property_value == needle
})
}
}
impl FindItemByProperty for Item {
fn find_items_with_matching_property_value_by<F>(&self, predicate: F) -> Vec<(String, Item)>
where
F: Fn(String, PropertyValue) -> bool + Copy,
{
let mut values = self
.properties
.iter()
.filter_map(|(name, values)| {
if values
.iter()
.any(|value| predicate(name.to_owned(), value.to_owned()))
{
Some((name.to_owned(), self.to_owned()))
} else {
None
}
})
.collect::<Vec<_>>();
self.children.iter().for_each(|child| {
values.extend(child.find_items_with_matching_property_value_by(predicate));
});
values
}
}
impl FindItemByProperty for Document {
fn find_items_with_matching_property_value_by<F>(&self, predicate: F) -> Vec<(String, Item)>
where
F: Fn(String, PropertyValue) -> bool + std::marker::Copy,
{
self.items
.iter()
.flat_map(|item| item.find_items_with_matching_property_value_by(predicate))
.collect()
}
}
pub trait FindItemByUrl: FindItemByProperty {
fn find_item_by_url(&self, expected_url: &url::Url) -> Option<Item> {
let url_property_value = PropertyValue::Url(crate::UrlValue::new(expected_url.to_owned()));
self.find_items_with_matching_property_value(url_property_value)
.first()
.map(|(_name, value)| value.to_owned())
}
}
impl FindItemByUrl for Document {}
impl FindItemByUrl for Item {}
pub trait FindItemById {
fn find_item_by_id(&self, expected_id: &str) -> Option<Item>;
}
impl FindItemById for Item {
fn find_item_by_id(&self, expected_id: &str) -> Option<Item> {
if self.id == Some(expected_id.to_string()) {
Some(self.to_owned())
} else {
self.children
.iter()
.find_map(|item| item.find_item_by_id(expected_id))
}
}
}
impl FindItemById for Document {
fn find_item_by_id(&self, expected_id: &str) -> Option<Item> {
self.items
.iter()
.find_map(|item| item.find_item_by_id(expected_id))
}
}