layer_proc_gen/
debug.rs

1//! Various helpers for viewing layers and their data without knowing the exact structure and contents
2
3use std::{any::TypeId, borrow::Borrow as _};
4
5use crate::{
6    rolling_grid::RollingGrid,
7    vec2::{Bounds, Line, Point2d},
8    Chunk, Dependencies as _, Layer,
9};
10
11/// Runtime representation of any chunk type.
12/// It is perfectly valid to not return anything if the
13/// data is not useful for debug views.
14pub trait Debug {
15    /// Render the elements of this chunk type.
16    fn debug(&self) -> Vec<DebugContent> {
17        vec![]
18    }
19}
20
21/// An debug element of a chunk
22pub enum DebugContent {
23    /// A line.
24    Line(Line),
25    /// A unfilled circle.
26    Circle {
27        /// Center position of the circle
28        center: Point2d,
29        /// Radius of the circle
30        radius: f32,
31    },
32    /// A Label.
33    Text {
34        /// Left bottom position of the first line of the text.
35        pos: Point2d,
36        /// Actual message of the text (can have newlines).
37        label: String,
38    },
39}
40
41impl From<Line> for DebugContent {
42    fn from(line: Line) -> Self {
43        Self::Line(line)
44    }
45}
46
47/// Can point to any layer and allows programatic access to dependencies and chunks.
48/// Implemented for [Layer]. You should implement this if you manually implement [Dependencies](super::Dependencies).
49pub trait DynLayer {
50    /// Iterate only over the chunks that have been generated already and not unloaded yet
51    /// to make space for new ones.
52    fn iter_all_loaded(&self) -> Box<dyn Iterator<Item = (Bounds, Box<dyn Debug + 'static>)> + '_>;
53
54    /// Iterate over the dependency layers of this layer.
55    fn deps(&self) -> Vec<&dyn DynLayer>;
56
57    /// A unique identifier for this layer, useful for the use as map keys.
58    fn ident(&self) -> (usize, TypeId);
59
60    /// A shortened version of the type name of the layer and its generic parameters.
61    fn name(&self) -> String;
62}
63
64impl<C: Chunk + Debug> DynLayer for Layer<C> {
65    fn iter_all_loaded(&self) -> Box<dyn Iterator<Item = (Bounds, Box<dyn Debug + 'static>)> + '_> {
66        Box::new(
67            self.layer
68                .borrow()
69                .0
70                .iter_all_loaded()
71                .map(|(index, chunk)| {
72                    (
73                        C::bounds(index),
74                        Box::new(chunk) as Box<dyn Debug + 'static>,
75                    )
76                }),
77        )
78    }
79
80    fn deps(&self) -> Vec<&dyn DynLayer> {
81        self.debug()
82    }
83
84    fn ident(&self) -> (usize, TypeId) {
85        let ptr: *const RollingGrid<C> = &self.layer.borrow().0;
86        (ptr as usize, TypeId::of::<Self>())
87    }
88
89    fn name(&self) -> String {
90        let mut name = std::any::type_name::<C>().to_owned();
91        let mut start = 0;
92        loop {
93            while let Some((pos, _)) = name[start..]
94                .char_indices()
95                .take_while(|&(_, c)| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | ':'))
96                .find(|&(_, c)| c == ':')
97            {
98                name.replace_range(start..(start + pos + 2), "");
99            }
100            if let Some((next, c)) = name[start..]
101                .char_indices()
102                .find(|&(_, c)| !matches!(c,  'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
103            {
104                start += next + c.len_utf8();
105            } else {
106                break;
107            }
108        }
109        name
110    }
111}