oats_framework/
actions.rs1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use crate::{Result, Object, Trait};
5
6pub type ActionId = uuid::Uuid;
8
9#[derive(Debug, Clone)]
11pub struct ActionContext {
12 pub objects: HashMap<String, Object>,
14 pub parameters: HashMap<String, serde_json::Value>,
16 pub metadata: HashMap<String, String>,
18}
19
20impl ActionContext {
21 #[inline]
23 pub fn new() -> Self {
24 Self {
25 objects: HashMap::new(),
26 parameters: HashMap::new(),
27 metadata: HashMap::new(),
28 }
29 }
30
31 #[inline]
33 pub fn with_capacity(expected_objects: usize, expected_parameters: usize) -> Self {
34 Self {
35 objects: HashMap::with_capacity(expected_objects),
36 parameters: HashMap::with_capacity(expected_parameters),
37 metadata: HashMap::new(),
38 }
39 }
40
41 #[inline]
43 pub fn add_object(&mut self, name: impl Into<String>, object: Object) {
44 self.objects.insert(name.into(), object);
45 }
46
47 #[inline]
49 pub fn get_object(&self, name: &str) -> Option<&Object> {
50 self.objects.get(name)
51 }
52
53 #[inline]
55 pub fn get_objects(&self, names: &[&str]) -> HashMap<String, &Object> {
56 names.iter()
57 .filter_map(|name| self.objects.get(*name).map(|obj| (name.to_string(), obj)))
58 .collect()
59 }
60
61 #[inline]
63 pub fn add_parameter(&mut self, name: impl Into<String>, value: serde_json::Value) {
64 self.parameters.insert(name.into(), value);
65 }
66
67 #[inline]
69 pub fn get_parameter(&self, name: &str) -> Option<&serde_json::Value> {
70 self.parameters.get(name)
71 }
72
73 #[inline]
75 pub fn add_metadata(&mut self, key: impl Into<String>, value: impl Into<String>) {
76 self.metadata.insert(key.into(), value.into());
77 }
78
79 #[inline]
81 pub fn get_metadata(&self, key: &str) -> Option<&String> {
82 self.metadata.get(key)
83 }
84
85 #[inline]
87 pub fn object_count(&self) -> usize {
88 self.objects.len()
89 }
90
91 #[inline]
93 pub fn parameter_count(&self) -> usize {
94 self.parameters.len()
95 }
96
97 #[inline]
99 pub fn metadata_count(&self) -> usize {
100 self.metadata.len()
101 }
102
103 #[inline]
105 pub fn reserve_objects(&mut self, additional: usize) {
106 self.objects.reserve(additional);
107 }
108
109 #[inline]
111 pub fn reserve_parameters(&mut self, additional: usize) {
112 self.parameters.reserve(additional);
113 }
114
115 #[inline]
117 pub fn clear_objects(&mut self) {
118 self.objects.clear();
119 }
120
121 #[inline]
123 pub fn clear_parameters(&mut self) {
124 self.parameters.clear();
125 }
126
127 #[inline]
129 pub fn clear_metadata(&mut self) {
130 self.metadata.clear();
131 }
132}
133
134impl Default for ActionContext {
135 fn default() -> Self {
136 Self::new()
137 }
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct ActionResult {
143 pub success: bool,
145 pub trait_updates: Vec<Trait>,
147 pub messages: Vec<String>,
149 pub data: HashMap<String, serde_json::Value>,
151}
152
153impl ActionResult {
154 #[inline]
156 pub fn success() -> Self {
157 Self {
158 success: true,
159 trait_updates: Vec::new(),
160 messages: Vec::new(),
161 data: HashMap::new(),
162 }
163 }
164
165 #[inline]
167 pub fn failure(message: impl Into<String>) -> Self {
168 Self {
169 success: false,
170 trait_updates: Vec::new(),
171 messages: vec![message.into()],
172 data: HashMap::new(),
173 }
174 }
175
176 pub fn success_with_capacity(trait_capacity: usize, message_capacity: usize, data_capacity: usize) -> Self {
178 Self {
179 success: true,
180 trait_updates: Vec::with_capacity(trait_capacity),
181 messages: Vec::with_capacity(message_capacity),
182 data: HashMap::with_capacity(data_capacity),
183 }
184 }
185
186 #[inline]
188 pub fn add_trait_update(&mut self, trait_obj: Trait) {
189 self.trait_updates.push(trait_obj);
190 }
191
192 #[inline]
194 pub fn add_trait_updates(&mut self, trait_updates: impl IntoIterator<Item = Trait>) {
195 self.trait_updates.extend(trait_updates);
196 }
197
198 #[inline]
200 pub fn add_message(&mut self, message: impl Into<String>) {
201 self.messages.push(message.into());
202 }
203
204 #[inline]
206 pub fn add_messages(&mut self, messages: impl IntoIterator<Item = String>) {
207 self.messages.extend(messages);
208 }
209
210 #[inline]
212 pub fn add_data(&mut self, key: impl Into<String>, value: serde_json::Value) {
213 self.data.insert(key.into(), value);
214 }
215
216 #[inline]
218 pub fn reserve_capacity(&mut self, trait_updates: usize, messages: usize) {
219 self.trait_updates.reserve(trait_updates);
220 self.messages.reserve(messages);
221 }
222
223 #[inline]
225 pub fn is_success(&self) -> bool {
226 self.success
227 }
228
229 #[inline]
231 pub fn is_failure(&self) -> bool {
232 !self.success
233 }
234
235 #[inline]
237 pub fn trait_update_count(&self) -> usize {
238 self.trait_updates.len()
239 }
240
241 #[inline]
243 pub fn message_count(&self) -> usize {
244 self.messages.len()
245 }
246
247 #[inline]
249 pub fn data_count(&self) -> usize {
250 self.data.len()
251 }
252
253 #[inline]
255 pub fn clear_trait_updates(&mut self) {
256 self.trait_updates.clear();
257 }
258
259 #[inline]
261 pub fn clear_messages(&mut self) {
262 self.messages.clear();
263 }
264
265 #[inline]
267 pub fn clear_data(&mut self) {
268 self.data.clear();
269 }
270}
271
272#[async_trait]
274pub trait Action: Send + Sync {
275 fn name(&self) -> &str;
277
278 fn description(&self) -> &str;
280
281 async fn execute(&self, context: ActionContext) -> Result<ActionResult>;
283
284 fn required_traits(&self) -> Vec<String> {
286 Vec::new()
287 }
288
289 fn optional_traits(&self) -> Vec<String> {
291 Vec::new()
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn test_action_context() {
301 let mut context = ActionContext::new();
302 let test_object = Object::new("test", "type");
303
304 context.add_object("test_obj", test_object);
305 context.add_parameter("param", serde_json::json!("value"));
306 context.add_metadata("key", "value");
307
308 assert!(context.get_object("test_obj").is_some());
309 assert!(context.get_parameter("param").is_some());
310 assert_eq!(context.get_metadata("key"), Some(&"value".to_string()));
311 }
312
313 #[test]
314 fn test_action_result() {
315 let mut result = ActionResult::success();
316 result.add_message("Test message");
317 result.add_data("key", serde_json::json!("value"));
318
319 assert!(result.is_success());
320 assert_eq!(result.messages.len(), 1);
321 assert_eq!(result.data.len(), 1);
322 }
323}