#[macro_export]
macro_rules! __multimap_combined_getters {
(@generate_combos
$vis:vis $map_name:ident<$value_type:ty>,
// all non-unique fields as (name, key_type, expr_param, expr) tuples
all_fields: [$(($fname:ident: $fkey:ty))*],
selected: [$($sel_name:ident: $sel_key:ty),*],
remaining: [$next_name:ident: $next_key:ty, $($rest_name:ident: $rest_key:ty,)*]
) => {
$crate::__multimap_combined_getters!(@generate_combos
$vis $map_name<$value_type>,
all_fields: [$(($fname: $fkey))*],
selected: [$($sel_name: $sel_key),*],
remaining: [$($rest_name: $rest_key,)*]
);
$crate::__multimap_combined_getters!(@generate_combos
$vis $map_name<$value_type>,
all_fields: [$(($fname: $fkey))*],
selected: [$($sel_name: $sel_key,)* $next_name: $next_key],
remaining: [$($rest_name: $rest_key,)*]
);
};
(@generate_combos
$vis:vis $map_name:ident<$value_type:ty>,
all_fields: [$($_f:tt)*],
selected: [$first_name:ident: $first_key:ty, $second_name:ident: $second_key:ty $(,$more_name:ident: $more_key:ty)*],
remaining: []
) => {
paste! {
#[doc = "Get a reference to a value, if it exist, by indexing by multiple keys."]
$vis fn [<get_by_ $first_name _ $second_name $( _ $more_name)*>]<'a>(
&'a self,
$first_name: &$first_key,
$second_name: &$second_key,
$($more_name: &$more_key,)*
) -> impl Iterator<Item = &'a $value_type> {
let result: Option<std::collections::HashSet<_>> = (|| {
let first_set = self.$first_name.get($first_name)?;
let second_set = self.$second_name.get($second_name)?;
let mut intersection: std::collections::HashSet<_> =
first_set.intersection(second_set).copied().collect();
$(
let next_set = self.$more_name.get($more_name)?;
intersection = intersection.intersection(next_set).copied().collect();
)*
Some(intersection)
})();
result
.into_iter()
.flatten()
.collect::<Vec<_>>()
.into_iter()
.filter_map(|key| self.storage.get(&key))
}
#[doc = "Get a mutable modifier for a value, if it exist, by indexing by multiple keys."]
$vis fn [<get_mut_by_ $first_name _ $second_name $( _ $more_name)*>](
&mut self,
$first_name: &$first_key,
$second_name: &$second_key,
$($more_name: &$more_key,)*
) -> [<$map_name MutEntries>]<'_> {
let first_set = match self.$first_name.get($first_name) {
Some(s) => s,
None => return [<$map_name MutEntries>] {
entries: vec![].into_iter(),
hashmap: self,
},
};
let second_set = match self.$second_name.get($second_name) {
Some(s) => s,
None => return [<$map_name MutEntries>] {
entries: vec![].into_iter(),
hashmap: self,
},
};
let mut intersection: std::collections::HashSet<_> =
first_set.intersection(second_set).copied().collect();
$(
let next_set = match self.$more_name.get($more_name) {
Some(s) => s,
None => return [<$map_name MutEntries>] {
entries: vec![].into_iter(),
hashmap: self,
},
};
intersection = intersection.intersection(next_set).copied().collect();
)*
let keys: Vec<_> = intersection.into_iter().collect();
[<$map_name MutEntries>] {
entries: keys.into_iter(),
hashmap: self,
}
}
}
};
(@generate_combos
$vis:vis $map_name:ident<$value_type:ty>,
all_fields: [$($_f:tt)*],
selected: [$($_s:tt)*],
remaining: []
) => {};
}
#[macro_export]
macro_rules! __multimap_combined_ordered_getters {
(@generate_combos
$vis:vis $map_name:ident<$value_type:ty>,
// All non-unique fields (ordered and unordered) for equality filtering
eq_fields: [$($eq_name:ident: $eq_key:ty,)*],
ordered_fields: [$next_ordered:ident: $next_ordered_key:ty, $($rest_ordered:ident: $rest_ordered_key:ty,)*]
) => {
$crate::__multimap_combined_ordered_getters!(@generate_eq_combos
$vis $map_name<$value_type>,
range_field: $next_ordered: $next_ordered_key,
selected_eq: [],
remaining_eq: [$($eq_name: $eq_key,)*]
);
$crate::__multimap_combined_ordered_getters!(@generate_combos
$vis $map_name<$value_type>,
eq_fields: [$($eq_name: $eq_key,)*],
ordered_fields: [$($rest_ordered: $rest_ordered_key,)*]
);
};
(@generate_combos
$vis:vis $map_name:ident<$value_type:ty>,
eq_fields: [$($eq_name:ident: $eq_key:ty,)*],
ordered_fields: []
) => {};
(@generate_eq_combos
$vis:vis $map_name:ident<$value_type:ty>,
range_field: $range_name:ident: $range_key:ty,
selected_eq: [$($sel_name:ident: $sel_key:ty),*],
remaining_eq: [$next_eq:ident: $next_eq_key:ty, $($rest_eq:ident: $rest_eq_key:ty,)*]
) => {
$crate::__multimap_combined_ordered_getters!(@generate_eq_combos
$vis $map_name<$value_type>,
range_field: $range_name: $range_key,
selected_eq: [$($sel_name: $sel_key),*],
remaining_eq: [$($rest_eq: $rest_eq_key,)*]
);
$crate::__multimap_combined_ordered_getters!(@generate_eq_combos
$vis $map_name<$value_type>,
range_field: $range_name: $range_key,
selected_eq: [$($sel_name: $sel_key,)* $next_eq: $next_eq_key],
remaining_eq: [$($rest_eq: $rest_eq_key,)*]
);
};
(@generate_eq_combos
$vis:vis $map_name:ident<$value_type:ty>,
range_field: $range_name:ident: $range_key:ty,
selected_eq: [$first_eq:ident: $first_eq_key:ty $(,$more_eq:ident: $more_eq_key:ty)*],
remaining_eq: []
) => {
paste! {
#[doc = "Get references to values within a key range on an ordered index, \
filtered by equality on additional indexes."]
$vis fn [<get_by_ $range_name _range_ $first_eq $( _ $more_eq)*>]<'a, R>(
&'a self,
[<$range_name range>]: R,
$first_eq: &$first_eq_key,
$($more_eq: &$more_eq_key,)*
) -> Box<dyn Iterator<Item = &'a $value_type> + 'a>
where
R: std::ops::RangeBounds<$range_key>,
{
let eq_intersection: Option<std::collections::HashSet<_>> = (|| {
let mut intersection: std::collections::HashSet<_> =
self.$first_eq.get($first_eq)?.iter().copied().collect();
$(
let next_set: std::collections::HashSet<_> =
self.$more_eq.get($more_eq)?.iter().copied().collect();
intersection = intersection.intersection(&next_set).copied().collect();
)*
Some(intersection)
})();
let eq_intersection = match eq_intersection {
Some(s) => s,
None => return Box::new(std::iter::empty()),
};
let iter = self
.$range_name
.range([<$range_name range>])
.flat_map(|(_, storage_keys)| storage_keys.iter().copied())
.filter(move |sk| eq_intersection.contains(sk))
.filter_map(|sk| self.storage.get(&sk));
Box::new(iter)
}
#[doc = "Get mutable entries within a key range on an ordered index, \
filtered by equality on additional indexes."]
$vis fn [<get_mut_by_ $range_name _range_ $first_eq $( _ $more_eq)*>]<R>(
&mut self,
[<$range_name range>]: R,
$first_eq: &$first_eq_key,
$($more_eq: &$more_eq_key,)*
) -> [<$map_name MutEntries>]<'_>
where
R: std::ops::RangeBounds<$range_key>,
{
let eq_intersection: Option<std::collections::HashSet<_>> = (|| {
let mut intersection: std::collections::HashSet<_> =
self.$first_eq.get($first_eq)?.iter().copied().collect();
$(
let next_set: std::collections::HashSet<_> =
self.$more_eq.get($more_eq)?.iter().copied().collect();
intersection = intersection.intersection(&next_set).copied().collect();
)*
Some(intersection)
})();
let eq_intersection = match eq_intersection {
Some(s) => s,
None => return [<$map_name MutEntries>] {
entries: vec![].into_iter(),
hashmap: self,
},
};
let keys: Vec<_> = self
.$range_name
.range([<$range_name range>])
.flat_map(|(_, storage_keys)| storage_keys.iter().copied())
.filter(|sk| eq_intersection.contains(sk))
.collect();
[<$map_name MutEntries>] {
entries: keys.into_iter(),
hashmap: self,
}
}
#[doc = "Get the first value by ordered index within a set of equality filters."]
$vis fn [<first_by_ $range_name _ $first_eq $( _ $more_eq)*>](
&self,
$first_eq: &$first_eq_key,
$($more_eq: &$more_eq_key,)*
) -> Option<&$value_type> {
let eq_intersection: std::collections::HashSet<_> = (|| {
let mut intersection: std::collections::HashSet<_> =
self.$first_eq.get($first_eq)?.iter().copied().collect();
$(
let next_set: std::collections::HashSet<_> =
self.$more_eq.get($more_eq)?.iter().copied().collect();
intersection = intersection.intersection(&next_set).copied().collect();
)*
Some(intersection)
})()?;
self.$range_name
.iter()
.flat_map(|(_, storage_keys)| storage_keys.iter().copied())
.find(|sk| eq_intersection.contains(sk))
.and_then(|sk| self.storage.get(&sk))
}
#[doc = "Get the last value by ordered index within a set of equality filters."]
$vis fn [<last_by_ $range_name _ $first_eq $( _ $more_eq)*>](
&self,
$first_eq: &$first_eq_key,
$($more_eq: &$more_eq_key,)*
) -> Option<&$value_type> {
let eq_intersection: std::collections::HashSet<_> = (|| {
let mut intersection: std::collections::HashSet<_> =
self.$first_eq.get($first_eq)?.iter().copied().collect();
$(
let next_set: std::collections::HashSet<_> =
self.$more_eq.get($more_eq)?.iter().copied().collect();
intersection = intersection.intersection(&next_set).copied().collect();
)*
Some(intersection)
})()?;
self.$range_name
.iter()
.rev()
.flat_map(|(_, storage_keys)| storage_keys.iter().copied())
.find(|sk| eq_intersection.contains(sk))
.and_then(|sk| self.storage.get(&sk))
}
}
};
(@generate_eq_combos
$vis:vis $map_name:ident<$value_type:ty>,
range_field: $range_name:ident: $range_key:ty,
selected_eq: [],
remaining_eq: []
) => {};
}