use crate::csaf_traits::{WithOptionalGroupIds, WithOptionalProductIds};
fn extract_group_id_impl<'a, T: WithOptionalGroupIds + 'a>(
items: impl Iterator<Item = &'a T>,
path_prefix: &str,
) -> Vec<(String, String)> {
let mut ids: Vec<(String, String)> = Vec::new();
for (index, item) in items.enumerate() {
if let Some(group_ids) = item.get_group_ids() {
for (group_index, group_id) in group_ids.enumerate() {
ids.push((
group_id.to_owned(),
format!("{path_prefix}/{index}/group_ids/{group_index}"),
))
}
}
}
ids
}
fn extract_product_id_impl<'a, T: WithOptionalProductIds + 'a>(
items: impl Iterator<Item = &'a T>,
path_prefix: &str,
) -> Vec<(String, String)> {
let mut ids: Vec<(String, String)> = Vec::new();
for (index, item) in items.enumerate() {
if let Some(product_ids) = item.get_product_ids() {
for (product_index, product_id) in product_ids.enumerate() {
ids.push((
product_id.to_owned(),
format!("{path_prefix}/{index}/product_ids/{product_index}"),
))
}
}
}
ids
}
pub trait ExtractGroupReferences<T: WithOptionalGroupIds> {
fn extract_group_references(&self, path_prefix: &str) -> Vec<(String, String)>;
}
impl<T: WithOptionalGroupIds> ExtractGroupReferences<T> for Option<&Vec<T>> {
fn extract_group_references(&self, path_prefix: &str) -> Vec<(String, String)> {
extract_group_id_impl(self.iter().flat_map(|x| x.iter()), path_prefix)
}
}
impl<T: WithOptionalGroupIds> ExtractGroupReferences<T> for Vec<T> {
fn extract_group_references(&self, path_prefix: &str) -> Vec<(String, String)> {
extract_group_id_impl(self.iter(), path_prefix)
}
}
pub trait ExtractProductReferences<T: WithOptionalProductIds> {
fn extract_product_references(&self, path_prefix: &str) -> Vec<(String, String)>;
}
impl<T: WithOptionalProductIds> ExtractProductReferences<T> for Option<&Vec<T>> {
fn extract_product_references(&self, path_prefix: &str) -> Vec<(String, String)> {
extract_product_id_impl(self.iter().flat_map(|x| x.iter()), path_prefix)
}
}
impl<T: WithOptionalProductIds> ExtractProductReferences<T> for Vec<T> {
fn extract_product_references(&self, path_prefix: &str) -> Vec<(String, String)> {
extract_product_id_impl(self.iter(), path_prefix)
}
}
macro_rules! define_reference_accessors {
(
both: [
$(
($group_method:ident, $product_method:ident, $getter:ident, $path:literal)
),* $(,)?
],
custom_group_extraction: [ $( $custom_group_extraction_method:ident ),* $(,)? ],
custom_product_extraction: [ $( $custom_product_extraction_method:ident ),* $(,)? ] $(,)?
) => {
$(
/// Get all group references from this element
fn $group_method(&self) -> Vec<(String, String)> {
self.$getter().extract_group_references($path)
}
fn $product_method(&self) -> Vec<(String, String)> {
self.$getter().extract_product_references($path)
}
)*
fn get_all_group_references(&self) -> Vec<(String, String)> {
let mut refs = Vec::new();
$( refs.extend(self.$group_method()); )*
$( refs.extend(self.$custom_group_extraction_method()); )*
refs
}
fn get_all_product_references(&self) -> Vec<(String, String)> {
let mut refs = Vec::new();
$( refs.extend(self.$product_method()); )*
$( refs.extend(self.$custom_product_extraction_method()); )*
refs
}
};
}
pub(crate) use define_reference_accessors;