formualizer_eval/engine/
sheet_registry.rs

1use std::collections::HashMap;
2
3use crate::SheetId;
4
5#[derive(Default, Debug)]
6pub struct SheetRegistry {
7    id_by_name: HashMap<String, SheetId>,
8    name_by_id: Vec<String>,
9}
10
11impl SheetRegistry {
12    pub fn new() -> Self {
13        SheetRegistry::default()
14    }
15
16    pub fn id_for(&mut self, name: &str) -> SheetId {
17        if let Some(&id) = self.id_by_name.get(name) {
18            return id;
19        }
20
21        let id = self.name_by_id.len() as SheetId;
22        self.name_by_id.push(name.to_string());
23        self.id_by_name.insert(name.to_string(), id);
24        id
25    }
26
27    pub fn name(&self, id: SheetId) -> &str {
28        if (id as usize) < self.name_by_id.len() {
29            &self.name_by_id[id as usize]
30        } else {
31            ""
32        }
33    }
34
35    pub fn get_id(&self, name: &str) -> Option<SheetId> {
36        self.id_by_name.get(name).copied()
37    }
38
39    /// Get all sheet IDs and names (excluding removed sheets)
40    pub fn all_sheets(&self) -> Vec<(SheetId, String)> {
41        self.name_by_id
42            .iter()
43            .enumerate()
44            .filter(|(_, name)| !name.is_empty())
45            .map(|(id, name)| (id as SheetId, name.clone()))
46            .collect()
47    }
48
49    /// Remove a sheet from the registry
50    /// Note: This doesn't actually free the ID, it just marks it as removed
51    pub fn remove(&mut self, id: SheetId) -> Result<(), formualizer_common::ExcelError> {
52        use formualizer_common::{ExcelError, ExcelErrorKind};
53
54        // Check if the ID exists
55        if id as usize >= self.name_by_id.len() {
56            return Err(
57                ExcelError::new(ExcelErrorKind::Value).with_message("Sheet ID does not exist")
58            );
59        }
60
61        // Get the name to remove from id_by_name
62        let name = self.name_by_id[id as usize].clone();
63        if name.is_empty() {
64            // Already removed
65            return Ok(());
66        }
67
68        // Remove from id_by_name mapping
69        self.id_by_name.remove(&name);
70
71        // Mark as removed in name_by_id (we can't actually remove it to preserve IDs)
72        self.name_by_id[id as usize] = String::new();
73
74        Ok(())
75    }
76
77    /// Rename a sheet
78    pub fn rename(
79        &mut self,
80        id: SheetId,
81        new_name: &str,
82    ) -> Result<(), formualizer_common::ExcelError> {
83        use formualizer_common::{ExcelError, ExcelErrorKind};
84
85        // Check if the ID exists
86        if id as usize >= self.name_by_id.len() {
87            return Err(
88                ExcelError::new(ExcelErrorKind::Value).with_message("Sheet ID does not exist")
89            );
90        }
91
92        // Get the old name
93        let old_name = self.name_by_id[id as usize].clone();
94
95        // Check if new name is already taken by another sheet
96        if let Some(&existing_id) = self.id_by_name.get(new_name) {
97            if existing_id != id {
98                return Err(ExcelError::new(ExcelErrorKind::Value)
99                    .with_message(format!("Sheet name '{new_name}' already exists")));
100            }
101        }
102
103        // Remove old name mapping
104        self.id_by_name.remove(&old_name);
105
106        // Update to new name
107        self.name_by_id[id as usize] = new_name.to_string();
108        self.id_by_name.insert(new_name.to_string(), id);
109
110        Ok(())
111    }
112}