use kurbo::Rect;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum RasterCause {
MeshShading,
NonIsolatedGroup,
Knockout,
CompositedGroup,
SoftMask,
SampledSource,
}
impl RasterCause {
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::MeshShading => "mesh-shading",
Self::NonIsolatedGroup => "non-isolated-group",
Self::Knockout => "knockout",
Self::CompositedGroup => "composited-group",
Self::SoftMask => "soft-mask",
Self::SampledSource => "sampled-source",
}
}
#[must_use]
pub const fn is_composite(self) -> bool {
!matches!(self, Self::SampledSource)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RasterRegion {
pub bounds: Rect,
pub cause: RasterCause,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct RasterReport {
regions: Vec<RasterRegion>,
}
impl RasterReport {
#[must_use]
pub fn regions(&self) -> &[RasterRegion] {
&self.regions
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.regions.is_empty()
}
#[must_use]
pub fn counts(&self) -> Vec<(RasterCause, usize)> {
let mut out: Vec<(RasterCause, usize)> = Vec::new();
for region in &self.regions {
match out.iter_mut().find(|(cause, _)| *cause == region.cause) {
Some((_, n)) => *n += 1,
None => out.push((region.cause, 1)),
}
}
out.sort_unstable();
out
}
pub fn push(&mut self, region: RasterRegion) {
self.regions.push(region);
}
pub fn extend(&mut self, other: &Self) {
self.regions.extend_from_slice(&other.regions);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn region(cause: RasterCause) -> RasterRegion {
RasterRegion {
bounds: Rect::new(0.0, 0.0, 1.0, 1.0),
cause,
}
}
#[test]
fn an_empty_report_is_the_all_vector_answer() {
assert!(RasterReport::default().is_empty());
assert!(RasterReport::default().counts().is_empty());
}
#[test]
fn counts_group_and_sort_by_cause() {
let mut r = RasterReport::default();
r.push(region(RasterCause::SampledSource));
r.push(region(RasterCause::MeshShading));
r.push(region(RasterCause::SampledSource));
assert_eq!(
r.counts(),
vec![
(RasterCause::MeshShading, 1),
(RasterCause::SampledSource, 2)
]
);
}
#[test]
fn every_cause_has_a_distinct_name() {
let all = [
RasterCause::MeshShading,
RasterCause::NonIsolatedGroup,
RasterCause::Knockout,
RasterCause::CompositedGroup,
RasterCause::SoftMask,
RasterCause::SampledSource,
];
let mut names: Vec<_> = all.iter().map(|c| c.name()).collect();
names.sort_unstable();
names.dedup();
assert_eq!(names.len(), all.len());
}
#[test]
fn only_a_sampled_source_is_not_a_composite() {
assert!(!RasterCause::SampledSource.is_composite());
for cause in [
RasterCause::MeshShading,
RasterCause::NonIsolatedGroup,
RasterCause::Knockout,
RasterCause::CompositedGroup,
RasterCause::SoftMask,
] {
assert!(cause.is_composite(), "{}", cause.name());
}
}
}