Skip to main content

driven/format/
schema.rs

1//! Binary schema definitions for .drv format
2
3use bytemuck::{Pod, Zeroable};
4
5/// Header for .drv files (16 bytes, aligned)
6#[derive(Debug, Clone, Copy, Pod, Zeroable)]
7#[repr(C)]
8pub struct DrvHeader {
9    /// Magic bytes: "DRV\0"
10    pub magic: [u8; 4],
11    /// Format version
12    pub version: u16,
13    /// Feature flags
14    pub flags: u16,
15    /// Number of sections
16    pub section_count: u32,
17    /// Blake3 checksum (truncated to 32 bits)
18    pub checksum: u32,
19}
20
21impl DrvHeader {
22    /// Create a new header with default values
23    pub fn new(section_count: u32) -> Self {
24        Self {
25            magic: *b"DRV\0",
26            version: super::DRV_VERSION,
27            flags: 0,
28            section_count,
29            checksum: 0,
30        }
31    }
32
33    /// Validate the header
34    pub fn validate(&self) -> crate::Result<()> {
35        if &self.magic != b"DRV\0" {
36            return Err(crate::DrivenError::InvalidBinary(
37                "Invalid magic bytes".to_string(),
38            ));
39        }
40        if self.version > super::DRV_VERSION {
41            return Err(crate::DrivenError::InvalidBinary(format!(
42                "Unsupported version: {} (max supported: {})",
43                self.version,
44                super::DRV_VERSION
45            )));
46        }
47        Ok(())
48    }
49}
50
51/// Rule category enumeration
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53#[repr(u8)]
54pub enum RuleCategory {
55    /// General coding style
56    Style = 0,
57    /// Naming conventions
58    Naming = 1,
59    /// Error handling patterns
60    ErrorHandling = 2,
61    /// Testing requirements
62    Testing = 3,
63    /// Documentation standards
64    Documentation = 4,
65    /// Security practices
66    Security = 5,
67    /// Performance guidelines
68    Performance = 6,
69    /// Architecture patterns
70    Architecture = 7,
71    /// Import organization
72    Imports = 8,
73    /// Git conventions
74    Git = 9,
75    /// API design
76    Api = 10,
77    /// Other/custom
78    Other = 255,
79}
80
81impl From<u8> for RuleCategory {
82    fn from(value: u8) -> Self {
83        match value {
84            0 => RuleCategory::Style,
85            1 => RuleCategory::Naming,
86            2 => RuleCategory::ErrorHandling,
87            3 => RuleCategory::Testing,
88            4 => RuleCategory::Documentation,
89            5 => RuleCategory::Security,
90            6 => RuleCategory::Performance,
91            7 => RuleCategory::Architecture,
92            8 => RuleCategory::Imports,
93            9 => RuleCategory::Git,
94            10 => RuleCategory::Api,
95            _ => RuleCategory::Other,
96        }
97    }
98}
99
100/// A single rule entry in the standards section
101#[derive(Debug, Clone)]
102pub struct RuleEntry {
103    /// Category of this rule
104    pub category: RuleCategory,
105    /// Priority (0 = highest)
106    pub priority: u8,
107    /// Description string index
108    pub description_idx: u32,
109    /// Pattern/example string index (optional, 0 = none)
110    pub pattern_idx: u32,
111}
112
113/// Persona section defining AI agent behavior
114#[derive(Debug, Clone, Default)]
115pub struct PersonaSection {
116    /// Name string index
117    pub name_idx: u32,
118    /// Role description string index
119    pub role_idx: u32,
120    /// Identity/expertise string index
121    pub identity_idx: u32,
122    /// Communication style string index
123    pub style_idx: u32,
124    /// Trait string indices
125    pub traits: Vec<u32>,
126    /// Principle string indices
127    pub principles: Vec<u32>,
128}
129
130/// Standards section containing coding rules
131#[derive(Debug, Clone, Default)]
132pub struct StandardsSection {
133    /// All rule entries
134    pub rules: Vec<RuleEntry>,
135}
136
137/// Context section for project-specific settings
138#[derive(Debug, Clone, Default)]
139pub struct ContextSection {
140    /// Include patterns (string indices)
141    pub include_patterns: Vec<u32>,
142    /// Exclude patterns (string indices)
143    pub exclude_patterns: Vec<u32>,
144    /// Focus areas (string indices)
145    pub focus_areas: Vec<u32>,
146    /// Dependencies (name, version pairs as string indices)
147    pub dependencies: Vec<(u32, u32)>,
148}
149
150/// A single step in a workflow
151#[derive(Debug, Clone)]
152pub struct WorkflowStep {
153    /// Step name string index
154    pub name_idx: u32,
155    /// Description string index
156    pub description_idx: u32,
157    /// Condition string index (0 = always)
158    pub condition_idx: u32,
159    /// Action string indices
160    pub actions: Vec<u32>,
161}
162
163/// Workflow section defining development processes
164#[derive(Debug, Clone, Default)]
165pub struct WorkflowSection {
166    /// Workflow name string index
167    pub name_idx: u32,
168    /// Workflow steps
169    pub steps: Vec<WorkflowStep>,
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn test_header_size() {
178        assert_eq!(std::mem::size_of::<DrvHeader>(), 16);
179    }
180
181    #[test]
182    fn test_header_validation() {
183        let valid = DrvHeader::new(3);
184        assert!(valid.validate().is_ok());
185
186        let invalid = DrvHeader {
187            magic: *b"BAD\0",
188            ..valid
189        };
190        assert!(invalid.validate().is_err());
191    }
192
193    #[test]
194    fn test_rule_category_roundtrip() {
195        for i in 0..=10 {
196            let cat = RuleCategory::from(i);
197            assert_eq!(cat as u8, i);
198        }
199        // Unknown values become Other
200        assert_eq!(RuleCategory::from(100), RuleCategory::Other);
201    }
202}