1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub enum Framework {
14 Gradio,
15 Streamlit,
16 Panel,
17 Dash,
18}
19
20impl Framework {
21 pub fn name(&self) -> &'static str {
23 match self {
24 Framework::Gradio => "Gradio",
25 Framework::Streamlit => "Streamlit",
26 Framework::Panel => "Panel",
27 Framework::Dash => "Dash",
28 }
29 }
30
31 pub fn replacement(&self) -> &'static str {
33 match self {
34 Framework::Gradio => "Presentar",
35 Framework::Streamlit => "Presentar",
36 Framework::Panel => "Trueno-Viz",
37 Framework::Dash => "Presentar + Trueno-Viz",
38 }
39 }
40
41 pub fn all() -> Vec<Self> {
43 vec![Framework::Gradio, Framework::Streamlit, Framework::Panel, Framework::Dash]
44 }
45}
46
47impl std::fmt::Display for Framework {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "{}", self.name())
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
55pub enum IntegrationType {
56 Replaces,
58 Transpiles,
60 Compatible,
62}
63
64impl IntegrationType {
65 pub fn code(&self) -> &'static str {
67 match self {
68 IntegrationType::Replaces => "REP",
69 IntegrationType::Transpiles => "TRN",
70 IntegrationType::Compatible => "CMP",
71 }
72 }
73}
74
75impl std::fmt::Display for IntegrationType {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", self.code())
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct FrameworkComponent {
88 pub name: String,
89 pub description: String,
90 pub replacement: String,
91 pub sub_components: Vec<String>,
92}
93
94impl FrameworkComponent {
95 pub fn new(
96 name: impl Into<String>,
97 description: impl Into<String>,
98 replacement: impl Into<String>,
99 ) -> Self {
100 Self {
101 name: name.into(),
102 description: description.into(),
103 replacement: replacement.into(),
104 sub_components: Vec::new(),
105 }
106 }
107
108 pub fn with_sub(mut self, sub: impl Into<String>) -> Self {
109 self.sub_components.push(sub.into());
110 self
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct FrameworkCategory {
117 pub name: String,
118 pub components: Vec<FrameworkComponent>,
119}
120
121impl FrameworkCategory {
122 pub fn new(name: impl Into<String>) -> Self {
123 Self { name: name.into(), components: Vec::new() }
124 }
125
126 pub fn with_component(mut self, component: FrameworkComponent) -> Self {
127 self.components.push(component);
128 self
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct VizTree {
135 pub framework: Framework,
136 pub replacement: String,
137 pub categories: Vec<FrameworkCategory>,
138}
139
140impl VizTree {
141 pub fn new(framework: Framework) -> Self {
142 Self { replacement: framework.replacement().to_string(), framework, categories: Vec::new() }
143 }
144
145 pub fn add_category(mut self, category: FrameworkCategory) -> Self {
146 self.categories.push(category);
147 self
148 }
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct IntegrationMapping {
154 pub python_component: String,
155 pub paiml_component: String,
156 pub integration_type: IntegrationType,
157 pub category: String,
158}
159
160impl IntegrationMapping {
161 pub fn new(
162 python: impl Into<String>,
163 paiml: impl Into<String>,
164 int_type: IntegrationType,
165 category: impl Into<String>,
166 ) -> Self {
167 Self {
168 python_component: python.into(),
169 paiml_component: paiml.into(),
170 integration_type: int_type,
171 category: category.into(),
172 }
173 }
174}
175
176pub fn build_gradio_tree() -> VizTree {
182 VizTree::new(Framework::Gradio)
183 .add_category(
184 FrameworkCategory::new("Interface").with_component(
185 FrameworkComponent::new("Interface", "Quick demo builder", "Presentar::QuickApp")
186 .with_sub("Inputs")
187 .with_sub("Outputs")
188 .with_sub("Examples"),
189 ),
190 )
191 .add_category(
192 FrameworkCategory::new("Blocks").with_component(
193 FrameworkComponent::new("Blocks", "Custom layouts", "Presentar::Layout")
194 .with_sub("Layout")
195 .with_sub("Events")
196 .with_sub("State"),
197 ),
198 )
199 .add_category(
200 FrameworkCategory::new("Components")
201 .with_component(FrameworkComponent::new(
202 "Image",
203 "Image display/upload",
204 "Trueno-Viz::ImageView",
205 ))
206 .with_component(FrameworkComponent::new(
207 "Audio",
208 "Audio player/recorder",
209 "Presentar::AudioPlayer",
210 ))
211 .with_component(FrameworkComponent::new(
212 "Video",
213 "Video player",
214 "Presentar::VideoPlayer",
215 ))
216 .with_component(FrameworkComponent::new(
217 "Chatbot",
218 "Chat interface",
219 "Realizar + Presentar",
220 ))
221 .with_component(FrameworkComponent::new(
222 "DataFrame",
223 "Data table",
224 "Trueno-Viz::DataGrid",
225 ))
226 .with_component(FrameworkComponent::new(
227 "Plot",
228 "Chart display",
229 "Trueno-Viz::Chart",
230 )),
231 )
232 .add_category(
233 FrameworkCategory::new("Deployment").with_component(
234 FrameworkComponent::new("Deployment", "Hosting options", "Batuta deploy")
235 .with_sub("HuggingFace Spaces")
236 .with_sub("Gradio Cloud")
237 .with_sub("Self-hosted"),
238 ),
239 )
240}
241
242pub fn build_streamlit_tree() -> VizTree {
244 VizTree::new(Framework::Streamlit)
245 .add_category(
246 FrameworkCategory::new("Widgets")
247 .with_component(
248 FrameworkComponent::new("Input", "User input widgets", "Presentar::Widgets")
249 .with_sub("text_input")
250 .with_sub("number_input")
251 .with_sub("slider")
252 .with_sub("selectbox"),
253 )
254 .with_component(
255 FrameworkComponent::new("Display", "Output widgets", "Presentar + Trueno-Viz")
256 .with_sub("write")
257 .with_sub("dataframe")
258 .with_sub("chart"),
259 ),
260 )
261 .add_category(
262 FrameworkCategory::new("Layout").with_component(
263 FrameworkComponent::new("Layout", "Page structure", "Presentar::Layout")
264 .with_sub("columns")
265 .with_sub("tabs")
266 .with_sub("sidebar")
267 .with_sub("expander"),
268 ),
269 )
270 .add_category(
271 FrameworkCategory::new("Caching")
272 .with_component(FrameworkComponent::new(
273 "@st.cache_data",
274 "Data caching",
275 "Trueno::TensorCache",
276 ))
277 .with_component(FrameworkComponent::new(
278 "@st.cache_resource",
279 "Resource caching",
280 "Presentar::ResourceCache",
281 ))
282 .with_component(FrameworkComponent::new(
283 "session_state",
284 "Session state",
285 "Presentar::State",
286 )),
287 )
288 .add_category(
289 FrameworkCategory::new("Deployment").with_component(
290 FrameworkComponent::new("Deployment", "Hosting options", "Batuta deploy")
291 .with_sub("Streamlit Cloud")
292 .with_sub("Community Cloud")
293 .with_sub("Self-hosted"),
294 ),
295 )
296}
297
298pub fn build_panel_tree() -> VizTree {
300 VizTree::new(Framework::Panel)
301 .add_category(
302 FrameworkCategory::new("Panes").with_component(
303 FrameworkComponent::new("Panes", "Visualization containers", "Trueno-Viz::Chart")
304 .with_sub("Matplotlib")
305 .with_sub("Plotly")
306 .with_sub("HoloViews")
307 .with_sub("Bokeh"),
308 ),
309 )
310 .add_category(
311 FrameworkCategory::new("HoloViz Stack")
312 .with_component(FrameworkComponent::new(
313 "HoloViews",
314 "Declarative viz",
315 "Trueno-Viz::ReactiveChart",
316 ))
317 .with_component(FrameworkComponent::new(
318 "Datashader",
319 "Big data raster",
320 "Trueno-Viz::GPURaster",
321 ))
322 .with_component(FrameworkComponent::new(
323 "hvPlot",
324 "High-level plotting",
325 "Trueno-Viz::Plot",
326 ))
327 .with_component(FrameworkComponent::new(
328 "Param",
329 "Parameters",
330 "Presentar::Params",
331 )),
332 )
333 .add_category(
334 FrameworkCategory::new("Layout").with_component(
335 FrameworkComponent::new("Layout", "Dashboard structure", "Presentar::Layout")
336 .with_sub("Row")
337 .with_sub("Column")
338 .with_sub("Tabs")
339 .with_sub("GridSpec"),
340 ),
341 )
342}
343
344pub fn build_dash_tree() -> VizTree {
346 VizTree::new(Framework::Dash)
347 .add_category(
348 FrameworkCategory::new("Core")
349 .with_component(FrameworkComponent::new(
350 "dash.Dash",
351 "App container",
352 "Presentar::App",
353 ))
354 .with_component(FrameworkComponent::new(
355 "html.*",
356 "HTML components",
357 "Presentar::Html",
358 ))
359 .with_component(FrameworkComponent::new(
360 "@callback",
361 "Event handlers",
362 "Presentar::on_event",
363 ))
364 .with_component(FrameworkComponent::new(
365 "State",
366 "State management",
367 "Presentar::State",
368 )),
369 )
370 .add_category(
371 FrameworkCategory::new("Components")
372 .with_component(FrameworkComponent::new(
373 "dcc.Graph",
374 "Plotly charts",
375 "Trueno-Viz::Chart",
376 ))
377 .with_component(FrameworkComponent::new(
378 "dcc.Input",
379 "Text input",
380 "Presentar::TextInput",
381 ))
382 .with_component(FrameworkComponent::new(
383 "dash_table",
384 "Data tables",
385 "Trueno-Viz::DataGrid",
386 ))
387 .with_component(FrameworkComponent::new(
388 "dcc.Store",
389 "Client storage",
390 "Presentar::Store",
391 )),
392 )
393 .add_category(
394 FrameworkCategory::new("Plotly")
395 .with_component(
396 FrameworkComponent::new("plotly.express", "Quick charts", "Trueno-Viz::Charts")
397 .with_sub("line")
398 .with_sub("scatter")
399 .with_sub("bar")
400 .with_sub("histogram"),
401 )
402 .with_component(FrameworkComponent::new(
403 "plotly.graph_objects",
404 "Custom charts",
405 "Trueno-Viz::Figure",
406 )),
407 )
408 .add_category(
409 FrameworkCategory::new("Enterprise").with_component(
410 FrameworkComponent::new("Enterprise", "Dash Enterprise", "Batuta deploy")
411 .with_sub("Auth")
412 .with_sub("Deployment")
413 .with_sub("Snapshots"),
414 ),
415 )
416}
417
418pub fn build_integration_mappings() -> Vec<IntegrationMapping> {
424 vec![
425 IntegrationMapping::new(
427 "gr.Interface",
428 "Presentar::QuickApp",
429 IntegrationType::Replaces,
430 "UI FRAMEWORKS",
431 ),
432 IntegrationMapping::new(
433 "gr.Blocks",
434 "Presentar::Layout",
435 IntegrationType::Replaces,
436 "UI FRAMEWORKS",
437 ),
438 IntegrationMapping::new(
439 "dash.Dash",
440 "Presentar::App",
441 IntegrationType::Replaces,
442 "UI FRAMEWORKS",
443 ),
444 IntegrationMapping::new(
445 "st.columns/sidebar",
446 "Presentar::Layout",
447 IntegrationType::Replaces,
448 "UI FRAMEWORKS",
449 ),
450 IntegrationMapping::new(
452 "dcc.Graph",
453 "Trueno-Viz::Chart",
454 IntegrationType::Replaces,
455 "VISUALIZATION",
456 ),
457 IntegrationMapping::new(
458 "st.plotly_chart",
459 "Trueno-Viz::Chart",
460 IntegrationType::Replaces,
461 "VISUALIZATION",
462 ),
463 IntegrationMapping::new(
464 "st.dataframe",
465 "Trueno-Viz::DataGrid",
466 IntegrationType::Replaces,
467 "VISUALIZATION",
468 ),
469 IntegrationMapping::new(
470 "dash_table",
471 "Trueno-Viz::DataGrid",
472 IntegrationType::Replaces,
473 "VISUALIZATION",
474 ),
475 IntegrationMapping::new(
476 "datashader",
477 "Trueno-Viz::GPURaster",
478 IntegrationType::Replaces,
479 "VISUALIZATION",
480 ),
481 IntegrationMapping::new(
482 "matplotlib/plotly/bokeh",
483 "Trueno-Viz::Plot",
484 IntegrationType::Replaces,
485 "VISUALIZATION",
486 ),
487 IntegrationMapping::new(
489 "st.text_input",
490 "Presentar::TextInput",
491 IntegrationType::Replaces,
492 "COMPONENTS",
493 ),
494 IntegrationMapping::new(
495 "st.slider",
496 "Presentar::Slider",
497 IntegrationType::Replaces,
498 "COMPONENTS",
499 ),
500 IntegrationMapping::new(
501 "st.selectbox",
502 "Presentar::Select",
503 IntegrationType::Replaces,
504 "COMPONENTS",
505 ),
506 IntegrationMapping::new(
507 "st.button",
508 "Presentar::Button",
509 IntegrationType::Replaces,
510 "COMPONENTS",
511 ),
512 IntegrationMapping::new(
513 "gr.Image",
514 "Trueno-Viz::ImageView",
515 IntegrationType::Replaces,
516 "COMPONENTS",
517 ),
518 IntegrationMapping::new(
520 "st.session_state",
521 "Presentar::State",
522 IntegrationType::Replaces,
523 "STATE & CACHING",
524 ),
525 IntegrationMapping::new(
526 "@st.cache_data",
527 "Trueno::TensorCache",
528 IntegrationType::Replaces,
529 "STATE & CACHING",
530 ),
531 IntegrationMapping::new(
532 "@callback",
533 "Presentar::on_event",
534 IntegrationType::Replaces,
535 "STATE & CACHING",
536 ),
537 IntegrationMapping::new(
539 "HuggingFace Spaces",
540 "Batuta deploy",
541 IntegrationType::Replaces,
542 "DEPLOYMENT",
543 ),
544 IntegrationMapping::new(
545 "Streamlit Cloud",
546 "Batuta deploy",
547 IntegrationType::Replaces,
548 "DEPLOYMENT",
549 ),
550 IntegrationMapping::new(
551 "Dash Enterprise",
552 "Batuta deploy",
553 IntegrationType::Replaces,
554 "DEPLOYMENT",
555 ),
556 ]
557}
558
559pub fn format_framework_tree(tree: &VizTree) -> String {
565 let mut output = String::new();
566 output.push_str(&format!(
567 "{} (Python) → {} (Rust)\n",
568 tree.framework.name().to_uppercase(),
569 tree.replacement
570 ));
571
572 let cat_count = tree.categories.len();
573 for (i, category) in tree.categories.iter().enumerate() {
574 let is_last_cat = i == cat_count - 1;
575 let cat_prefix = if is_last_cat { "└──" } else { "├──" };
576 let cat_cont = if is_last_cat { " " } else { "│ " };
577
578 output.push_str(&format!("{} {}\n", cat_prefix, category.name));
579
580 let comp_count = category.components.len();
581 for (j, component) in category.components.iter().enumerate() {
582 let is_last_comp = j == comp_count - 1;
583 let comp_prefix = if is_last_comp { "└──" } else { "├──" };
584 let comp_cont = if is_last_comp { " " } else { "│ " };
585
586 output.push_str(&format!(
587 "{}{} {} → {}\n",
588 cat_cont, comp_prefix, component.name, component.replacement
589 ));
590
591 let sub_count = component.sub_components.len();
593 for (k, sub) in component.sub_components.iter().enumerate() {
594 let is_last_sub = k == sub_count - 1;
595 let sub_prefix = if is_last_sub { "└──" } else { "├──" };
596 output.push_str(&format!("{}{}{} {}\n", cat_cont, comp_cont, sub_prefix, sub));
597 }
598 }
599 }
600
601 output
602}
603
604pub fn format_all_frameworks() -> String {
606 let mut output = String::new();
607 output.push_str("VISUALIZATION FRAMEWORKS ECOSYSTEM\n");
608 output.push_str("==================================\n\n");
609
610 let trees =
611 vec![build_gradio_tree(), build_streamlit_tree(), build_panel_tree(), build_dash_tree()];
612
613 for tree in &trees {
614 output.push_str(&format_framework_tree(tree));
615 output.push('\n');
616 }
617
618 output.push_str(&format!(
619 "Summary: {} Python frameworks replaced by 2 Rust libraries (Presentar, Trueno-Viz)\n",
620 trees.len()
621 ));
622
623 output
624}
625
626pub fn format_integration_mappings() -> String {
628 let mut output = String::new();
629 output.push_str("PAIML REPLACEMENTS FOR PYTHON VIZ\n");
630 output.push_str("=================================\n\n");
631
632 let mappings = build_integration_mappings();
633 let mut current_category = String::new();
634
635 for mapping in &mappings {
636 if mapping.category != current_category {
637 if !current_category.is_empty() {
638 output.push('\n');
639 }
640 output.push_str(&format!("{}\n", mapping.category));
641 current_category = mapping.category.clone();
642 }
643
644 output.push_str(&format!(
645 "├── [{}] {} ← {}\n",
646 mapping.integration_type.code(),
647 mapping.paiml_component,
648 mapping.python_component
649 ));
650 }
651
652 output.push_str("\nLegend: [REP]=Replaces (Python eliminated)\n");
653 output.push_str("\nSummary: ");
654
655 let rep_count =
656 mappings.iter().filter(|m| m.integration_type == IntegrationType::Replaces).count();
657
658 output.push_str(&format!(
659 "{} Python components replaced by sovereign Rust alternatives\n",
660 rep_count
661 ));
662 output.push_str(" Zero Python dependencies in production\n");
663
664 output
665}
666
667#[cfg(test)]
672#[allow(non_snake_case)]
673mod tests {
674 use super::*;
675
676 #[test]
681 fn test_VIZ_TREE_001_framework_names() {
682 assert_eq!(Framework::Gradio.name(), "Gradio");
683 assert_eq!(Framework::Streamlit.name(), "Streamlit");
684 assert_eq!(Framework::Panel.name(), "Panel");
685 assert_eq!(Framework::Dash.name(), "Dash");
686 }
687
688 #[test]
689 fn test_VIZ_TREE_001_framework_replacements() {
690 assert_eq!(Framework::Gradio.replacement(), "Presentar");
691 assert_eq!(Framework::Streamlit.replacement(), "Presentar");
692 assert_eq!(Framework::Panel.replacement(), "Trueno-Viz");
693 assert_eq!(Framework::Dash.replacement(), "Presentar + Trueno-Viz");
694 }
695
696 #[test]
697 fn test_VIZ_TREE_001_framework_all() {
698 let all = Framework::all();
699 assert_eq!(all.len(), 4);
700 }
701
702 #[test]
703 fn test_VIZ_TREE_001_framework_display() {
704 assert_eq!(format!("{}", Framework::Gradio), "Gradio");
705 }
706
707 #[test]
712 fn test_VIZ_TREE_002_integration_codes() {
713 assert_eq!(IntegrationType::Replaces.code(), "REP");
714 assert_eq!(IntegrationType::Transpiles.code(), "TRN");
715 assert_eq!(IntegrationType::Compatible.code(), "CMP");
716 }
717
718 #[test]
719 fn test_VIZ_TREE_002_integration_display() {
720 assert_eq!(format!("{}", IntegrationType::Replaces), "REP");
721 }
722
723 #[test]
728 fn test_VIZ_TREE_003_gradio_tree() {
729 let tree = build_gradio_tree();
730 assert_eq!(tree.framework, Framework::Gradio);
731 assert_eq!(tree.replacement, "Presentar");
732 assert!(!tree.categories.is_empty());
733 }
734
735 #[test]
736 fn test_VIZ_TREE_003_streamlit_tree() {
737 let tree = build_streamlit_tree();
738 assert_eq!(tree.framework, Framework::Streamlit);
739 assert_eq!(tree.replacement, "Presentar");
740 assert!(!tree.categories.is_empty());
741 }
742
743 #[test]
744 fn test_VIZ_TREE_003_panel_tree() {
745 let tree = build_panel_tree();
746 assert_eq!(tree.framework, Framework::Panel);
747 assert_eq!(tree.replacement, "Trueno-Viz");
748 assert!(!tree.categories.is_empty());
749 }
750
751 #[test]
752 fn test_VIZ_TREE_003_dash_tree() {
753 let tree = build_dash_tree();
754 assert_eq!(tree.framework, Framework::Dash);
755 assert_eq!(tree.replacement, "Presentar + Trueno-Viz");
756 assert!(!tree.categories.is_empty());
757 }
758
759 #[test]
764 fn test_VIZ_TREE_004_mappings_exist() {
765 let mappings = build_integration_mappings();
766 assert!(!mappings.is_empty());
767 assert!(mappings.len() >= 20);
768 }
769
770 #[test]
771 fn test_VIZ_TREE_004_all_replaces() {
772 let mappings = build_integration_mappings();
773 for mapping in &mappings {
775 assert_eq!(
776 mapping.integration_type,
777 IntegrationType::Replaces,
778 "Mapping {} should be Replaces",
779 mapping.python_component
780 );
781 }
782 }
783
784 #[test]
785 fn test_VIZ_TREE_004_mapping_categories() {
786 let mappings = build_integration_mappings();
787 let categories: std::collections::HashSet<_> =
788 mappings.iter().map(|m| m.category.as_str()).collect();
789 assert!(categories.contains("UI FRAMEWORKS"));
790 assert!(categories.contains("VISUALIZATION"));
791 assert!(categories.contains("COMPONENTS"));
792 assert!(categories.contains("DEPLOYMENT"));
793 }
794
795 #[test]
800 fn test_VIZ_TREE_005_format_framework_tree() {
801 let tree = build_gradio_tree();
802 let output = format_framework_tree(&tree);
803 assert!(output.contains("GRADIO"));
804 assert!(output.contains("Presentar"));
805 assert!(output.contains("Interface"));
806 }
807
808 #[test]
809 fn test_VIZ_TREE_005_format_all_frameworks() {
810 let output = format_all_frameworks();
811 assert!(output.contains("VISUALIZATION FRAMEWORKS ECOSYSTEM"));
812 assert!(output.contains("GRADIO"));
813 assert!(output.contains("STREAMLIT"));
814 assert!(output.contains("PANEL"));
815 assert!(output.contains("DASH"));
816 assert!(output.contains("Summary:"));
817 }
818
819 #[test]
820 fn test_VIZ_TREE_005_format_integration_mappings() {
821 let output = format_integration_mappings();
822 assert!(output.contains("PAIML REPLACEMENTS"));
823 assert!(output.contains("[REP]"));
824 assert!(output.contains("Presentar"));
825 assert!(output.contains("Trueno-Viz"));
826 assert!(output.contains("Legend:"));
827 }
828
829 #[test]
834 fn test_VIZ_TREE_006_framework_component() {
835 let component = FrameworkComponent::new("Test", "Description", "Replacement")
836 .with_sub("Sub1")
837 .with_sub("Sub2");
838 assert_eq!(component.name, "Test");
839 assert_eq!(component.sub_components.len(), 2);
840 }
841
842 #[test]
843 fn test_VIZ_TREE_006_framework_category() {
844 let category = FrameworkCategory::new("Test Category")
845 .with_component(FrameworkComponent::new("Comp1", "Desc1", "Rep1"));
846 assert_eq!(category.name, "Test Category");
847 assert_eq!(category.components.len(), 1);
848 }
849
850 #[test]
851 fn test_VIZ_TREE_006_integration_mapping() {
852 let mapping =
853 IntegrationMapping::new("Python", "Rust", IntegrationType::Replaces, "Category");
854 assert_eq!(mapping.python_component, "Python");
855 assert_eq!(mapping.paiml_component, "Rust");
856 }
857
858 #[test]
863 fn test_VIZ_TREE_007_framework_equality() {
864 assert_eq!(Framework::Gradio, Framework::Gradio);
865 assert_ne!(Framework::Gradio, Framework::Streamlit);
866 }
867
868 #[test]
869 fn test_VIZ_TREE_007_framework_clone() {
870 let f1 = Framework::Panel;
871 let f2 = f1;
872 assert_eq!(f1, f2);
873 }
874
875 #[test]
876 fn test_VIZ_TREE_007_integration_type_equality() {
877 assert_eq!(IntegrationType::Replaces, IntegrationType::Replaces);
878 assert_ne!(IntegrationType::Replaces, IntegrationType::Transpiles);
879 }
880
881 #[test]
882 fn test_VIZ_TREE_007_integration_type_clone() {
883 let t1 = IntegrationType::Compatible;
884 let t2 = t1;
885 assert_eq!(t1, t2);
886 }
887
888 #[test]
889 fn test_VIZ_TREE_007_framework_serialization() {
890 let framework = Framework::Dash;
891 let json = serde_json::to_string(&framework).expect("json serialize failed");
892 let parsed: Framework = serde_json::from_str(&json).expect("json deserialize failed");
893 assert_eq!(framework, parsed);
894 }
895
896 #[test]
897 fn test_VIZ_TREE_007_integration_type_serialization() {
898 let integration = IntegrationType::Transpiles;
899 let json = serde_json::to_string(&integration).expect("json serialize failed");
900 let parsed: IntegrationType = serde_json::from_str(&json).expect("json deserialize failed");
901 assert_eq!(integration, parsed);
902 }
903
904 #[test]
905 fn test_VIZ_TREE_007_framework_component_serialization() {
906 let component = FrameworkComponent::new("Test", "Desc", "Rep");
907 let json = serde_json::to_string(&component).expect("json serialize failed");
908 let parsed: FrameworkComponent =
909 serde_json::from_str(&json).expect("json deserialize failed");
910 assert_eq!(component.name, parsed.name);
911 }
912
913 #[test]
914 fn test_VIZ_TREE_007_framework_tree_categories() {
915 let tree = build_gradio_tree();
916 assert!(tree.categories.len() > 1);
918 for category in &tree.categories {
920 assert!(!category.components.is_empty());
921 }
922 }
923
924 #[test]
925 fn test_VIZ_TREE_007_framework_debug() {
926 let f = Framework::Gradio;
927 let debug = format!("{:?}", f);
928 assert!(debug.contains("Gradio"));
929 }
930
931 #[test]
932 fn test_VIZ_TREE_007_integration_type_debug() {
933 let t = IntegrationType::Replaces;
934 let debug = format!("{:?}", t);
935 assert!(debug.contains("Replaces"));
936 }
937}