ironcalc 0.7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,330 @@
1
+ use std::cell::RefCell;
2
+
3
+ use magnus::value::StaticSymbol;
4
+ use magnus::{RArray, RString, Ruby};
5
+
6
+ use xlsx::base::types::Style;
7
+ use xlsx::base::Model as CoreModel;
8
+ use xlsx::export::{save_to_icalc, save_to_xlsx};
9
+
10
+ use crate::error::workbook_error;
11
+
12
+ /// Maps an engine `CellType` to a snake_case name, matching the names of the
13
+ /// Python binding's `CellType` enum variants. Returned to Ruby as a Symbol.
14
+ pub(crate) fn cell_type_to_str(cell_type: xlsx::base::types::CellType) -> &'static str {
15
+ use xlsx::base::types::CellType::*;
16
+ match cell_type {
17
+ Number => "number",
18
+ Text => "text",
19
+ LogicalValue => "logical_value",
20
+ ErrorValue => "error_value",
21
+ Array => "array",
22
+ CompoundData => "compound_data",
23
+ }
24
+ }
25
+
26
+ /// The raw IronCalc API. Wraps [`CoreModel`]; you must call `evaluate` yourself
27
+ /// after setting inputs.
28
+ #[magnus::wrap(class = "IronCalc::Model", free_immediately, size)]
29
+ pub struct Model {
30
+ pub model: RefCell<CoreModel<'static>>,
31
+ }
32
+
33
+ impl Model {
34
+ pub fn new(model: CoreModel<'static>) -> Self {
35
+ Model {
36
+ model: RefCell::new(model),
37
+ }
38
+ }
39
+
40
+ // Persistence -----------------------------------------------------------
41
+
42
+ pub fn save_to_xlsx(&self, file: String) -> Result<(), magnus::Error> {
43
+ save_to_xlsx(&self.model.borrow(), &file).map_err(workbook_error)
44
+ }
45
+
46
+ pub fn save_to_icalc(&self, file: String) -> Result<(), magnus::Error> {
47
+ save_to_icalc(&self.model.borrow(), &file).map_err(workbook_error)
48
+ }
49
+
50
+ pub fn to_bytes(ruby: &Ruby, rb_self: &Self) -> RString {
51
+ ruby.str_from_slice(&rb_self.model.borrow().to_bytes())
52
+ }
53
+
54
+ // Evaluation ------------------------------------------------------------
55
+
56
+ pub fn evaluate(&self) {
57
+ self.model.borrow_mut().evaluate()
58
+ }
59
+
60
+ // Set / clear values ----------------------------------------------------
61
+
62
+ pub fn set_user_input(
63
+ &self,
64
+ sheet: u32,
65
+ row: i32,
66
+ column: i32,
67
+ value: String,
68
+ ) -> Result<(), magnus::Error> {
69
+ self.model
70
+ .borrow_mut()
71
+ .set_user_input(sheet, row, column, value)
72
+ .map_err(workbook_error)
73
+ }
74
+
75
+ pub fn clear_cell_contents(
76
+ &self,
77
+ sheet: u32,
78
+ row: i32,
79
+ column: i32,
80
+ ) -> Result<(), magnus::Error> {
81
+ self.model
82
+ .borrow_mut()
83
+ .cell_clear_contents(sheet, row, column)
84
+ .map_err(workbook_error)
85
+ }
86
+
87
+ // Get values ------------------------------------------------------------
88
+
89
+ pub fn get_cell_content(
90
+ &self,
91
+ sheet: u32,
92
+ row: i32,
93
+ column: i32,
94
+ ) -> Result<String, magnus::Error> {
95
+ self.model
96
+ .borrow()
97
+ .get_localized_cell_content(sheet, row, column)
98
+ .map_err(workbook_error)
99
+ }
100
+
101
+ pub fn get_cell_type(
102
+ ruby: &Ruby,
103
+ rb_self: &Self,
104
+ sheet: u32,
105
+ row: i32,
106
+ column: i32,
107
+ ) -> Result<StaticSymbol, magnus::Error> {
108
+ rb_self
109
+ .model
110
+ .borrow()
111
+ .get_cell_type(sheet, row, column)
112
+ .map(|t| ruby.sym_new(cell_type_to_str(t)))
113
+ .map_err(workbook_error)
114
+ }
115
+
116
+ pub fn get_formatted_cell_value(
117
+ &self,
118
+ sheet: u32,
119
+ row: i32,
120
+ column: i32,
121
+ ) -> Result<String, magnus::Error> {
122
+ self.model
123
+ .borrow()
124
+ .get_formatted_cell_value(sheet, row, column)
125
+ .map_err(workbook_error)
126
+ }
127
+
128
+ // Styles (serialized as JSON; the Ruby layer exposes them as hashes) -----
129
+
130
+ pub fn set_cell_style_json(
131
+ &self,
132
+ sheet: u32,
133
+ row: i32,
134
+ column: i32,
135
+ style_json: String,
136
+ ) -> Result<(), magnus::Error> {
137
+ let style: Style = serde_json::from_str(&style_json).map_err(workbook_error)?;
138
+ self.model
139
+ .borrow_mut()
140
+ .set_cell_style(sheet, row, column, &style)
141
+ .map_err(workbook_error)
142
+ }
143
+
144
+ pub fn get_cell_style_json(
145
+ &self,
146
+ sheet: u32,
147
+ row: i32,
148
+ column: i32,
149
+ ) -> Result<String, magnus::Error> {
150
+ let style = self
151
+ .model
152
+ .borrow()
153
+ .get_style_for_cell(sheet, row, column)
154
+ .map_err(workbook_error)?;
155
+ serde_json::to_string(&style).map_err(workbook_error)
156
+ }
157
+
158
+ // Rows / columns --------------------------------------------------------
159
+
160
+ pub fn insert_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
161
+ self.model
162
+ .borrow_mut()
163
+ .insert_rows(sheet, row, row_count)
164
+ .map_err(workbook_error)
165
+ }
166
+
167
+ pub fn insert_columns(
168
+ &self,
169
+ sheet: u32,
170
+ column: i32,
171
+ column_count: i32,
172
+ ) -> Result<(), magnus::Error> {
173
+ self.model
174
+ .borrow_mut()
175
+ .insert_columns(sheet, column, column_count)
176
+ .map_err(workbook_error)
177
+ }
178
+
179
+ pub fn delete_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
180
+ self.model
181
+ .borrow_mut()
182
+ .delete_rows(sheet, row, row_count)
183
+ .map_err(workbook_error)
184
+ }
185
+
186
+ pub fn delete_columns(
187
+ &self,
188
+ sheet: u32,
189
+ column: i32,
190
+ column_count: i32,
191
+ ) -> Result<(), magnus::Error> {
192
+ self.model
193
+ .borrow_mut()
194
+ .delete_columns(sheet, column, column_count)
195
+ .map_err(workbook_error)
196
+ }
197
+
198
+ pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, magnus::Error> {
199
+ self.model
200
+ .borrow()
201
+ .get_column_width(sheet, column)
202
+ .map_err(workbook_error)
203
+ }
204
+
205
+ pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, magnus::Error> {
206
+ self.model
207
+ .borrow()
208
+ .get_row_height(sheet, row)
209
+ .map_err(workbook_error)
210
+ }
211
+
212
+ pub fn set_column_width(
213
+ &self,
214
+ sheet: u32,
215
+ column: i32,
216
+ width: f64,
217
+ ) -> Result<(), magnus::Error> {
218
+ self.model
219
+ .borrow_mut()
220
+ .set_column_width(sheet, column, width)
221
+ .map_err(workbook_error)
222
+ }
223
+
224
+ pub fn set_row_height(&self, sheet: u32, row: i32, height: f64) -> Result<(), magnus::Error> {
225
+ self.model
226
+ .borrow_mut()
227
+ .set_row_height(sheet, row, height)
228
+ .map_err(workbook_error)
229
+ }
230
+
231
+ // Frozen rows / columns -------------------------------------------------
232
+
233
+ pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
234
+ self.model
235
+ .borrow()
236
+ .get_frozen_columns_count(sheet)
237
+ .map_err(workbook_error)
238
+ }
239
+
240
+ pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
241
+ self.model
242
+ .borrow()
243
+ .get_frozen_rows_count(sheet)
244
+ .map_err(workbook_error)
245
+ }
246
+
247
+ pub fn set_frozen_columns_count(
248
+ &self,
249
+ sheet: u32,
250
+ column_count: i32,
251
+ ) -> Result<(), magnus::Error> {
252
+ self.model
253
+ .borrow_mut()
254
+ .set_frozen_columns(sheet, column_count)
255
+ .map_err(workbook_error)
256
+ }
257
+
258
+ pub fn set_frozen_rows_count(&self, sheet: u32, row_count: i32) -> Result<(), magnus::Error> {
259
+ self.model
260
+ .borrow_mut()
261
+ .set_frozen_rows(sheet, row_count)
262
+ .map_err(workbook_error)
263
+ }
264
+
265
+ // Sheets ----------------------------------------------------------------
266
+
267
+ pub fn get_worksheets_properties(ruby: &Ruby, rb_self: &Self) -> RArray {
268
+ let array = ruby.ary_new();
269
+ for sheet in rb_self.model.borrow().get_worksheets_properties() {
270
+ let hash = ruby.hash_new();
271
+ let _ = hash.aset(ruby.sym_new("name"), sheet.name);
272
+ let _ = hash.aset(ruby.sym_new("state"), sheet.state);
273
+ let _ = hash.aset(ruby.sym_new("sheet_id"), sheet.sheet_id);
274
+ let _ = hash.aset(ruby.sym_new("color"), sheet.color);
275
+ let _ = array.push(hash);
276
+ }
277
+ array
278
+ }
279
+
280
+ pub fn set_sheet_color(&self, sheet: u32, color: String) -> Result<(), magnus::Error> {
281
+ self.model
282
+ .borrow_mut()
283
+ .set_sheet_color(sheet, &color)
284
+ .map_err(workbook_error)
285
+ }
286
+
287
+ pub fn add_sheet(&self, sheet_name: String) -> Result<(), magnus::Error> {
288
+ self.model
289
+ .borrow_mut()
290
+ .add_sheet(&sheet_name)
291
+ .map_err(workbook_error)
292
+ }
293
+
294
+ pub fn new_sheet(&self) {
295
+ self.model.borrow_mut().new_sheet();
296
+ }
297
+
298
+ pub fn delete_sheet(&self, sheet: u32) -> Result<(), magnus::Error> {
299
+ self.model
300
+ .borrow_mut()
301
+ .delete_sheet(sheet)
302
+ .map_err(workbook_error)
303
+ }
304
+
305
+ pub fn rename_sheet(&self, sheet: u32, new_name: String) -> Result<(), magnus::Error> {
306
+ self.model
307
+ .borrow_mut()
308
+ .rename_sheet_by_index(sheet, &new_name)
309
+ .map_err(workbook_error)
310
+ }
311
+
312
+ /// Returns `[min_row, max_row, min_column, max_column]` for all non-empty
313
+ /// cells. An empty sheet returns `[1, 1, 1, 1]`.
314
+ pub fn get_sheet_dimensions(&self, sheet: u32) -> Result<(i32, i32, i32, i32), magnus::Error> {
315
+ let model = self.model.borrow();
316
+ let worksheet = model.workbook.worksheet(sheet).map_err(workbook_error)?;
317
+ let dimension = worksheet.dimension();
318
+ Ok((
319
+ dimension.min_row,
320
+ dimension.max_row,
321
+ dimension.min_column,
322
+ dimension.max_column,
323
+ ))
324
+ }
325
+
326
+ #[allow(clippy::panic)]
327
+ pub fn test_panic(&self) {
328
+ panic!("This function panics for testing panic handling");
329
+ }
330
+ }
@@ -0,0 +1,365 @@
1
+ use std::cell::RefCell;
2
+
3
+ use magnus::value::StaticSymbol;
4
+ use magnus::{RArray, RString, Ruby};
5
+
6
+ use xlsx::base::expressions::types::Area;
7
+ use xlsx::base::UserModel as CoreUserModel;
8
+ use xlsx::export::{save_to_icalc, save_to_xlsx};
9
+
10
+ use crate::error::workbook_error;
11
+ use crate::model::cell_type_to_str;
12
+
13
+ /// The higher-level, recommended IronCalc API. Wraps [`CoreUserModel`], which
14
+ /// **auto-evaluates after every action** and records diffs for collaboration
15
+ /// (`flush_send_queue` / `apply_external_diffs`). Prefer this over the raw
16
+ /// `Model`, which requires manual `evaluate` and can be left inconsistent.
17
+ ///
18
+ /// This mirrors the surface of IronCalc's WebAssembly binding (the engine's
19
+ /// canonical UserModel), so it is a superset of the Python binding's thinner
20
+ /// `UserModel`.
21
+ #[magnus::wrap(class = "IronCalc::UserModel", free_immediately, size)]
22
+ pub struct UserModel {
23
+ pub model: RefCell<CoreUserModel<'static>>,
24
+ }
25
+
26
+ impl UserModel {
27
+ pub fn new(model: CoreUserModel<'static>) -> Self {
28
+ UserModel {
29
+ model: RefCell::new(model),
30
+ }
31
+ }
32
+
33
+ /// A single-cell `Area`, for the range-based engine operations below.
34
+ fn cell_area(sheet: u32, row: i32, column: i32) -> Area {
35
+ Area {
36
+ sheet,
37
+ row,
38
+ column,
39
+ width: 1,
40
+ height: 1,
41
+ }
42
+ }
43
+
44
+ // Persistence -----------------------------------------------------------
45
+
46
+ pub fn save_to_xlsx(&self, file: String) -> Result<(), magnus::Error> {
47
+ let model = self.model.borrow();
48
+ save_to_xlsx(model.get_model(), &file).map_err(workbook_error)
49
+ }
50
+
51
+ pub fn save_to_icalc(&self, file: String) -> Result<(), magnus::Error> {
52
+ let model = self.model.borrow();
53
+ save_to_icalc(model.get_model(), &file).map_err(workbook_error)
54
+ }
55
+
56
+ pub fn to_bytes(ruby: &Ruby, rb_self: &Self) -> RString {
57
+ ruby.str_from_slice(&rb_self.model.borrow().to_bytes())
58
+ }
59
+
60
+ // Collaboration (diff queue) --------------------------------------------
61
+
62
+ pub fn apply_external_diffs(&self, external_diffs: RString) -> Result<(), magnus::Error> {
63
+ let bytes = unsafe { external_diffs.as_slice() }.to_vec();
64
+ self.model
65
+ .borrow_mut()
66
+ .apply_external_diffs(&bytes)
67
+ .map_err(workbook_error)
68
+ }
69
+
70
+ pub fn flush_send_queue(ruby: &Ruby, rb_self: &Self) -> RString {
71
+ let bytes = rb_self.model.borrow_mut().flush_send_queue();
72
+ ruby.str_from_slice(&bytes)
73
+ }
74
+
75
+ // Evaluation / history --------------------------------------------------
76
+
77
+ /// Usually unnecessary (the user model auto-evaluates); exposed for parity.
78
+ pub fn evaluate(&self) {
79
+ self.model.borrow_mut().evaluate();
80
+ }
81
+
82
+ pub fn undo(&self) -> Result<(), magnus::Error> {
83
+ self.model.borrow_mut().undo().map_err(workbook_error)
84
+ }
85
+
86
+ pub fn redo(&self) -> Result<(), magnus::Error> {
87
+ self.model.borrow_mut().redo().map_err(workbook_error)
88
+ }
89
+
90
+ pub fn can_undo(&self) -> bool {
91
+ self.model.borrow().can_undo()
92
+ }
93
+
94
+ pub fn can_redo(&self) -> bool {
95
+ self.model.borrow().can_redo()
96
+ }
97
+
98
+ // Set / clear values ----------------------------------------------------
99
+
100
+ pub fn set_user_input(
101
+ &self,
102
+ sheet: u32,
103
+ row: i32,
104
+ column: i32,
105
+ value: String,
106
+ ) -> Result<(), magnus::Error> {
107
+ self.model
108
+ .borrow_mut()
109
+ .set_user_input(sheet, row, column, &value)
110
+ .map_err(workbook_error)
111
+ }
112
+
113
+ pub fn clear_cell_contents(
114
+ &self,
115
+ sheet: u32,
116
+ row: i32,
117
+ column: i32,
118
+ ) -> Result<(), magnus::Error> {
119
+ self.model
120
+ .borrow_mut()
121
+ .range_clear_contents(&Self::cell_area(sheet, row, column))
122
+ .map_err(workbook_error)
123
+ }
124
+
125
+ // Get values ------------------------------------------------------------
126
+
127
+ pub fn get_cell_content(
128
+ &self,
129
+ sheet: u32,
130
+ row: i32,
131
+ column: i32,
132
+ ) -> Result<String, magnus::Error> {
133
+ self.model
134
+ .borrow()
135
+ .get_cell_content(sheet, row, column)
136
+ .map_err(workbook_error)
137
+ }
138
+
139
+ pub fn get_cell_type(
140
+ ruby: &Ruby,
141
+ rb_self: &Self,
142
+ sheet: u32,
143
+ row: i32,
144
+ column: i32,
145
+ ) -> Result<StaticSymbol, magnus::Error> {
146
+ rb_self
147
+ .model
148
+ .borrow()
149
+ .get_cell_type(sheet, row, column)
150
+ .map(|t| ruby.sym_new(cell_type_to_str(t)))
151
+ .map_err(workbook_error)
152
+ }
153
+
154
+ pub fn get_formatted_cell_value(
155
+ &self,
156
+ sheet: u32,
157
+ row: i32,
158
+ column: i32,
159
+ ) -> Result<String, magnus::Error> {
160
+ self.model
161
+ .borrow()
162
+ .get_formatted_cell_value(sheet, row, column)
163
+ .map_err(workbook_error)
164
+ }
165
+
166
+ // Styles ----------------------------------------------------------------
167
+ //
168
+ // Reads return the full style as JSON (the Ruby layer exposes it as a Hash).
169
+ // The user-model styling primitive is per-property (`update_range_style`,
170
+ // mirroring the WASM binding) rather than the whole-Style setter the raw
171
+ // `Model` exposes.
172
+
173
+ pub fn get_cell_style_json(
174
+ &self,
175
+ sheet: u32,
176
+ row: i32,
177
+ column: i32,
178
+ ) -> Result<String, magnus::Error> {
179
+ let style = self
180
+ .model
181
+ .borrow()
182
+ .get_cell_style(sheet, row, column)
183
+ .map_err(workbook_error)?;
184
+ serde_json::to_string(&style).map_err(workbook_error)
185
+ }
186
+
187
+ pub fn update_range_style(
188
+ &self,
189
+ sheet: u32,
190
+ row: i32,
191
+ column: i32,
192
+ style_path: String,
193
+ value: String,
194
+ ) -> Result<(), magnus::Error> {
195
+ self.model
196
+ .borrow_mut()
197
+ .update_range_style(&Self::cell_area(sheet, row, column), &style_path, &value)
198
+ .map_err(workbook_error)
199
+ }
200
+
201
+ // Rows / columns --------------------------------------------------------
202
+
203
+ pub fn insert_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
204
+ self.model
205
+ .borrow_mut()
206
+ .insert_rows(sheet, row, row_count)
207
+ .map_err(workbook_error)
208
+ }
209
+
210
+ pub fn insert_columns(
211
+ &self,
212
+ sheet: u32,
213
+ column: i32,
214
+ column_count: i32,
215
+ ) -> Result<(), magnus::Error> {
216
+ self.model
217
+ .borrow_mut()
218
+ .insert_columns(sheet, column, column_count)
219
+ .map_err(workbook_error)
220
+ }
221
+
222
+ pub fn delete_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
223
+ self.model
224
+ .borrow_mut()
225
+ .delete_rows(sheet, row, row_count)
226
+ .map_err(workbook_error)
227
+ }
228
+
229
+ pub fn delete_columns(
230
+ &self,
231
+ sheet: u32,
232
+ column: i32,
233
+ column_count: i32,
234
+ ) -> Result<(), magnus::Error> {
235
+ self.model
236
+ .borrow_mut()
237
+ .delete_columns(sheet, column, column_count)
238
+ .map_err(workbook_error)
239
+ }
240
+
241
+ pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, magnus::Error> {
242
+ self.model
243
+ .borrow()
244
+ .get_column_width(sheet, column)
245
+ .map_err(workbook_error)
246
+ }
247
+
248
+ pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, magnus::Error> {
249
+ self.model
250
+ .borrow()
251
+ .get_row_height(sheet, row)
252
+ .map_err(workbook_error)
253
+ }
254
+
255
+ pub fn set_column_width(
256
+ &self,
257
+ sheet: u32,
258
+ column: i32,
259
+ width: f64,
260
+ ) -> Result<(), magnus::Error> {
261
+ self.model
262
+ .borrow_mut()
263
+ .set_columns_width(sheet, column, column, width)
264
+ .map_err(workbook_error)
265
+ }
266
+
267
+ pub fn set_row_height(&self, sheet: u32, row: i32, height: f64) -> Result<(), magnus::Error> {
268
+ self.model
269
+ .borrow_mut()
270
+ .set_rows_height(sheet, row, row, height)
271
+ .map_err(workbook_error)
272
+ }
273
+
274
+ // Frozen rows / columns -------------------------------------------------
275
+
276
+ pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
277
+ self.model
278
+ .borrow()
279
+ .get_frozen_columns_count(sheet)
280
+ .map_err(workbook_error)
281
+ }
282
+
283
+ pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
284
+ self.model
285
+ .borrow()
286
+ .get_frozen_rows_count(sheet)
287
+ .map_err(workbook_error)
288
+ }
289
+
290
+ pub fn set_frozen_columns_count(
291
+ &self,
292
+ sheet: u32,
293
+ column_count: i32,
294
+ ) -> Result<(), magnus::Error> {
295
+ self.model
296
+ .borrow_mut()
297
+ .set_frozen_columns_count(sheet, column_count)
298
+ .map_err(workbook_error)
299
+ }
300
+
301
+ pub fn set_frozen_rows_count(&self, sheet: u32, row_count: i32) -> Result<(), magnus::Error> {
302
+ self.model
303
+ .borrow_mut()
304
+ .set_frozen_rows_count(sheet, row_count)
305
+ .map_err(workbook_error)
306
+ }
307
+
308
+ // Sheets ----------------------------------------------------------------
309
+
310
+ pub fn get_worksheets_properties(ruby: &Ruby, rb_self: &Self) -> RArray {
311
+ let array = ruby.ary_new();
312
+ for sheet in rb_self.model.borrow().get_worksheets_properties() {
313
+ let hash = ruby.hash_new();
314
+ let _ = hash.aset(ruby.sym_new("name"), sheet.name);
315
+ let _ = hash.aset(ruby.sym_new("state"), sheet.state);
316
+ let _ = hash.aset(ruby.sym_new("sheet_id"), sheet.sheet_id);
317
+ let _ = hash.aset(ruby.sym_new("color"), sheet.color);
318
+ let _ = array.push(hash);
319
+ }
320
+ array
321
+ }
322
+
323
+ pub fn set_sheet_color(&self, sheet: u32, color: String) -> Result<(), magnus::Error> {
324
+ self.model
325
+ .borrow_mut()
326
+ .set_sheet_color(sheet, &color)
327
+ .map_err(workbook_error)
328
+ }
329
+
330
+ pub fn new_sheet(&self) -> Result<(), magnus::Error> {
331
+ self.model.borrow_mut().new_sheet().map_err(workbook_error)
332
+ }
333
+
334
+ pub fn delete_sheet(&self, sheet: u32) -> Result<(), magnus::Error> {
335
+ self.model
336
+ .borrow_mut()
337
+ .delete_sheet(sheet)
338
+ .map_err(workbook_error)
339
+ }
340
+
341
+ pub fn rename_sheet(&self, sheet: u32, new_name: String) -> Result<(), magnus::Error> {
342
+ self.model
343
+ .borrow_mut()
344
+ .rename_sheet(sheet, &new_name)
345
+ .map_err(workbook_error)
346
+ }
347
+
348
+ /// Returns `[min_row, max_row, min_column, max_column]` for all non-empty
349
+ /// cells. An empty sheet returns `[1, 1, 1, 1]`.
350
+ pub fn get_sheet_dimensions(&self, sheet: u32) -> Result<(i32, i32, i32, i32), magnus::Error> {
351
+ let model = self.model.borrow();
352
+ let worksheet = model
353
+ .get_model()
354
+ .workbook
355
+ .worksheet(sheet)
356
+ .map_err(workbook_error)?;
357
+ let dimension = worksheet.dimension();
358
+ Ok((
359
+ dimension.min_row,
360
+ dimension.max_row,
361
+ dimension.min_column,
362
+ dimension.max_column,
363
+ ))
364
+ }
365
+ }