#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum LayerKind {
Map2d,
Map3d,
Graph,
Overlay,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Layer {
pub z: f32,
pub kind: LayerKind,
}
impl Layer {
pub fn new(z: f32, kind: LayerKind) -> Self {
Self { z, kind }
}
}
#[derive(Clone, Debug, Default)]
pub struct LayerStack {
layers: Vec<Layer>,
}
impl LayerStack {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, layer: Layer) -> usize {
self.layers.push(layer);
self.layers.len() - 1
}
pub fn add(&mut self, z: f32, kind: LayerKind) -> usize {
self.push(Layer::new(z, kind))
}
pub fn len(&self) -> usize {
self.layers.len()
}
pub fn is_empty(&self) -> bool {
self.layers.is_empty()
}
pub fn ordered(&self) -> Vec<Layer> {
let mut idx: Vec<usize> = (0..self.layers.len()).collect();
idx.sort_by(|&a, &b| {
self.layers[a].z.partial_cmp(&self.layers[b].z).unwrap_or(std::cmp::Ordering::Equal)
});
idx.into_iter().map(|i| self.layers[i]).collect()
}
pub fn top(&self) -> Option<Layer> {
self.ordered().last().copied()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn layer_stack_orders_back_to_front_by_z() {
let mut s = LayerStack::new();
s.add(10.0, LayerKind::Graph); s.add(0.0, LayerKind::Map3d); s.add(5.0, LayerKind::Map2d);
let order = s.ordered();
assert_eq!(order.len(), 3);
assert_eq!(order[0].kind, LayerKind::Map3d, "lowest z drawn first (underneath)");
assert_eq!(order[1].kind, LayerKind::Map2d);
assert_eq!(order[2].kind, LayerKind::Graph, "highest z composites on top");
assert_eq!(s.top().unwrap().kind, LayerKind::Graph);
}
#[test]
fn layer_stack_breaks_ties_by_insertion_order() {
let mut s = LayerStack::new();
s.add(1.0, LayerKind::Map2d);
let first = s.add(2.0, LayerKind::Overlay);
let second = s.add(2.0, LayerKind::Graph);
let _ = (first, second);
let order = s.ordered();
assert_eq!(order[0].kind, LayerKind::Map2d);
assert_eq!(order[1].kind, LayerKind::Overlay, "first-inserted of the tie paints first");
assert_eq!(order[2].kind, LayerKind::Graph);
}
#[test]
fn empty_stack_has_no_top() {
let s = LayerStack::new();
assert!(s.is_empty());
assert!(s.top().is_none());
}
}