1use anyhow::{Result, anyhow};
8use std::{
9 path::{Path, PathBuf}, sync::Arc, time::Duration,
10};
11use crate::{
12 Cell, Reference, Sheet, aim::{LockManager, Row, Rule, WorkflowLike, Workspace}, reference::parse_identifier, values::{Instance, Node, Value}, info_library::{FunctionInfoRegistry, FunctionCard}
13};
14
15pub struct Aim {}
16
17impl Aim {
18 #[doc = include_str!("../docs/api/create.md")]
28 pub fn create(path: Arc<PathBuf>) -> Result<Sheet> {
29 Workspace::create(path)
30 }
31
32 #[doc = include_str!("../docs/api/open.md")]
34 pub fn open(path: &Path) -> Result<Sheet> {
35 Workspace::open(path)
36 }
37
38 #[doc = include_str!("../docs/api/save.md")]
40 pub fn save() -> Result<()> {
41 Workspace::save()
42 }
43
44 #[doc = include_str!("../docs/api/save_all.md")]
46 pub fn save_all() -> Result<()> {
47 Workspace::save_all()
48 }
49
50 #[doc = include_str!("../docs/api/compact.md")]
52 pub fn compact() -> Result<()> {
53 Workspace::compact()
54 }
55
56 #[doc = include_str!("../docs/api/root.md")]
62 pub fn root() -> Arc<Reference> {
63 Reference::workspace()
64 }
65
66 #[doc = include_str!("../docs/api/catalog.md")]
68 pub fn catalog(locator: Arc<Reference>) -> Result<Vec<Arc<Sheet>>> {
69 if &*locator =="_" {
70 Workspace::catalog()
71 } else {
72 let node = Workspace::locate_node(&locator)?;
73 let workflow = node.get_workflow()?;
74 let mut list = Vec::new();
75 for rule in workflow.iter_rules() {
76 if let Some(node) = rule.get_node() {
78 let sheet = Sheet::convert(&node)?;
79 list.push(Arc::new(sheet));
80 }
81 }
82 Ok(list)
83 }
84 }
85
86 #[doc = include_str!("../docs/api/add.md")]
88 pub fn add(identifier: &str, parameters: &str) -> Result<Arc<Reference>> {
89 Workspace::add_node(identifier, parameters)
90 }
91
92 #[doc = include_str!("../docs/api/copy.md")]
94 pub fn copy(from: &str, to: &str) -> Result<()> {
95 Workspace::copy_node(Arc::from(from), Arc::from(to))
96 }
97
98 #[doc = include_str!("../docs/api/rename.md")]
100 pub fn rename(from: &str, to: &str) -> Result<()> {
101 Workspace::rename_node(from, Arc::from(to))
102 }
103
104 #[doc = include_str!("../docs/api/remove.md")]
110 pub fn remove(identifier: &str) -> Result<()> {
111 Workspace::remove_node(identifier)
112 }
113
114 #[doc = include_str!("../docs/api/sheet.md")]
120 pub fn sheet(locator: Arc<Reference>) -> Result<Sheet> {
121 if &*locator =="_" {
122 Workspace::sheet()
123 } else {
124 let node = Workspace::locate_node(&locator)?;
125 Sheet::convert(&node)
126 }
127 }
128
129 #[doc = include_str!("../docs/api/list.md")]
131 pub fn list(locator: Arc<Reference>) -> Result<Vec<Cell>> {
132 if &*locator == "_" {
133 let workspace = Workspace::workflow()?;
135 let mut list = Vec::new();
136 for row in workspace.iter_rows() {
137 let cell = Cell::convert_row(row);
139 list.push(cell);
140 }
141 Ok(list)
142 } else {
143 let node = Workspace::locate_node(&locator)?;
144 let workflow = node.get_workflow()?;
145 let mut list = Vec::new();
146 for row in workflow.iter_rows() {
147 let cell = Cell::convert_row(row);
149 list.push(cell);
150 }
151 Ok(list)
152 }
153 }
154
155 pub fn exists(locator: Arc<Reference>) -> Result<bool> {
156 if locator.depth() == 1 {
157 let identifier = locator.identifier();
158 Workspace::contains_node(&identifier)
159 } else {
160 let parent = locator.get_parent()?;
161 let identifier = locator.identifier();
162 Aim::contains(Arc::new(parent), &identifier)
163 }
164 }
165
166 #[doc = include_str!("../docs/api/contains.md")]
168 pub fn contains(locator: Arc<Reference>, identifier: &str) -> Result<bool> {
169 if &*locator == "_" {
170 Workspace::contains_node(identifier)
171 } else {
172 let node = Workspace::locate_node(&locator)?;
173 let workflow = node.get_workflow()?;
174 Ok(workflow.contains(identifier))
175 }
176 }
177
178 #[doc = include_str!("../docs/api/import.md")]
180 pub fn import(_locator: Arc<Reference>, _target_path: &Path) -> Result<()> {
181 todo!();
182 }
183
184 #[doc = include_str!("../docs/api/export.md")]
186 pub fn export(_locator: Arc<Reference>, _target_path: &Path) -> Result<()> {
187 todo!();
188 }
189
190 #[doc = include_str!("../docs/api/print.md")]
192 pub fn print(_locator: Arc<Reference>) -> Result<Arc<str>> {
193 todo!();
194 }
195
196 #[doc = include_str!("../docs/api/cell.md")]
202 pub fn cell(locator: Arc<Reference>, identifier: Arc<str>) -> Result<Cell> {
203 let reference = locator.add_child(identifier)?;
204 Ok(if let Some(rule) = Workspace::locate_rule(&reference)? {
205 Cell::convert_rule(&rule)
206 }
207 else {
208 Cell::Empty
209 })
210 }
211
212 #[doc = include_str!("../docs/api/acquire.md")]
218 pub fn acquire(locator: Arc<Reference>) -> Result<Arc<str>> {
219 let context_locator = Reference::context();
221 let mutex = LockManager::try_get_mutex_with_timeout(context_locator.clone(), Duration::from_secs(1))?;
223 let _lock_guard = mutex.lock()
224 .expect("Lock poisoned during acquire().");
225 let context_node = Workspace::locate_node(&context_locator)?;
227 let context_workflow = context_node.get_workflow_like()?;
229 let instance_handle: Arc<str> = locator.handle();
231 if !context_workflow.contains(&instance_handle) {
233 let mut workflow = context_node.get_workflow_mut()?;
235 workflow.add_instance(instance_handle.clone(), locator.clone(), locator.clone())?;
237 context_node.set_workflow(workflow);
238 Ok(instance_handle)
239 } else {
240 Err(anyhow!("Workflow {} already in use", locator))
241 }
242 }
243
244 #[doc = include_str!("../docs/api/snapshot.md")]
246 pub fn snapshot(handle: &str) -> Result<()> {
247 let instance = Instance::locate(handle)?;
248 let mut write_guard = instance.write()
249 .expect("Lock poisoned in snapshot() instance write.");
250 write_guard.save()
251 }
252
253 #[doc = include_str!("../docs/api/release.md")]
255 pub fn release(handle: &str) -> Result<()> {
256 Aim::snapshot(handle)?;
257
258 let context_locator = Reference::context();
261 let mutex = LockManager::try_get_mutex_with_timeout(context_locator.clone(), Duration::from_secs(1))?;
263 let _lock_guard = mutex.lock()
264 .expect("Lock poisoned during context release().");
265 let context_node = Workspace::locate_node(&context_locator)?;
267 let mut workflow = context_node.get_workflow_mut()?;
269 if let Some(index) = workflow.get_index(handle) {
270 workflow.remove_row(index);
271 context_node.set_workflow(workflow);
272 Ok(())
273 } else {
274 Err(anyhow!("Unable to release {}, missing instance", handle))
275 }
276 }
277
278 #[doc = include_str!("../docs/api/add_node.md")]
284 pub fn add_node(locator: Arc<Reference>, identifier: Arc<str>, parameters: &str) -> Result<Arc<Reference>> {
285 let node = Node::parse(parameters)?;
286 let handle = Aim::acquire(locator)?;
287 match Instance::locate(&handle) {
288 Ok(context) => {
289 let result = {
290 let mut write_guard = context.write()
291 .expect("Lock poisoned in add_node() context write.");
292 write_guard.target().add_node(identifier, node)
293 };
294 Aim::release(&handle)?;
295 result
296 }
297 Err(e) => {
298 Aim::release(&handle)?;
299 Err(e)
300 }
301 }
302 }
303
304 #[doc = include_str!("../docs/api/copy_node.md")]
306 pub fn copy_node(locator: Arc<Reference>, from: Arc<Reference>, to: Arc<str>) -> Result<()> {
307 let node = Workspace::locate_node(&from)?;
308 let handle = Aim::acquire(locator)?;
309 match Instance::locate(&handle) {
310 Ok(context) => {
311 let result = {
312 let mut write_guard = context.write()
313 .expect("Lock poisoned in copy_node() context write.");
314 write_guard.target().copy_node(&node, to)
315 };
316 Aim::release(&handle)?;
317 result
318 }
319 Err(e) => {
320 Aim::release(&handle)?;
321 Err(e)
322 }
323 }
324 }
325
326 #[doc = include_str!("../docs/api/rename_node.md")]
328 pub fn rename_node(locator: Arc<Reference>, from: &str, to: Arc<str>) -> Result<()> {
329 let handle = Aim::acquire(locator)?;
330 match Instance::locate(&handle) {
331 Ok(context) => {
332 let result = {
333 let mut write_guard = context.write()
334 .expect("Lock poisoned in rename_node() context write.");
335 write_guard.target().rename_node(from, to)
336 };
337 Aim::release(&handle)?;
338 result
339 }
340 Err(e) => {
341 Aim::release(&handle)?;
342 Err(e)
343 }
344 }
345 }
346
347 #[doc = include_str!("../docs/api/remove_node.md")]
349 pub fn remove_node(locator: Arc<Reference>, identifier: &str) -> Result<()> {
350 let handle = Aim::acquire(locator)?;
351 match Instance::locate(&handle) {
352 Ok(context) => {
353 let result = {
354 let mut write_guard = context.write()
355 .expect("Lock poisoned in remove_node() context write.");
356 write_guard.target().delete_node(identifier)
357 };
358 Aim::release(&handle)?;
359 result
360 }
361 Err(e) => {
362 Aim::release(&handle)?;
363 Err(e)
364 }
365 }
366 }
367
368 #[doc = include_str!("../docs/api/get_index.md")]
374 pub fn get_index(handle: &str, identifier: &str) -> Result<Option<usize>> {
375 let context = Instance::locate(handle)?;
376 let mut write_guard = context.write()
377 .expect("Lock poisoned in get_index() context write.");
378 Ok(write_guard.target().get_index(identifier))
379 }
380
381 #[doc = include_str!("../docs/api/get_row.md")]
383 pub fn get_row(handle: &str, index: usize) -> Result<Cell> {
384 let context = Instance::locate(handle)?;
385 let mut write_guard = context.write()
386 .expect("Lock poisoned in get_row() context write.");
387 let row = write_guard.target().get_row(index);
388 Ok(Cell::convert_row(&row))
389 }
390
391 #[doc = include_str!("../docs/api/set_row.md")]
393 pub fn set_row(handle: &str, index: usize, cell: Cell) -> Result<()> {
394 let context = Instance::locate(handle)?;
395 let mut write_guard = context.write()
396 .expect("Lock poisoned in set_row() context write.");
397 let row = Row::convert(cell);
398 write_guard.target().set_row(index, row)
399 }
400
401 #[doc = include_str!("../docs/api/insert_row.md")]
403 pub fn insert_row(handle: &str, index: usize, cell: Cell) -> Result<()> {
404 let context = Instance::locate(handle)?;
405 let mut write_guard = context.write()
406 .expect("Lock poisoned in insert_row() context write.");
407 let row = Row::convert(cell);
408 write_guard.target().insert_row(index, row)
409 }
410
411 #[doc = include_str!("../docs/api/reposition_row.md")]
413 pub fn reposition_row(handle: &str, from: usize, to: usize) -> Result<()> {
414 let context = Instance::locate(handle)?;
415 let mut write_guard = context.write()
416 .expect("Lock poisoned in reposition_row() context write.");
417 write_guard.target().reposition_row(from, to)
418 }
419
420 #[doc = include_str!("../docs/api/clear_row.md")]
422 pub fn clear_row(handle: &str, index: usize) -> Result<Cell> {
423 let context = Instance::locate(handle)?;
424 let mut write_guard = context.write()
425 .expect("Lock poisoned in clear_row() context write.");
426 let row = write_guard.target().clear_row(index);
427 Ok(Cell::convert_row(&row))
428 }
429
430 #[doc = include_str!("../docs/api/remove_row.md")]
432 pub fn remove_row(handle: &str, index: usize) -> Result<Cell> {
433 let context = Instance::locate(handle)?;
434 let mut write_guard = context.write()
435 .expect("Lock poisoned in remove_row() context write.");
436 let row = write_guard.target().remove_row(index);
437 Ok(Cell::convert_row(&row))
438 }
439
440 #[doc = include_str!("../docs/api/has_cell.md")]
446 pub fn has_cell(handle: &str, identifier: &str) -> Result<bool> {
447 let context = Instance::locate(handle)?;
448 let mut write_guard = context.write()
449 .expect("Lock poisoned in has_cell() context write.");
450 Ok(write_guard.target().contains(identifier))
451 }
452
453 #[doc = include_str!("../docs/api/get_cell.md")]
455 pub fn get_cell(handle: &str, identifier: &str) -> Result<Option<Cell>> {
456 let context = Instance::locate(handle)?;
457 let mut write_guard = context.write()
458 .expect("Lock poisoned in get_cell() context write.");
459 match write_guard.target().get_rule(identifier) {
460 Some(rule) => Ok(Some(Cell::convert_rule(&rule))),
461 _ => Ok(None),
462 }
463 }
464
465 #[doc = include_str!("../docs/api/append_or_update_cell.md")]
467 pub fn append_or_update_cell(handle: &str, cell: Cell) -> Result<()> {
468 let context = Instance::locate(handle)?;
469 let mut write_guard = context.write()
470 .expect("Lock poisoned in append_or_update_cell() context write.");
471 let row = Row::convert(cell);
472 write_guard.target().append_or_update(row);
473 Ok(())
474 }
475
476 #[doc = include_str!("../docs/api/update_cell.md")]
478 pub fn update_cell(handle: &str, identifier: Arc<str>, typedef: Arc<str>, formula: Arc<str>, value: Arc<str>) -> Result<()> {
479 let context = Instance::locate(handle)?;
480 let mut write_guard = context.write()
481 .expect("Lock poisoned in update_cell() context write.");
482 let rule = Rule::convert(identifier, typedef, formula, value);
483 write_guard.target().update_rule(Arc::new(rule))
484 }
485
486 #[doc = include_str!("../docs/api/update_cell_value.md")]
488 pub fn update_cell_value(handle: &str, identifier: Arc<str>, value: Arc<str>) -> Result<()> {
489 let context = Instance::locate(handle)?;
490 let mut write_guard = context.write()
491 .expect("Lock poisoned in update_cell_value() context write.");
492 write_guard.target().update_value(&identifier, Value::convert(value))
493 }
494
495 #[doc = include_str!("../docs/api/delete_cell.md")]
497 pub fn delete_cell(handle: &str, identifier: Arc<str>) -> Result<Cell> {
498 let context = Instance::locate(handle)?;
499 let mut write_guard = context.write()
500 .expect("Lock poisoned in delete_cell() context write.");
501 let row = write_guard.target().delete_rule(&identifier);
502 Ok(Cell::convert_row(&row))
503 }
504
505 #[doc = include_str!("../docs/api/start.md")]
511 pub fn start(_source: Arc<Reference>, _target: Option<Arc<Reference>>) -> Result<Arc<str>> {
512 todo!();
519 }
520
521 #[doc = include_str!("../docs/api/next.md")]
523 pub fn next(_handle: &str) -> Result<()> {
524 todo!("next() implementation pending");
531 }
532
533 #[doc = include_str!("../docs/api/undo.md")]
535 pub fn undo(_handle: &str) -> Result<()> {
536 todo!();
537 }
538
539 #[doc = include_str!("../docs/api/proceed.md")]
541 pub fn proceed(_handle: &str) -> Result<()> {
542 todo!();
543 }
544
545 #[doc = include_str!("../docs/api/redo.md")]
547 pub fn redo(_handle: &str) -> Result<()> {
548 todo!();
549 }
550
551 #[doc = include_str!("../docs/api/cancel.md")]
553 pub fn cancel(_handle: &str) -> Result<()> {
554 todo!();
555 }
556
557 #[doc = include_str!("../docs/api/results.md")]
559 pub fn results(locator: Arc<Reference>) -> Result<Vec<Cell>> {
560 let node = Workspace::locate_node(&locator)?;
561 let workflow = node.get_workflow()?;
562 let mut list = Vec::new();
563 for row in workflow.iter_rows() {
564 let cell = Cell::convert_result(row);
566 list.push(cell);
567 }
568 Ok(list)
569 }
570
571 pub fn check_identifier(input: &str) -> Result<()> {
576 if input.is_empty() {
577 return Err(anyhow!("Empty identifier"));
578 }
579 match parse_identifier(input) {
580 Ok((remain, identifier)) => {
581 if remain.is_empty() {
582 if identifier == "_" {
583 Err(anyhow!("Invalid identifier {}", input))
584 } else {
585 Ok(())
586 }
587 } else {
588 Err(anyhow!("Invalid identifier {}~{}", input, remain))
589 }
590 }
591 Err(e) => Err(anyhow!("Parse error: {}", e)),
592 }
593 }
594
595 pub fn function_categories() -> Result<Vec<Arc<str>>> {
605 let registry = FunctionInfoRegistry::global();
606 Ok(registry.categories().into_iter().map(Arc::from).collect())
607 }
608
609 pub fn function_list(category: &str) -> Result<Vec<Arc<str>>> {
614 let registry = FunctionInfoRegistry::global();
615 let functions = registry.by_category(category);
616 Ok(functions.into_iter()
617 .map(|card| Arc::from(card.identifier))
618 .collect())
619 }
620
621 pub fn function_card(identifier: &str) -> Result<FunctionCard> {
627 let registry = FunctionInfoRegistry::global();
628 registry.get_required(identifier)
629 .map(|card| card.clone())
630 .map_err(|e| anyhow!(e))
631 }
632
633 pub fn function_search(partial: &str) -> Result<Vec<Arc<str>>> {
639 let registry = FunctionInfoRegistry::global();
640 let results = registry.search(partial);
641 Ok(results.into_iter()
642 .map(|card| Arc::from(card.identifier))
643 .collect())
644 }
645
646 pub fn function_signatures(identifier_list: Vec<Arc<str>>) -> Result<Vec<Arc<str>>> {
651 let registry = FunctionInfoRegistry::global();
652
653 let signatures: Vec<_> = identifier_list
654 .into_iter()
655 .filter_map(|id| registry.get(&id))
656 .map(|card| Arc::from(card.signature))
657 .collect();
658
659 Ok(signatures)
660 }
661}