Skip to main content

Grove/Common/
traits.rs

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