grove/Common/
traits.rs

1//! Shared Traits Module
2//!
3//! Defines common traits used across the Grove codebase.
4
5use std::fmt;
6
7use serde::{Deserialize, Serialize};
8
9/// Extension context trait for providing extension-specific information
10pub trait ExtensionContext: Send + Sync {
11	/// Get the extension ID
12	fn extension_id(&self) -> &str;
13
14	/// Get the extension version
15	fn version(&self) -> &str;
16
17	/// Get the extension publisher
18	fn publisher(&self) -> &str;
19
20	/// Get the extension display name
21	fn display_name(&self) -> &str;
22
23	/// Get the extension description
24	fn description(&self) -> &str;
25
26	/// Check if the extension is in development mode
27	fn is_development(&self) -> bool;
28}
29
30/// Extension metadata trait for package.json information
31pub trait ExtensionMetadata: Send + Sync {
32	/// Get the extension name
33	fn name(&self) -> &str;
34
35	/// Get the extension publisher
36	fn publisher(&self) -> &str;
37
38	/// Get the extension version
39	fn version(&self) -> &str;
40
41	/// Get the extension description
42	fn description(&self) -> &str;
43
44	/// Get the main entry point
45	fn main(&self) -> &str;
46
47	/// Get activation events
48	fn activation_events(&self) -> &[String];
49
50	/// Get extension capabilities
51	fn capabilities(&self) -> &[String];
52
53	/// Get extension dependencies
54	fn dependencies(&self) -> &[String];
55
56	/// Get the engine compatibility
57	fn engine(&self) -> &str;
58}
59
60/// Result type for Grove operations
61pub type GroveResult<T> = Result<T, GroveError>;
62
63/// Grove error type
64#[derive(Debug, thiserror::Error)]
65pub enum GroveError {
66	/// Extension not found
67	#[error("Extension not found: {0}")]
68	ExtensionNotFound(String),
69
70	/// Extension activation failed
71	#[error("Extension activation failed: {0}")]
72	ActivationFailed(String),
73
74	/// Extension deactivation failed
75	#[error("Extension deactivation failed: {0}")]
76	DeactivationFailed(String),
77
78	/// Transport error
79	#[error("Transport error: {0}")]
80	TransportError(String),
81
82	/// WASM runtime error
83	#[error("WASM runtime error: {0}")]
84	WASMError(String),
85
86	/// API error
87	#[error("API error: {0}")]
88	APIError(String),
89
90	/// Configuration error
91	#[error("Configuration error: {0}")]
92	ConfigurationError(String),
93
94	/// I/O error
95	#[error("I/O error: {0}")]
96	IoError(#[from] std::io::Error),
97
98	/// Serialization error
99	#[error("Serialization error: {0}")]
100	SerializationError(String),
101
102	/// Deserialization error
103	#[error("Deserialization error: {0}")]
104	DeserializationError(String),
105
106	/// Timeout error
107	#[error("Operation timed out")]
108	Timeout,
109
110	/// Invalid argument
111	#[error("Invalid argument: {0}")]
112	InvalidArgument(String),
113
114	/// Not implemented
115	#[error("Not implemented: {0}")]
116	NotImplemented(String),
117
118	/// Generic error
119	#[error("{0}")]
120	Other(String),
121}
122
123
124/// Identifiable trait for objects with unique IDs
125pub trait Identifiable {
126	/// Get the unique identifier
127	fn id(&self) -> &str;
128}
129
130/// Named trait for objects with names
131pub trait Named {
132	/// Get the name
133	fn name(&self) -> &str;
134}
135
136/// Configurable trait for objects with configuration
137pub trait Configurable {
138	/// Configuration type
139	type Config;
140
141	/// Configure the object
142	fn configure(&mut self, config:Self::Config) -> anyhow::Result<()>;
143
144	/// Get current configuration
145	fn config(&self) -> &Self::Config;
146}
147
148/// Resettable trait for objects that can be reset
149pub trait Resettable {
150	/// Reset the object to its initial state
151	fn reset(&mut self) -> anyhow::Result<()>;
152}
153
154/// Disposable trait for objects with cleanup
155pub trait Disposable {
156	/// Dispose and cleanup resources
157	fn dispose(&mut self) -> anyhow::Result<()>;
158}
159
160/// Cloneable trait for objects that can be cloned with context
161pub trait ContextClone {
162	/// Clone the object with additional context
163	fn clone_with_context(&self, context:&serde_json::Value) -> anyhow::Result<Self>
164	where
165		Self: Sized;
166}
167
168/// Stateful trait for objects with state
169pub trait Stateful {
170	/// State type
171	type State: Clone;
172
173	/// Get current state
174	fn state(&self) -> Self::State;
175
176	/// Set state
177	fn set_state(&mut self, state:Self::State) -> anyhow::Result<()>;
178
179	/// Restore state
180	fn restore_state(&mut self, state:Self::State) -> anyhow::Result<()>;
181}
182
183/// Observable trait for objects that can emit events
184pub trait Observable {
185	/// Event type
186	type Event;
187
188	/// Subscribe to events
189	fn subscribe(&self, callback:fn(Self::Event)) -> anyhow::Result<()>;
190
191	/// Unsubscribe from events
192	fn unsubscribe(&self) -> anyhow::Result<()>;
193}
194
195/// Validation trait for objects that can be validated
196pub trait Validatable {
197	/// Validate the object
198	fn validate(&self) -> anyhow::Result<()>;
199}
200
201/// Serializable trait for objects that can be serialized
202pub trait Serializable: Serialize + for<'de> Deserialize<'de> {
203	/// Serialize to JSON string
204	fn to_json(&self) -> anyhow::Result<String> {
205		serde_json::to_string(self).map_err(|e| anyhow::anyhow!("Serialization failed: {}", e))
206	}
207
208	/// Serialize to JSON pretty string
209	fn to_json_pretty(&self) -> anyhow::Result<String> {
210		serde_json::to_string_pretty(self).map_err(|e| anyhow::anyhow!("Serialization failed: {}", e))
211	}
212
213	/// Deserialize from JSON string
214	fn from_json(json:&str) -> anyhow::Result<Self>
215	where
216		Self: Sized, {
217		serde_json::from_str(json).map_err(|e| anyhow::anyhow!("Deserialization failed: {}", e))
218	}
219}
220
221/// Extend Serializable for serializable types
222impl<T> Serializable for T where T: Serialize + for<'de> Deserialize<'de> {}
223
224/// Versioned trait for objects with version information
225pub trait Versioned {
226	/// Get version
227	fn version(&self) -> &str;
228
229	/// Check compatibility with another version
230	fn is_compatible_with(&self, other_version:&str) -> bool;
231}
232
233/// Retryable trait for operations that can be retried
234pub trait Retryable {
235	/// Execute with retry
236	fn execute_with_retry<F, T, E>(&self, mut operation:F, max_retries:u32, delay_ms:u64) -> anyhow::Result<T>
237	where
238		F: FnMut() -> Result<T, E> + Send,
239		E: std::fmt::Display + Send + 'static,
240		T: Send, {
241		let mut last_error = None;
242
243		for attempt in 0..=max_retries {
244			match operation() {
245				Ok(result) => return Ok(result),
246				Err(e) => {
247					last_error = Some(e.to_string());
248					if attempt < max_retries {
249						std::thread::sleep(std::time::Duration::from_millis(delay_ms));
250					}
251				},
252			}
253		}
254
255		Err(anyhow::anyhow!(
256			"Operation failed after {} attempts: {}",
257			max_retries + 1,
258			last_error.unwrap_or_else(|| "Unknown error".to_string())
259		))
260	}
261}
262
263#[cfg(test)]
264mod tests {
265	use super::*;
266
267	#[test]
268	fn test_grove_error_display() {
269		let err = GroveError::ExtensionNotFound("test.ext".to_string());
270		assert_eq!(err.to_string(), "Extension not found: test.ext");
271
272		let err = GroveError::Timeout;
273		assert_eq!(err.to_string(), "Operation timed out");
274	}
275
276	#[test]
277	fn test_serializable_trait() {
278		#[derive(Serialize, Deserialize, PartialEq, Debug)]
279		struct TestStruct {
280			value:i32,
281		}
282
283		let test = TestStruct { value:42 };
284		let json = test.to_json().unwrap();
285		let deserialized:TestStruct = TestStruct::from_json(&json).unwrap();
286		assert_eq!(test, deserialized);
287	}
288
289	#[test]
290	fn test_retryable_execute_with_retry() {
291		let retryable = RetryableTrait;
292
293		let mut attempt_count = 0;
294		let result = retryable.execute_with_retry(
295			|| {
296				attempt_count += 1;
297				if attempt_count < 3 { Err("Not ready") } else { Ok("Success") }
298			},
299			5,
300			100,
301		);
302
303		assert!(result.is_ok());
304		assert_eq!(result.unwrap(), "Success");
305		assert_eq!(attempt_count, 3);
306	}
307}
308
309// Helper struct for testing Retryable
310struct RetryableTrait;
311
312impl Retryable for RetryableTrait {}