Another project
1use serde::{Deserialize, Serialize};
2
3macro_rules! icon_ids {
4 ($($variant:ident),+ $(,)?) => {
5 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
6 #[repr(u8)]
7 pub enum IconId {
8 $($variant,)+
9 }
10
11 impl IconId {
12 pub const ALL: &'static [IconId] = &[$(IconId::$variant,)+];
13
14 pub const COUNT: usize = Self::ALL.len();
15 }
16 };
17}
18
19icon_ids! {
20 Point,
21 Line,
22 CenterpointArc,
23 TangentArc,
24 ThreePointArc,
25 Circle,
26 PerimeterCircle,
27 CornerRectangle,
28 CenterRectangle,
29 ThreePointCornerRectangle,
30 ThreePointCenterRectangle,
31 Parallelogram,
32 SmartDimension,
33 Coincident,
34 Horizontal,
35 Vertical,
36 Parallel,
37 Perpendicular,
38 Tangent,
39 Equal,
40 Concentric,
41 Midpoint,
42 Symmetric,
43 Fix,
44 ExtrudedBossBase,
45 ExtrudedCut,
46 TreeFeature,
47 TreePlane,
48 TreeSketch,
49 TreeOrigin,
50 TabTree,
51 TabProperties,
52 TabConfiguration,
53 TabDimensionExpert,
54 TabDisplay,
55 ZoomToFit,
56 ZoomToArea,
57 PreviousView,
58 SectionView,
59 ViewOrientation,
60 DisplayStyle,
61 HideShowItems,
62 EditAppearance,
63 ViewSettings,
64 Check,
65 Cross,
66}
67
68#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
69pub struct IconTile(u8);
70
71impl IconTile {
72 #[must_use]
73 pub const fn index(self) -> u8 {
74 self.0
75 }
76
77 #[must_use]
78 pub fn as_usize(self) -> usize {
79 usize::from(self.0)
80 }
81}
82
83impl IconId {
84 #[must_use]
85 pub const fn tile(self) -> IconTile {
86 IconTile(self as u8)
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::IconId;
93
94 #[test]
95 fn tile_index_and_usize_agree() {
96 IconId::ALL.iter().for_each(|icon| {
97 let tile = icon.tile();
98 assert_eq!(usize::from(tile.index()), tile.as_usize());
99 });
100 }
101
102 #[test]
103 fn tile_is_injective_and_dense_over_all() {
104 let mut indices: Vec<usize> = IconId::ALL
105 .iter()
106 .map(|icon| icon.tile().as_usize())
107 .collect();
108 indices.sort_unstable();
109 assert_eq!(indices.len(), IconId::COUNT);
110 let dense = indices.iter().enumerate().all(|(i, &v)| v == i);
111 assert!(
112 dense,
113 "tile indices over ALL must be exactly 0..COUNT with no gaps or duplicates",
114 );
115 }
116
117 #[test]
118 fn all_is_ordered_by_discriminant() {
119 IconId::ALL.iter().enumerate().for_each(|(i, icon)| {
120 assert_eq!(
121 usize::from(icon.tile().index()),
122 i,
123 "ALL must list variants in discriminant order so the tile matches the slot",
124 );
125 });
126 }
127}