ricecoder_storage/
types.rs

1//! Core types for RiceCoder storage
2
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6/// Storage configuration
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct StorageConfig {
9    /// Path to global storage directory
10    pub global_path: PathBuf,
11    /// Path to project storage directory (if in a project)
12    pub project_path: Option<PathBuf>,
13    /// Storage mode (how to combine global and project storage)
14    pub mode: StorageMode,
15    /// Whether this is the first initialization
16    pub first_run: bool,
17}
18
19/// Storage mode determines how global and project storage are combined
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
21pub enum StorageMode {
22    /// Only use global storage
23    GlobalOnly,
24    /// Only use project storage
25    ProjectOnly,
26    /// Merge both, with project overriding global
27    Merged,
28}
29
30/// Resource types that can be stored
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
32pub enum ResourceType {
33    /// Templates for code generation
34    Template,
35    /// Coding standards and guidelines
36    Standard,
37    /// Specification documents
38    Spec,
39    /// Steering documents (project rules)
40    Steering,
41    /// Boilerplate projects
42    Boilerplate,
43    /// Learned rules from the learning system
44    Rule,
45    /// Custom command definitions
46    CustomCommand,
47    /// LSP language configuration files
48    LspLanguageConfig,
49    /// Code completion language configuration files
50    CompletionLanguageConfig,
51    /// Hooks configuration files
52    HooksConfig,
53    /// Refactoring language configuration files
54    RefactoringLanguageConfig,
55}
56
57impl ResourceType {
58    /// Get the directory name for this resource type
59    pub fn dir_name(&self) -> &'static str {
60        match self {
61            ResourceType::Template => "templates",
62            ResourceType::Standard => "standards",
63            ResourceType::Spec => "specs",
64            ResourceType::Steering => "steering",
65            ResourceType::Boilerplate => "boilerplates",
66            ResourceType::Rule => "rules",
67            ResourceType::CustomCommand => "commands",
68            ResourceType::LspLanguageConfig => "lsp/languages",
69            ResourceType::CompletionLanguageConfig => "completion/languages",
70            ResourceType::HooksConfig => "hooks",
71            ResourceType::RefactoringLanguageConfig => "refactoring/languages",
72        }
73    }
74}
75
76/// Configuration file format
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum ConfigFormat {
79    /// YAML format (.yaml, .yml)
80    Yaml,
81    /// TOML format (.toml)
82    Toml,
83    /// JSON format (.json)
84    Json,
85}
86
87impl ConfigFormat {
88    /// Get the file extension for this format
89    pub fn extension(&self) -> &'static str {
90        match self {
91            ConfigFormat::Yaml => "yaml",
92            ConfigFormat::Toml => "toml",
93            ConfigFormat::Json => "json",
94        }
95    }
96
97    /// Detect format from file extension
98    pub fn from_extension(ext: &str) -> Option<Self> {
99        match ext.to_lowercase().as_str() {
100            "yaml" | "yml" => Some(ConfigFormat::Yaml),
101            "toml" => Some(ConfigFormat::Toml),
102            "json" => Some(ConfigFormat::Json),
103            _ => None,
104        }
105    }
106}
107
108/// Document format for steering and specs
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
110pub enum DocumentFormat {
111    /// YAML format
112    Yaml,
113    /// Markdown format
114    Markdown,
115}
116
117impl DocumentFormat {
118    /// Get the file extension for this format
119    pub fn extension(&self) -> &'static str {
120        match self {
121            DocumentFormat::Yaml => "yaml",
122            DocumentFormat::Markdown => "md",
123        }
124    }
125
126    /// Detect format from file extension
127    pub fn from_extension(ext: &str) -> Option<Self> {
128        match ext.to_lowercase().as_str() {
129            "yaml" | "yml" => Some(DocumentFormat::Yaml),
130            "md" | "markdown" => Some(DocumentFormat::Markdown),
131            _ => None,
132        }
133    }
134}
135
136/// Storage availability state
137#[derive(Debug, Clone, PartialEq, Eq)]
138pub enum StorageState {
139    /// Storage is available and writable
140    Available,
141    /// Storage is unavailable (e.g., external drive disconnected)
142    Unavailable { reason: String },
143    /// Storage is available but read-only (e.g., offline mode)
144    ReadOnly { cached_at: String },
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn test_resource_type_dir_names() {
153        assert_eq!(ResourceType::Template.dir_name(), "templates");
154        assert_eq!(ResourceType::Standard.dir_name(), "standards");
155        assert_eq!(ResourceType::Spec.dir_name(), "specs");
156        assert_eq!(ResourceType::Steering.dir_name(), "steering");
157        assert_eq!(ResourceType::Boilerplate.dir_name(), "boilerplates");
158        assert_eq!(ResourceType::Rule.dir_name(), "rules");
159        assert_eq!(ResourceType::CustomCommand.dir_name(), "commands");
160        assert_eq!(ResourceType::HooksConfig.dir_name(), "hooks");
161        assert_eq!(
162            ResourceType::RefactoringLanguageConfig.dir_name(),
163            "refactoring/languages"
164        );
165    }
166
167    #[test]
168    fn test_config_format_extensions() {
169        assert_eq!(ConfigFormat::Yaml.extension(), "yaml");
170        assert_eq!(ConfigFormat::Toml.extension(), "toml");
171        assert_eq!(ConfigFormat::Json.extension(), "json");
172    }
173
174    #[test]
175    fn test_config_format_detection() {
176        assert_eq!(
177            ConfigFormat::from_extension("yaml"),
178            Some(ConfigFormat::Yaml)
179        );
180        assert_eq!(
181            ConfigFormat::from_extension("yml"),
182            Some(ConfigFormat::Yaml)
183        );
184        assert_eq!(
185            ConfigFormat::from_extension("toml"),
186            Some(ConfigFormat::Toml)
187        );
188        assert_eq!(
189            ConfigFormat::from_extension("json"),
190            Some(ConfigFormat::Json)
191        );
192        assert_eq!(ConfigFormat::from_extension("txt"), None);
193    }
194
195    #[test]
196    fn test_document_format_detection() {
197        assert_eq!(
198            DocumentFormat::from_extension("yaml"),
199            Some(DocumentFormat::Yaml)
200        );
201        assert_eq!(
202            DocumentFormat::from_extension("md"),
203            Some(DocumentFormat::Markdown)
204        );
205        assert_eq!(
206            DocumentFormat::from_extension("markdown"),
207            Some(DocumentFormat::Markdown)
208        );
209        assert_eq!(DocumentFormat::from_extension("txt"), None);
210    }
211}