Skip to main content

plot/lib/job/
step3.rs

1use std::collections::BTreeMap;
2
3use crate::lib::{job, job::config::ConfigGetSetup};
4
5// ============================================================================
6// SORTER (Step 3) - UKŁADACZ ELEMENTÓW W WORKU
7// ============================================================================
8
9pub fn engine_step3_data_sort<'a>(
10	sort_cfg: &job::ValidSortByConfig,
11	item_cfg: &job::ValidColumnItemConfig,
12	table: &'a mut job::ValidResultMainTab, // ⚡ Zostawiamy referencję mutowalną!
13) -> &'a mut job::ValidResultMainTab {
14	// ⚡ Zwracamy referencję mutowalną!
15	if table.rows.is_empty() {
16		return table; // Teraz to zadziała bezbłędnie
17	}
18
19	// Wyciągamy informacje o trybie płaskim bezpośrednio z konfiguratora
20	let is_flat = match item_cfg.list {
21		job::ModeListForValidColumnItem::Flat => true,
22		job::ModeListForValidColumnItem::None => true,
23		job::ModeListForValidColumnItem::Tree => false,
24	};
25
26	// 1. Inicjalizacja ciężkiej logiki sortowania
27	let queries = sort_cfg.get();
28
29	if is_flat {
30		// --------------------------------------------------------------------
31		// JEDEN WOREK: Globalne sortowanie płaskiej listy
32		// --------------------------------------------------------------------
33		table.rows.sort_by(|a, b| queries.compare(a, b));
34	} else {
35		// --------------------------------------------------------------------
36		// WIELE WORKÓW: Sortowanie w obrębie własnych katalogów (Tree)
37		// --------------------------------------------------------------------
38		// Mapa powiązań (Klucz = ID Rodzica, Wartość = Indeksy dzieci)
39		let mut tree_map: BTreeMap<usize, Vec<usize>> = BTreeMap::new();
40
41		for (i, row) in table.rows.iter().enumerate() {
42			// Bezpośredni rodzic to ostatni element w id_path.
43			// Jeśli id_path jest puste (korzeń), przypisujemy do ID 0.
44			let parent_id = row.node.id_path.last().copied().unwrap_or(0);
45			tree_map.entry(parent_id).or_default().push(i);
46		}
47
48		// Sortujemy zawartość wewnątrz każdego worka (rodzica) z osobna!
49		for indices in tree_map.values_mut() {
50			indices.sort_by(|&a, &b| queries.compare(&table.rows[a], &table.rows[b]));
51		}
52
53		// Szukamy "Korzeni" (elementy, których rodzicem jest workspace_dir z ID 0)
54		let mut root_indices = tree_map.remove(&0).unwrap_or_default();
55
56		// Sortujemy same korzenie między sobą
57		root_indices.sort_by(|&a, &b| queries.compare(&table.rows[a], &table.rows[b]));
58
59		// Zwijamy wszystko rekurencyjnie do płaskiego wektora w idealnej kolejności
60		let mut flat_indices = Vec::with_capacity(table.rows.len());
61		flatten(&root_indices, &tree_map, &table.rows, &mut flat_indices);
62
63		// Błyskawiczna podmiana wierszy (in-place)
64		let total_rows = table.rows.len(); // Najpierw czytamy długość...
65		let old_rows = std::mem::replace(&mut table.rows, Vec::with_capacity(total_rows)); // ...potem mutujemy!
66
67		let mut temp_rows: Vec<Option<job::ValidResultMainRow>> = old_rows.into_iter().map(Some).collect();
68
69		for idx in flat_indices {
70			if let Some(row) = temp_rows[idx].take() {
71				table.rows.push(row);
72			}
73		}
74	}
75	table
76}
77
78/// Helper do rekurencyjnego opróżniania worków w ustalonej kolejności (oparty na ID) 🔙📂
79fn flatten(
80	indices: &[usize],
81	tree_map: &BTreeMap<usize, Vec<usize>>,
82	rows: &[job::ValidResultMainRow],
83	out: &mut Vec<usize>,
84) {
85	for &idx in indices {
86		out.push(idx);
87
88		let my_id = rows[idx].node.id_self; // Pobieram swoje własne ID
89
90		// Jeśli jestem rodzicem dla jakichś dzieci w mapie, wchodzimy głębiej
91		if let Some(children) = tree_map.get(&my_id) {
92			flatten(children, tree_map, rows, out);
93		}
94	}
95}