rosace_widgets/template/
swap.rs1use super::diff::{diff, EscalationReason, TemplateDiff};
12use super::registry;
13use super::Template;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum SwapOutcome {
18 Applied,
20 Unchanged,
22 Escalate(EscalationReason),
25 UnknownSite,
28}
29
30pub fn apply_swap(new: Template) -> SwapOutcome {
33 match registry::get(&new.key) {
34 None => SwapOutcome::UnknownSite,
35 Some(running) => match diff(&running, &new) {
36 TemplateDiff::Unchanged => SwapOutcome::Unchanged,
37 TemplateDiff::Swappable => {
38 registry::register(new);
39 SwapOutcome::Applied
40 }
41 TemplateDiff::Escalate(reason) => SwapOutcome::Escalate(reason),
42 },
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use crate::template::{registry, PropValue, StaticValue, Template, TemplateKey, TemplateNode};
50
51 fn col(key: &TemplateKey, spacing: PropValue) -> Template {
52 Template::new(key.clone(), TemplateNode::new("Column").with_prop("spacing", spacing))
53 }
54
55 trait WithProp {
57 fn with_prop(self, k: &str, v: PropValue) -> Self;
58 }
59 impl WithProp for TemplateNode {
60 fn with_prop(mut self, k: &str, v: PropValue) -> Self {
61 self.props.push((k.to_string(), v));
62 self
63 }
64 }
65
66 #[test]
67 fn safe_static_edit_is_applied_and_replaces_the_registry_entry() {
68 let key = TemplateKey::new("src/swap_a.rs", 1, 1);
69 registry::register(col(&key, PropValue::Static(StaticValue::Float(4.0))));
70
71 let edited = col(&key, PropValue::Static(StaticValue::Float(40.0)));
72 assert_eq!(apply_swap(edited), SwapOutcome::Applied);
73
74 let now = registry::get(&key).unwrap();
76 assert_eq!(now.root.props[0].1, PropValue::Static(StaticValue::Float(40.0)));
77 }
78
79 #[test]
80 fn adding_a_hole_escalates_and_leaves_the_registry_untouched() {
81 let key = TemplateKey::new("src/swap_b.rs", 2, 1);
82 registry::register(col(&key, PropValue::Static(StaticValue::Float(4.0))));
83
84 let edited = col(&key, PropValue::Hole(0));
86 assert_eq!(
87 apply_swap(edited),
88 SwapOutcome::Escalate(EscalationReason::HoleCountChanged { old: 0, new: 1 })
89 );
90 assert_eq!(
92 registry::get(&key).unwrap().root.props[0].1,
93 PropValue::Static(StaticValue::Float(4.0))
94 );
95 }
96
97 #[test]
98 fn unknown_site_is_reported() {
99 let key = TemplateKey::new("src/never_registered_swap.rs", 99, 1);
100 assert_eq!(apply_swap(col(&key, PropValue::Static(StaticValue::Float(1.0)))), SwapOutcome::UnknownSite);
101 }
102
103 #[test]
104 fn identical_edit_is_unchanged() {
105 let key = TemplateKey::new("src/swap_c.rs", 3, 1);
106 registry::register(col(&key, PropValue::Static(StaticValue::Float(4.0))));
107 assert_eq!(apply_swap(col(&key, PropValue::Static(StaticValue::Float(4.0)))), SwapOutcome::Unchanged);
108 }
109}