1use crate::doc_ng::operands::{
7 BlockUpdate, CommentUpdate, DocumentUpdate, ImageUpdate, LabelUpdate, PinUpdate,
8 RouteLabelUpdate, RouteUpdate, TextUpdate,
9};
10
11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
12pub enum StringPaths {
13 DocumentName,
14 BlockTitleName,
15 BlockTypeLabelName,
16 PinName,
17 PinTypeName,
18 PinTag,
19 RouteName,
20 TextText,
21 CommentTitleName,
22}
23
24#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
25pub enum BoolPaths {
26 BlockLocked,
27 BlockTitleHidden,
28 BlockTypeLabelHidden,
29 PinTagHidden,
30 PinFlipLR,
31 CommentTitleHidden,
32}
33
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
35pub enum FracValPaths {
36 BlockTitleOffset,
37 BlockTypeLabelOffset,
38 RouteLabelPos,
39 CommentTitleOffset,
40}
41
42#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
43pub enum LabelSidePaths {
44 BlockTitleSide,
45 BlockTypeLabelSide,
46 CommentTitleSide,
47}
48
49#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
50pub enum BlockIdPaths {
51 BlockParent,
52 PinOwner,
53 RouteOwner,
54 TextOwner,
55 CommentOwner,
56 ImageOwner,
57}
58
59#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
60pub enum RouteIdPaths {
61 RouteLabelOwner,
62}
63
64#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
65pub enum RolePaths {
66 PinPinAccent,
67 PinPortAccent,
68 PinPortPinAccent,
69 RouteRole,
70 TextRole,
71 CommentRole,
72}
73
74#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
75pub enum PinDirPaths {
76 PinDir,
77}
78
79#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
80pub enum GridRectPaths {
81 BlockRect,
82 PinRect,
83 CommentRect,
84}
85
86#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
87pub enum GridPointPaths {
88 TextPos,
89}
90
91#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
92pub enum ScreenRectPaths {
93 ImageRect,
94}
95
96#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
97pub enum IconPaths {
98 BlockIcon,
99}
100
101#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
102pub enum AssetHashPaths {
103 ImageAsset,
104}
105
106#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
107pub enum WaypointsPaths {
108 RouteWaypoints,
109}
110
111#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
114pub enum Path {
115 String(StringPaths),
116 Bool(BoolPaths),
117 FracVal(FracValPaths),
118 LabelSide(LabelSidePaths),
119 BlockId(BlockIdPaths),
120 RouteId(RouteIdPaths),
121 Role(RolePaths),
122 PinDir(PinDirPaths),
123 GridRect(GridRectPaths),
124 GridPoint(GridPointPaths),
125 ScreenRect(ScreenRectPaths),
126 Icon(IconPaths),
127 AssetHash(AssetHashPaths),
128 Waypoints(WaypointsPaths),
129}
130
131impl DocumentUpdate {
132 pub fn path(&self) -> Path {
133 match self {
134 DocumentUpdate::Name(_) => Path::String(StringPaths::DocumentName),
135 }
136 }
137}
138
139impl BlockUpdate {
140 pub fn path(&self) -> Path {
141 match self {
142 BlockUpdate::Parent(_) => Path::BlockId(BlockIdPaths::BlockParent),
143 BlockUpdate::Rect(_) => Path::GridRect(GridRectPaths::BlockRect),
144 BlockUpdate::Locked(_) => Path::Bool(BoolPaths::BlockLocked),
145 BlockUpdate::Title(label) => match label {
146 LabelUpdate::Name(_) => Path::String(StringPaths::BlockTitleName),
147 LabelUpdate::Side(_) => Path::LabelSide(LabelSidePaths::BlockTitleSide),
148 LabelUpdate::Offset(_) => Path::FracVal(FracValPaths::BlockTitleOffset),
149 LabelUpdate::Hidden(_) => Path::Bool(BoolPaths::BlockTitleHidden),
150 },
151 BlockUpdate::TypeLabel(label) => match label {
152 LabelUpdate::Name(_) => Path::String(StringPaths::BlockTypeLabelName),
153 LabelUpdate::Side(_) => Path::LabelSide(LabelSidePaths::BlockTypeLabelSide),
154 LabelUpdate::Offset(_) => Path::FracVal(FracValPaths::BlockTypeLabelOffset),
155 LabelUpdate::Hidden(_) => Path::Bool(BoolPaths::BlockTypeLabelHidden),
156 },
157 BlockUpdate::Icon(_) => Path::Icon(IconPaths::BlockIcon),
158 }
159 }
160}
161
162impl PinUpdate {
163 pub fn path(&self) -> Path {
164 match self {
165 PinUpdate::Owner(_) => Path::BlockId(BlockIdPaths::PinOwner),
166 PinUpdate::Name(_) => Path::String(StringPaths::PinName),
167 PinUpdate::TypeName(_) => Path::String(StringPaths::PinTypeName),
168 PinUpdate::Tag(_) => Path::String(StringPaths::PinTag),
169 PinUpdate::TagHidden(_) => Path::Bool(BoolPaths::PinTagHidden),
170 PinUpdate::Rect(_) => Path::GridRect(GridRectPaths::PinRect),
171 PinUpdate::Dir(_) => Path::PinDir(PinDirPaths::PinDir),
172 PinUpdate::PinAccent(_) => Path::Role(RolePaths::PinPinAccent),
173 PinUpdate::PortAccent(_) => Path::Role(RolePaths::PinPortAccent),
174 PinUpdate::PortPinAccent(_) => Path::Role(RolePaths::PinPortPinAccent),
175 PinUpdate::FlipLR(_) => Path::Bool(BoolPaths::PinFlipLR),
176 }
177 }
178}
179
180impl RouteUpdate {
181 pub fn path(&self) -> Path {
182 match self {
183 RouteUpdate::Owner(_) => Path::BlockId(BlockIdPaths::RouteOwner),
184 RouteUpdate::Name(_) => Path::String(StringPaths::RouteName),
185 RouteUpdate::Role(_) => Path::Role(RolePaths::RouteRole),
186 RouteUpdate::Waypoints(_) => Path::Waypoints(WaypointsPaths::RouteWaypoints),
187 }
188 }
189}
190
191impl RouteLabelUpdate {
192 pub fn path(&self) -> Path {
193 match self {
194 RouteLabelUpdate::Owner(_) => Path::RouteId(RouteIdPaths::RouteLabelOwner),
195 RouteLabelUpdate::Pos(_) => Path::FracVal(FracValPaths::RouteLabelPos),
196 }
197 }
198}
199
200impl TextUpdate {
201 pub fn path(&self) -> Path {
202 match self {
203 TextUpdate::Owner(_) => Path::BlockId(BlockIdPaths::TextOwner),
204 TextUpdate::Text(_) => Path::String(StringPaths::TextText),
205 TextUpdate::Pos(_) => Path::GridPoint(GridPointPaths::TextPos),
206 TextUpdate::Role(_) => Path::Role(RolePaths::TextRole),
207 }
208 }
209}
210
211impl CommentUpdate {
212 pub fn path(&self) -> Path {
213 match self {
214 CommentUpdate::Owner(_) => Path::BlockId(BlockIdPaths::CommentOwner),
215 CommentUpdate::Rect(_) => Path::GridRect(GridRectPaths::CommentRect),
216 CommentUpdate::Role(_) => Path::Role(RolePaths::CommentRole),
217 CommentUpdate::Title(label) => match label {
218 LabelUpdate::Name(_) => Path::String(StringPaths::CommentTitleName),
219 LabelUpdate::Side(_) => Path::LabelSide(LabelSidePaths::CommentTitleSide),
220 LabelUpdate::Offset(_) => Path::FracVal(FracValPaths::CommentTitleOffset),
221 LabelUpdate::Hidden(_) => Path::Bool(BoolPaths::CommentTitleHidden),
222 },
223 }
224 }
225}
226
227impl ImageUpdate {
228 pub fn path(&self) -> Path {
229 match self {
230 ImageUpdate::Owner(_) => Path::BlockId(BlockIdPaths::ImageOwner),
231 ImageUpdate::Asset(_) => Path::AssetHash(AssetHashPaths::ImageAsset),
232 ImageUpdate::Rect(_) => Path::ScreenRect(ScreenRectPaths::ImageRect),
233 }
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use crate::doc_ng::id::{BlockId, RouteId};
241 use crate::doc_ng::operands::Swap;
242 use std::collections::BTreeSet;
243
244 fn s<T: Default>() -> Swap<T> {
245 Swap {
246 old: T::default(),
247 new: T::default(),
248 }
249 }
250
251 fn s_block() -> Swap<BlockId> {
252 Swap {
253 old: BlockId::NULL,
254 new: BlockId::NULL,
255 }
256 }
257
258 fn s_route() -> Swap<RouteId> {
259 Swap {
260 old: RouteId::NULL,
261 new: RouteId::NULL,
262 }
263 }
264
265 fn label_updates() -> Vec<LabelUpdate> {
266 vec![
267 LabelUpdate::Name(s()),
268 LabelUpdate::Side(s()),
269 LabelUpdate::Offset(s()),
270 LabelUpdate::Hidden(s()),
271 ]
272 }
273
274 #[test]
278 fn the_catalog_is_one_to_one_with_the_update_vocabularies() {
279 let mut paths: Vec<Path> = Vec::new();
280
281 paths.push(DocumentUpdate::Name(s()).path());
282
283 paths.extend(
284 [
285 BlockUpdate::Parent(s_block()),
286 BlockUpdate::Rect(s()),
287 BlockUpdate::Locked(s()),
288 BlockUpdate::Icon(s()),
289 ]
290 .iter()
291 .map(BlockUpdate::path),
292 );
293 paths.extend(
294 label_updates()
295 .into_iter()
296 .map(|w| BlockUpdate::Title(w).path()),
297 );
298 paths.extend(
299 label_updates()
300 .into_iter()
301 .map(|w| BlockUpdate::TypeLabel(w).path()),
302 );
303
304 paths.extend(
305 [
306 PinUpdate::Owner(s_block()),
307 PinUpdate::Name(s()),
308 PinUpdate::TypeName(s()),
309 PinUpdate::Tag(s()),
310 PinUpdate::TagHidden(s()),
311 PinUpdate::Rect(s()),
312 PinUpdate::Dir(s()),
313 PinUpdate::PinAccent(s()),
314 PinUpdate::PortAccent(s()),
315 PinUpdate::PortPinAccent(s()),
316 PinUpdate::FlipLR(s()),
317 ]
318 .iter()
319 .map(PinUpdate::path),
320 );
321
322 paths.extend(
323 [
324 RouteUpdate::Owner(s_block()),
325 RouteUpdate::Name(s()),
326 RouteUpdate::Role(s()),
327 RouteUpdate::Waypoints(s()),
328 ]
329 .iter()
330 .map(RouteUpdate::path),
331 );
332
333 paths.extend(
334 [
335 RouteLabelUpdate::Owner(s_route()),
336 RouteLabelUpdate::Pos(s()),
337 ]
338 .iter()
339 .map(RouteLabelUpdate::path),
340 );
341
342 paths.extend(
343 [
344 TextUpdate::Owner(s_block()),
345 TextUpdate::Text(s()),
346 TextUpdate::Pos(s()),
347 TextUpdate::Role(s()),
348 ]
349 .iter()
350 .map(TextUpdate::path),
351 );
352
353 paths.extend(
354 [
355 CommentUpdate::Owner(s_block()),
356 CommentUpdate::Rect(s()),
357 CommentUpdate::Role(s()),
358 ]
359 .iter()
360 .map(CommentUpdate::path),
361 );
362 paths.extend(
363 label_updates()
364 .into_iter()
365 .map(|w| CommentUpdate::Title(w).path()),
366 );
367
368 paths.extend(
369 [
370 ImageUpdate::Owner(s_block()),
371 ImageUpdate::Asset(s()),
372 ImageUpdate::Rect(s()),
373 ]
374 .iter()
375 .map(ImageUpdate::path),
376 );
377
378 assert_eq!(paths.len(), 44, "the register catalog holds 44 registers");
379 let distinct: BTreeSet<Path> = paths.iter().copied().collect();
380 assert_eq!(
381 distinct.len(),
382 paths.len(),
383 "no two update variants may share a path"
384 );
385 }
386}