use crate::RectToInsert;
#[cfg(not(std))]
use alloc::collections::BTreeMap as KeyValMap;
#[cfg(std)]
use std::collections::HashMap as KeyValMap;
use alloc::{
collections::{btree_map::Entry, BTreeMap},
vec::Vec,
};
use core::{fmt::Debug, hash::Hash};
#[derive(Debug)]
pub struct GroupedRectsToPlace<RectToPlaceId, GroupId = ()>
where
RectToPlaceId: Debug + Hash + Eq + Ord + PartialOrd,
GroupId: Debug + Hash + Eq + Ord + PartialOrd,
{
pub(crate) inbound_id_to_group_ids:
KeyValMap<RectToPlaceId, Vec<Group<GroupId, RectToPlaceId>>>,
pub(crate) group_id_to_inbound_ids: BTreeMap<Group<GroupId, RectToPlaceId>, Vec<RectToPlaceId>>,
pub(crate) rects: KeyValMap<RectToPlaceId, RectToInsert>,
}
#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum Group<GroupId, RectToPlaceId>
where
GroupId: Debug + Hash + Eq + PartialEq + Ord + PartialOrd,
RectToPlaceId: Debug + Ord + PartialOrd,
{
Ungrouped(RectToPlaceId),
Grouped(GroupId),
}
impl<RectToPlaceId, GroupId> GroupedRectsToPlace<RectToPlaceId, GroupId>
where
RectToPlaceId: Debug + Hash + Clone + Eq + Ord + PartialOrd,
GroupId: Debug + Hash + Clone + Eq + Ord + PartialOrd,
{
pub fn new() -> Self {
Self {
inbound_id_to_group_ids: Default::default(),
group_id_to_inbound_ids: Default::default(),
rects: Default::default(),
}
}
pub fn push_rect(
&mut self,
inbound_id: RectToPlaceId,
group_ids: Option<Vec<GroupId>>,
inbound: RectToInsert,
) {
self.rects.insert(inbound_id.clone(), inbound);
match group_ids {
None => {
self.group_id_to_inbound_ids.insert(
Group::Ungrouped(inbound_id.clone()),
vec![inbound_id.clone()],
);
self.inbound_id_to_group_ids
.insert(inbound_id.clone(), vec![Group::Ungrouped(inbound_id)]);
}
Some(group_ids) => {
self.inbound_id_to_group_ids.insert(
inbound_id.clone(),
group_ids
.clone()
.into_iter()
.map(|gid| Group::Grouped(gid))
.collect(),
);
for group_id in group_ids {
match self.group_id_to_inbound_ids.entry(Group::Grouped(group_id)) {
Entry::Occupied(mut o) => {
o.get_mut().push(inbound_id.clone());
}
Entry::Vacant(v) => {
v.insert(vec![inbound_id.clone()]);
}
};
}
}
};
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RectToInsert;
#[test]
fn ungrouped_rectangles_use_their_inbound_id_as_their_group_id() {
let mut lrg: GroupedRectsToPlace<_, ()> = GroupedRectsToPlace::new();
lrg.push_rect(RectToPlaceId::One, None, RectToInsert::new(10, 10, 1));
assert_eq!(
lrg.group_id_to_inbound_ids[&Group::Ungrouped(RectToPlaceId::One)],
vec![RectToPlaceId::One]
);
}
#[test]
fn group_id_to_inbound_ids() {
let mut lrg = GroupedRectsToPlace::new();
lrg.push_rect(
RectToPlaceId::One,
Some(vec![0]),
RectToInsert::new(10, 10, 1),
);
lrg.push_rect(
RectToPlaceId::Two,
Some(vec![0]),
RectToInsert::new(10, 10, 1),
);
assert_eq!(
lrg.group_id_to_inbound_ids.get(&Group::Grouped(0)).unwrap(),
&vec![RectToPlaceId::One, RectToPlaceId::Two]
);
}
#[test]
fn inbound_id_to_group_ids() {
let mut lrg = GroupedRectsToPlace::new();
lrg.push_rect(
RectToPlaceId::One,
Some(vec![0, 1]),
RectToInsert::new(10, 10, 1),
);
lrg.push_rect(RectToPlaceId::Two, None, RectToInsert::new(10, 10, 1));
assert_eq!(
lrg.inbound_id_to_group_ids[&RectToPlaceId::One],
vec![Group::Grouped(0), Group::Grouped(1)]
);
assert_eq!(
lrg.inbound_id_to_group_ids[&RectToPlaceId::Two],
vec![Group::Ungrouped(RectToPlaceId::Two)]
);
}
#[test]
fn store_the_inbound_rectangle() {
let mut lrg = GroupedRectsToPlace::new();
lrg.push_rect(
RectToPlaceId::One,
Some(vec![0, 1]),
RectToInsert::new(10, 10, 1),
);
assert_eq!(lrg.rects[&RectToPlaceId::One], RectToInsert::new(10, 10, 1));
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
enum RectToPlaceId {
One,
Two,
}
}