Skip to main content

gravityfile_plugin/
types.rs

1//! Core types for the plugin system.
2
3use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8/// Result type for plugin operations.
9pub type PluginResult<T> = Result<T, PluginError>;
10
11/// Errors that can occur in the plugin system.
12#[derive(Debug, Error)]
13pub enum PluginError {
14    /// Plugin file not found.
15    #[error("Plugin not found: {path}")]
16    NotFound { path: PathBuf },
17
18    /// Failed to load plugin.
19    #[error("Failed to load plugin '{name}': {message}")]
20    LoadError { name: String, message: String },
21
22    /// Plugin execution error.
23    #[error("Plugin '{name}' execution error: {message}")]
24    ExecutionError { name: String, message: String },
25
26    /// Plugin was cancelled.
27    #[error("Plugin '{name}' was cancelled")]
28    Cancelled { name: String },
29
30    /// Plugin timed out.
31    #[error("Plugin '{name}' timed out after {timeout_ms}ms")]
32    Timeout { name: String, timeout_ms: u64 },
33
34    /// Invalid plugin configuration.
35    #[error("Invalid plugin configuration: {message}")]
36    ConfigError { message: String },
37
38    /// Permission denied.
39    #[error("Permission denied for plugin '{name}': {action}")]
40    PermissionDenied { name: String, action: String },
41
42    /// Runtime not available.
43    #[error("Runtime '{runtime}' is not available")]
44    RuntimeNotAvailable { runtime: String },
45
46    /// IO error.
47    #[error("IO error: {0}")]
48    Io(#[from] std::io::Error),
49
50    /// Serialization error.
51    #[error("Serialization error: {0}")]
52    Serialization(String),
53
54    /// Hook not implemented.
55    #[error("Hook '{hook}' not implemented by plugin '{name}'")]
56    HookNotImplemented { name: String, hook: String },
57}
58
59/// Categories of plugins.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
61#[serde(rename_all = "lowercase")]
62pub enum PluginKind {
63    #[default]
64    /// Custom analysis plugins (find patterns, compute metrics).
65    /// Runs asynchronously in the background.
66    Analyzer,
67
68    /// File preview generation plugins (syntax highlighting, thumbnails).
69    /// Runs in an isolated context for safety.
70    Previewer,
71
72    /// Custom file operation plugins (compress, archive, transform).
73    /// Runs asynchronously with progress reporting.
74    Action,
75
76    /// Custom column/cell rendering plugins (git status, permissions).
77    /// Runs synchronously on the main thread.
78    Renderer,
79
80    /// Search and filter plugins (custom search algorithms).
81    /// Can be sync or async depending on implementation.
82    Filter,
83
84    /// Event listener plugins (logging, notifications).
85    /// Runs synchronously as callbacks.
86    Hook,
87}
88
89impl std::fmt::Display for PluginKind {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        match self {
92            Self::Analyzer => write!(f, "analyzer"),
93            Self::Previewer => write!(f, "previewer"),
94            Self::Action => write!(f, "action"),
95            Self::Renderer => write!(f, "renderer"),
96            Self::Filter => write!(f, "filter"),
97            Self::Hook => write!(f, "hook"),
98        }
99    }
100}
101
102/// A dynamic value that can be passed between Rust and plugin runtimes.
103///
104/// This is a simplified representation that can be converted to/from
105/// runtime-specific value types (mlua::Value, rhai::Dynamic, etc.).
106#[derive(Debug, Clone, Default, Serialize, Deserialize)]
107#[serde(untagged)]
108pub enum Value {
109    /// Null/nil value.
110    #[default]
111    Null,
112
113    /// Boolean value.
114    Bool(bool),
115
116    /// Integer value.
117    Integer(i64),
118
119    /// Floating point value.
120    Float(f64),
121
122    /// String value.
123    String(String),
124
125    /// Array/list value.
126    Array(Vec<Value>),
127
128    /// Object/table/map value.
129    Object(std::collections::HashMap<String, Value>),
130
131    /// Binary data.
132    Bytes(Vec<u8>),
133}
134
135impl Value {
136    /// Create a null value.
137    pub fn null() -> Self {
138        Self::Null
139    }
140
141    /// Check if this value is null.
142    pub fn is_null(&self) -> bool {
143        matches!(self, Self::Null)
144    }
145
146    /// Try to get this value as a boolean.
147    pub fn as_bool(&self) -> Option<bool> {
148        match self {
149            Self::Bool(b) => Some(*b),
150            _ => None,
151        }
152    }
153
154    /// Try to get this value as an integer.
155    pub fn as_i64(&self) -> Option<i64> {
156        match self {
157            Self::Integer(i) => Some(*i),
158            _ => None,
159        }
160    }
161
162    /// Try to get this value as a float.
163    pub fn as_f64(&self) -> Option<f64> {
164        match self {
165            Self::Float(f) => Some(*f),
166            Self::Integer(i) => Some(*i as f64),
167            _ => None,
168        }
169    }
170
171    /// Try to get this value as a string.
172    pub fn as_str(&self) -> Option<&str> {
173        match self {
174            Self::String(s) => Some(s),
175            _ => None,
176        }
177    }
178
179    /// Try to get this value as an array.
180    pub fn as_array(&self) -> Option<&[Value]> {
181        match self {
182            Self::Array(arr) => Some(arr),
183            _ => None,
184        }
185    }
186
187    /// Try to get this value as an object.
188    pub fn as_object(&self) -> Option<&std::collections::HashMap<String, Value>> {
189        match self {
190            Self::Object(obj) => Some(obj),
191            _ => None,
192        }
193    }
194}
195
196impl From<bool> for Value {
197    fn from(b: bool) -> Self {
198        Self::Bool(b)
199    }
200}
201
202impl From<i64> for Value {
203    fn from(i: i64) -> Self {
204        Self::Integer(i)
205    }
206}
207
208impl From<i32> for Value {
209    fn from(i: i32) -> Self {
210        Self::Integer(i as i64)
211    }
212}
213
214impl From<u64> for Value {
215    fn from(u: u64) -> Self {
216        if let Ok(i) = i64::try_from(u) {
217            Self::Integer(i)
218        } else {
219            Self::Float(u as f64)
220        }
221    }
222}
223
224impl From<f64> for Value {
225    fn from(f: f64) -> Self {
226        Self::Float(f)
227    }
228}
229
230impl From<String> for Value {
231    fn from(s: String) -> Self {
232        Self::String(s)
233    }
234}
235
236impl From<&str> for Value {
237    fn from(s: &str) -> Self {
238        Self::String(s.to_string())
239    }
240}
241
242impl<T: Into<Value>> From<Vec<T>> for Value {
243    fn from(arr: Vec<T>) -> Self {
244        Self::Array(arr.into_iter().map(Into::into).collect())
245    }
246}
247
248impl From<std::collections::HashMap<String, Value>> for Value {
249    fn from(obj: std::collections::HashMap<String, Value>) -> Self {
250        Self::Object(obj)
251    }
252}
253
254impl From<PathBuf> for Value {
255    fn from(path: PathBuf) -> Self {
256        Self::String(path.to_string_lossy().to_string())
257    }
258}