open_gpui_canvas/tool/
registry.rs1use std::{error::Error, fmt};
2
3use crate::{CanvasEvent, CanvasToolId, DocumentError};
4use indexmap::IndexMap;
5
6use super::{CanvasToolContext, CanvasToolIntent};
7
8pub trait CanvasToolReducer {
9 fn handle_event(
10 &mut self,
11 context: CanvasToolContext<'_>,
12 event: CanvasEvent,
13 ) -> Result<Vec<CanvasToolIntent>, DocumentError>;
14}
15
16impl<F> CanvasToolReducer for F
17where
18 F: for<'a> FnMut(
19 CanvasToolContext<'a>,
20 CanvasEvent,
21 ) -> Result<Vec<CanvasToolIntent>, DocumentError>,
22{
23 fn handle_event(
24 &mut self,
25 context: CanvasToolContext<'_>,
26 event: CanvasEvent,
27 ) -> Result<Vec<CanvasToolIntent>, DocumentError> {
28 self(context, event)
29 }
30}
31
32#[derive(Default)]
33pub struct CanvasToolRegistry {
34 reducers: IndexMap<CanvasToolId, Box<dyn CanvasToolReducer>>,
35}
36
37impl CanvasToolRegistry {
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn insert<T>(
43 &mut self,
44 id: impl Into<CanvasToolId>,
45 reducer: T,
46 ) -> Option<Box<dyn CanvasToolReducer>>
47 where
48 T: CanvasToolReducer + 'static,
49 {
50 self.reducers.insert(id.into(), Box::new(reducer))
51 }
52
53 pub fn insert_boxed(
54 &mut self,
55 id: impl Into<CanvasToolId>,
56 reducer: Box<dyn CanvasToolReducer>,
57 ) -> Option<Box<dyn CanvasToolReducer>> {
58 self.reducers.insert(id.into(), reducer)
59 }
60
61 pub fn remove(&mut self, id: &CanvasToolId) -> Option<Box<dyn CanvasToolReducer>> {
62 self.reducers.shift_remove(id)
63 }
64
65 pub fn contains(&self, id: &CanvasToolId) -> bool {
66 self.reducers.contains_key(id)
67 }
68
69 pub fn reducer_mut(&mut self, id: &CanvasToolId) -> Option<&mut (dyn CanvasToolReducer + '_)> {
70 let reducer = self.reducers.get_mut(id)?;
71 Some(reducer.as_mut())
72 }
73
74 pub fn ids(&self) -> impl Iterator<Item = &CanvasToolId> {
75 self.reducers.keys()
76 }
77
78 pub fn len(&self) -> usize {
79 self.reducers.len()
80 }
81
82 pub fn is_empty(&self) -> bool {
83 self.reducers.is_empty()
84 }
85}
86
87#[derive(Debug, Eq, PartialEq)]
88pub enum CanvasToolRegistryError {
89 MissingTool(CanvasToolId),
90 Document(DocumentError),
91}
92
93impl From<DocumentError> for CanvasToolRegistryError {
94 fn from(value: DocumentError) -> Self {
95 Self::Document(value)
96 }
97}
98
99impl fmt::Display for CanvasToolRegistryError {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 match self {
102 Self::MissingTool(id) => write!(f, "canvas custom tool `{id}` is not registered"),
103 Self::Document(error) => fmt::Display::fmt(error, f),
104 }
105 }
106}
107
108impl Error for CanvasToolRegistryError {
109 fn source(&self) -> Option<&(dyn Error + 'static)> {
110 match self {
111 Self::MissingTool(_) => None,
112 Self::Document(error) => Some(error),
113 }
114 }
115}