use std::any::Any;
use std::fmt;
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT_LAYER_ID: AtomicU64 = AtomicU64::new(1);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LayerId(u64);
impl LayerId {
#[inline]
pub fn next() -> Self {
Self(NEXT_LAYER_ID.fetch_add(1, Ordering::Relaxed))
}
#[inline]
pub fn as_u64(self) -> u64 {
self.0
}
}
impl fmt::Debug for LayerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LayerId({})", self.0)
}
}
impl fmt::Display for LayerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LayerKind {
Background,
Hillshade,
Tile,
Vector,
Model,
Visualization,
Custom,
}
pub trait Layer: Send + Sync {
fn id(&self) -> LayerId {
LayerId::next()
}
fn name(&self) -> &str;
fn kind(&self) -> LayerKind {
LayerKind::Custom
}
fn visible(&self) -> bool;
fn set_visible(&mut self, visible: bool);
fn opacity(&self) -> f32 {
1.0
}
fn set_opacity(&mut self, _opacity: f32) {}
fn z_index(&self) -> i32 {
0
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl fmt::Debug for dyn Layer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Layer")
.field("id", &self.id())
.field("name", &self.name())
.field("visible", &self.visible())
.field("opacity", &self.opacity())
.field("z_index", &self.z_index())
.finish()
}
}
impl fmt::Debug for dyn Layer + Send + Sync {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Layer")
.field("id", &self.id())
.field("name", &self.name())
.field("visible", &self.visible())
.field("opacity", &self.opacity())
.field("z_index", &self.z_index())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct StubLayer {
id: LayerId,
name: String,
visible: bool,
opacity: f32,
}
impl StubLayer {
fn new(name: &str) -> Self {
Self {
id: LayerId::next(),
name: name.to_owned(),
visible: true,
opacity: 1.0,
}
}
}
impl Layer for StubLayer {
fn id(&self) -> LayerId {
self.id
}
fn name(&self) -> &str {
&self.name
}
fn visible(&self) -> bool {
self.visible
}
fn set_visible(&mut self, v: bool) {
self.visible = v;
}
fn opacity(&self) -> f32 {
self.opacity
}
fn set_opacity(&mut self, o: f32) {
self.opacity = o.clamp(0.0, 1.0);
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[test]
fn layer_id_uniqueness() {
let a = LayerId::next();
let b = LayerId::next();
assert_ne!(a, b);
assert!(b.as_u64() > a.as_u64());
}
#[test]
fn layer_id_display() {
let id = LayerId::next();
let s = format!("{id}");
assert!(!s.is_empty());
assert!(s.parse::<u64>().is_ok());
}
#[test]
fn layer_id_debug() {
let id = LayerId::next();
let s = format!("{id:?}");
assert!(s.starts_with("LayerId("));
}
#[test]
fn stub_defaults() {
let layer = StubLayer::new("base");
assert_eq!(layer.name(), "base");
assert!(layer.visible());
assert!((layer.opacity() - 1.0).abs() < f32::EPSILON);
assert_eq!(layer.z_index(), 0);
}
#[test]
fn set_visibility() {
let mut layer = StubLayer::new("base");
layer.set_visible(false);
assert!(!layer.visible());
layer.set_visible(true);
assert!(layer.visible());
}
#[test]
fn opacity_clamped() {
let mut layer = StubLayer::new("base");
layer.set_opacity(1.5);
assert!((layer.opacity() - 1.0).abs() < f32::EPSILON);
layer.set_opacity(-0.5);
assert!((layer.opacity() - 0.0).abs() < f32::EPSILON);
layer.set_opacity(0.42);
assert!((layer.opacity() - 0.42).abs() < f32::EPSILON);
}
#[test]
fn downcast_works() {
let layer: Box<dyn Layer> = Box::new(StubLayer::new("down"));
assert!(layer.as_any().downcast_ref::<StubLayer>().is_some());
}
#[test]
fn downcast_mut_works() {
let mut layer: Box<dyn Layer> = Box::new(StubLayer::new("down"));
assert!(layer.as_any_mut().downcast_mut::<StubLayer>().is_some());
}
#[test]
fn trait_object_debug() {
let layer: Box<dyn Layer> = Box::new(StubLayer::new("dbg"));
let s = format!("{layer:?}");
assert!(s.contains("dbg"));
assert!(s.contains("Layer"));
}
#[test]
fn id_is_stable() {
let layer = StubLayer::new("stable");
let id1 = layer.id();
let id2 = layer.id();
assert_eq!(id1, id2);
}
}