depyler_annotations/
lib.rs

1#![allow(clippy::missing_errors_doc)] // Parse methods have obvious error conditions
2
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use thiserror::Error;
7
8#[derive(Error, Debug)]
9pub enum AnnotationError {
10    #[error("Invalid annotation syntax: {0}")]
11    InvalidSyntax(String),
12    #[error("Unknown annotation key: {0}")]
13    UnknownKey(String),
14    #[error("Invalid value for key {key}: {value}")]
15    InvalidValue { key: String, value: String },
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19#[allow(clippy::struct_excessive_bools)] // Configuration struct requires multiple boolean flags
20pub struct TranspilationAnnotations {
21    pub type_strategy: TypeStrategy,
22    pub ownership_model: OwnershipModel,
23    pub safety_level: SafetyLevel,
24    pub performance_hints: Vec<PerformanceHint>,
25    pub fallback_strategy: FallbackStrategy,
26    pub bounds_checking: BoundsChecking,
27    pub optimization_level: OptimizationLevel,
28    pub thread_safety: ThreadSafety,
29    pub interior_mutability: InteriorMutability,
30    pub string_strategy: StringStrategy,
31    pub hash_strategy: HashStrategy,
32    pub panic_behavior: PanicBehavior,
33    pub error_strategy: ErrorStrategy,
34    pub global_strategy: GlobalStrategy,
35    pub termination: Termination,
36    pub invariants: Vec<String>,
37    pub verify_bounds: bool,
38    pub service_type: Option<ServiceType>,
39    pub migration_strategy: Option<MigrationStrategy>,
40    pub compatibility_layer: Option<CompatibilityLayer>,
41    pub pattern: Option<String>,
42    // Lambda-specific annotations
43    pub lambda_annotations: Option<LambdaAnnotations>,
44}
45
46impl Default for TranspilationAnnotations {
47    fn default() -> Self {
48        Self {
49            type_strategy: TypeStrategy::Conservative,
50            ownership_model: OwnershipModel::Owned,
51            safety_level: SafetyLevel::Safe,
52            performance_hints: Vec::new(),
53            fallback_strategy: FallbackStrategy::Error,
54            bounds_checking: BoundsChecking::Explicit,
55            optimization_level: OptimizationLevel::Standard,
56            thread_safety: ThreadSafety::NotRequired,
57            interior_mutability: InteriorMutability::None,
58            string_strategy: StringStrategy::Conservative,
59            hash_strategy: HashStrategy::Standard,
60            panic_behavior: PanicBehavior::Propagate,
61            error_strategy: ErrorStrategy::Panic,
62            global_strategy: GlobalStrategy::None,
63            termination: Termination::Unknown,
64            invariants: Vec::new(),
65            verify_bounds: false,
66            service_type: None,
67            migration_strategy: None,
68            compatibility_layer: None,
69            pattern: None,
70            lambda_annotations: None,
71        }
72    }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76#[allow(clippy::struct_excessive_bools)] // Lambda configuration requires many boolean flags
77pub struct LambdaAnnotations {
78    pub runtime: LambdaRuntime,
79    pub event_type: Option<LambdaEventType>,
80    pub cold_start_optimize: bool,
81    pub memory_size: u16,
82    pub architecture: Architecture,
83    pub pre_warm_paths: Vec<String>,
84    pub custom_serialization: bool,
85    pub batch_failure_reporting: bool,
86    pub timeout: Option<u16>,
87    pub tracing_enabled: bool,
88    pub environment_variables: Vec<(String, String)>,
89}
90
91impl Default for LambdaAnnotations {
92    fn default() -> Self {
93        Self {
94            runtime: LambdaRuntime::ProvidedAl2,
95            event_type: None,
96            cold_start_optimize: true,
97            memory_size: 128,
98            architecture: Architecture::Arm64,
99            pre_warm_paths: vec![],
100            custom_serialization: false,
101            batch_failure_reporting: false,
102            timeout: None,
103            tracing_enabled: false,
104            environment_variables: vec![],
105        }
106    }
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub enum LambdaRuntime {
111    ProvidedAl2,
112    ProvidedAl2023,
113    Custom(String),
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
117pub enum LambdaEventType {
118    Auto,
119    S3Event,
120    ApiGatewayProxyRequest,
121    ApiGatewayV2HttpRequest,
122    SqsEvent,
123    SnsEvent,
124    DynamodbEvent,
125    EventBridgeEvent(Option<String>),
126    CloudwatchEvent,
127    KinesisEvent,
128    Custom(String),
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
132pub enum Architecture {
133    X86_64,
134    Arm64,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub enum TypeStrategy {
139    Conservative,
140    Aggressive,
141    ZeroCopy,
142    AlwaysOwned,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146pub enum OwnershipModel {
147    Owned,
148    Borrowed,
149    Shared,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
153pub enum SafetyLevel {
154    Safe,
155    UnsafeAllowed,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
159pub enum PerformanceHint {
160    Vectorize,
161    UnrollLoops(u32),
162    OptimizeForLatency,
163    OptimizeForThroughput,
164    PerformanceCritical,
165}
166
167#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
168pub enum FallbackStrategy {
169    Mcp,
170    Manual,
171    Error,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub enum BoundsChecking {
176    Explicit,
177    Implicit,
178    Disabled,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
182pub enum OptimizationLevel {
183    Standard,
184    Aggressive,
185    Conservative,
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
189pub enum ThreadSafety {
190    Required,
191    NotRequired,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
195pub enum InteriorMutability {
196    None,
197    ArcMutex,
198    RefCell,
199    Cell,
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
203pub enum StringStrategy {
204    Conservative,
205    AlwaysOwned,
206    ZeroCopy,
207}
208
209#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
210pub enum HashStrategy {
211    Standard,
212    Fnv,
213    AHash,
214}
215
216#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
217pub enum PanicBehavior {
218    Propagate,
219    ReturnError,
220    Abort,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
224pub enum ErrorStrategy {
225    Panic,
226    ResultType,
227    OptionType,
228}
229
230#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
231pub enum GlobalStrategy {
232    None,
233    LazyStatic,
234    OnceCell,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
238pub enum Termination {
239    Unknown,
240    Proven,
241    BoundedLoop(u32),
242}
243
244#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
245pub enum ServiceType {
246    WebApi,
247    Cli,
248    Library,
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
252pub enum MigrationStrategy {
253    Incremental,
254    BigBang,
255    Hybrid,
256}
257
258#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
259pub enum CompatibilityLayer {
260    PyO3,
261    CTypes,
262    None,
263}
264
265pub struct AnnotationParser {
266    pattern: Regex,
267}
268
269#[derive(Debug, Clone, Default)]
270pub struct AnnotationValidator;
271
272impl AnnotationValidator {
273    /// Creates a new annotation validator.
274    pub fn new() -> Self {
275        Self
276    }
277
278    /// Validates the consistency of annotation settings.
279    ///
280    /// # Errors
281    ///
282    /// Returns a vector of error messages if any validation rules are violated.
283    pub fn validate(&self, annotations: &TranspilationAnnotations) -> Result<(), Vec<String>> {
284        let mut errors = Vec::new();
285
286        // Validate conflicting strategies
287        if annotations.string_strategy == StringStrategy::ZeroCopy
288            && annotations.ownership_model == OwnershipModel::Owned
289        {
290            errors
291                .push("Zero-copy string strategy conflicts with owned ownership model".to_string());
292        }
293
294        if annotations.thread_safety == ThreadSafety::Required
295            && annotations.interior_mutability == InteriorMutability::RefCell
296        {
297            errors.push("RefCell is not thread-safe, use Arc<Mutex<T>> instead".to_string());
298        }
299
300        if annotations.panic_behavior == PanicBehavior::ReturnError
301            && annotations.error_strategy == ErrorStrategy::Panic
302        {
303            errors.push("Conflicting panic behavior and error strategy".to_string());
304        }
305
306        if annotations.optimization_level == OptimizationLevel::Aggressive
307            && annotations.bounds_checking == BoundsChecking::Explicit
308        {
309            errors.push(
310                "Aggressive optimization may conflict with explicit bounds checking".to_string(),
311            );
312        }
313
314        if errors.is_empty() {
315            Ok(())
316        } else {
317            Err(errors)
318        }
319    }
320
321    pub fn suggest_improvements(&self, annotations: &TranspilationAnnotations) -> Vec<String> {
322        let mut suggestions = Vec::new();
323
324        if annotations
325            .performance_hints
326            .contains(&PerformanceHint::PerformanceCritical)
327            && annotations.optimization_level != OptimizationLevel::Aggressive
328        {
329            suggestions.push(
330                "Consider using optimization_level = \"aggressive\" for performance critical code"
331                    .to_string(),
332            );
333        }
334
335        if annotations.thread_safety == ThreadSafety::Required
336            && annotations.ownership_model != OwnershipModel::Shared
337        {
338            suggestions
339                .push("Consider using ownership = \"shared\" for thread-safe code".to_string());
340        }
341
342        if annotations.service_type == Some(ServiceType::WebApi)
343            && !annotations
344                .performance_hints
345                .contains(&PerformanceHint::OptimizeForLatency)
346        {
347            suggestions
348                .push("Consider adding optimization_hint = \"latency\" for web APIs".to_string());
349        }
350
351        suggestions
352    }
353}
354
355#[derive(Debug, Clone)]
356pub struct AnnotationExtractor {
357    function_pattern: Regex,
358    class_pattern: Regex,
359}
360
361impl Default for AnnotationExtractor {
362    fn default() -> Self {
363        Self {
364            function_pattern: Regex::new(r"(?m)^def\s+(\w+)\s*\(").unwrap(),
365            class_pattern: Regex::new(r"(?m)^class\s+(\w+)\s*[\(:]").unwrap(),
366        }
367    }
368}
369
370impl AnnotationExtractor {
371    /// Creates a new annotation extractor with pre-compiled regex patterns.
372    pub fn new() -> Self {
373        Self::default()
374    }
375
376    /// Extracts annotations for a specific function from source code.
377    ///
378    /// # Panics
379    ///
380    /// Panics if regex patterns fail to match (should not happen with valid regex).
381    pub fn extract_function_annotations(
382        &self,
383        source: &str,
384        function_name: &str,
385    ) -> Option<String> {
386        let lines: Vec<&str> = source.lines().collect();
387
388        for (i, line) in lines.iter().enumerate() {
389            if let Some(captures) = self.function_pattern.captures(line) {
390                if captures.get(1).unwrap().as_str() == function_name {
391                    // Collect annotations above the function
392                    let mut annotations = Vec::new();
393                    let mut j = i.saturating_sub(1);
394
395                    while j < i && (lines[j].trim().starts_with('#') || lines[j].trim().is_empty())
396                    {
397                        if lines[j].contains("@depyler:") {
398                            annotations.push(lines[j]);
399                        }
400                        if j == 0 {
401                            break;
402                        }
403                        j = j.saturating_sub(1);
404                    }
405
406                    if !annotations.is_empty() {
407                        annotations.reverse();
408                        return Some(annotations.join("\n"));
409                    }
410                }
411            }
412        }
413        None
414    }
415
416    /// Extracts annotations for a specific class from source code.
417    ///
418    /// # Panics
419    ///
420    /// Panics if regex patterns fail to match (should not happen with valid regex).
421    pub fn extract_class_annotations(&self, source: &str, class_name: &str) -> Option<String> {
422        let lines: Vec<&str> = source.lines().collect();
423
424        for (i, line) in lines.iter().enumerate() {
425            if let Some(captures) = self.class_pattern.captures(line) {
426                if captures.get(1).unwrap().as_str() == class_name {
427                    // Collect annotations above the class
428                    let mut annotations = Vec::new();
429                    let mut j = i.saturating_sub(1);
430
431                    while j < i && (lines[j].trim().starts_with('#') || lines[j].trim().is_empty())
432                    {
433                        if lines[j].contains("@depyler:") {
434                            annotations.push(lines[j]);
435                        }
436                        if j == 0 {
437                            break;
438                        }
439                        j = j.saturating_sub(1);
440                    }
441
442                    if !annotations.is_empty() {
443                        annotations.reverse();
444                        return Some(annotations.join("\n"));
445                    }
446                }
447            }
448        }
449        None
450    }
451}
452
453impl Default for AnnotationParser {
454    fn default() -> Self {
455        Self::new()
456    }
457}
458
459impl AnnotationParser {
460    /// Creates a new annotation parser.
461    ///
462    /// # Panics
463    ///
464    /// Panics if the internal regex pattern fails to compile (should never happen).
465    pub fn new() -> Self {
466        let pattern =
467            // This regex is statically known to be valid
468            Regex::new(r"#\s*@depyler:\s*(\w+)\s*=\s*(.+)")
469                .unwrap_or_else(|e| panic!("Failed to compile annotation regex: {e}"));
470        Self { pattern }
471    }
472
473    /// Parses annotations from source code comments.
474    ///
475    /// # Errors
476    ///
477    /// Returns `AnnotationError` if unknown keys or invalid values are encountered.
478    ///
479    /// # Panics
480    ///
481    /// Panics if the regex fails to capture groups (should not happen with valid regex).
482    pub fn parse_annotations(
483        &self,
484        source: &str,
485    ) -> Result<TranspilationAnnotations, AnnotationError> {
486        let mut annotations = TranspilationAnnotations::default();
487        let mut parsed_values: HashMap<String, String> = HashMap::new();
488
489        for line in source.lines() {
490            if let Some(captures) = self.pattern.captures(line) {
491                let key = captures.get(1).unwrap().as_str().to_string();
492                let value = captures.get(2).unwrap().as_str().trim_matches('"').trim();
493                parsed_values.insert(key, value.to_string());
494            }
495        }
496
497        self.apply_annotations(&mut annotations, parsed_values)?;
498        Ok(annotations)
499    }
500
501    /// Parses annotations from function-specific source code.
502    ///
503    /// # Errors
504    ///
505    /// Returns `AnnotationError` if parsing fails.
506    pub fn parse_function_annotations(
507        &self,
508        function_source: &str,
509    ) -> Result<TranspilationAnnotations, AnnotationError> {
510        self.parse_annotations(function_source)
511    }
512
513    #[allow(clippy::too_many_lines)]
514    fn apply_annotations(
515        &self,
516        annotations: &mut TranspilationAnnotations,
517        values: HashMap<String, String>,
518    ) -> Result<(), AnnotationError> {
519        for (key, value) in values {
520            match key.as_str() {
521                "type_strategy" => {
522                    annotations.type_strategy = self.parse_type_strategy(&value)?;
523                }
524                "ownership" => {
525                    annotations.ownership_model = self.parse_ownership_model(&value)?;
526                }
527                "safety_level" => {
528                    annotations.safety_level = self.parse_safety_level(&value)?;
529                }
530                "fallback" => {
531                    annotations.fallback_strategy = self.parse_fallback_strategy(&value)?;
532                }
533                "bounds_checking" => {
534                    annotations.bounds_checking = self.parse_bounds_checking(&value)?;
535                }
536                "optimization_level" => {
537                    annotations.optimization_level = self.parse_optimization_level(&value)?;
538                }
539                "thread_safety" => {
540                    annotations.thread_safety = self.parse_thread_safety(&value)?;
541                }
542                "interior_mutability" => {
543                    annotations.interior_mutability = self.parse_interior_mutability(&value)?;
544                }
545                "performance_critical" => {
546                    if value == "true" {
547                        annotations
548                            .performance_hints
549                            .push(PerformanceHint::PerformanceCritical);
550                    }
551                }
552                "vectorize" => {
553                    if value == "true" {
554                        annotations
555                            .performance_hints
556                            .push(PerformanceHint::Vectorize);
557                    }
558                }
559                "unroll_loops" => {
560                    let count: u32 = value.parse().map_err(|_| AnnotationError::InvalidValue {
561                        key: key.clone(),
562                        value: value.clone(),
563                    })?;
564                    annotations
565                        .performance_hints
566                        .push(PerformanceHint::UnrollLoops(count));
567                }
568                "optimization_hint" => {
569                    match value.as_str() {
570                        "vectorize" => annotations
571                            .performance_hints
572                            .push(PerformanceHint::Vectorize),
573                        "latency" => annotations
574                            .performance_hints
575                            .push(PerformanceHint::OptimizeForLatency),
576                        "throughput" => annotations
577                            .performance_hints
578                            .push(PerformanceHint::OptimizeForThroughput),
579                        "async_ready" => {
580                            // Async support requires tokio/async-std integration
581                            // Annotate functions as async-ready for future implementation
582                            eprintln!(
583                                "Warning: async_ready is experimental and not yet fully supported"
584                            );
585                        }
586                        _ => return Err(AnnotationError::InvalidValue { key, value }),
587                    }
588                }
589                "string_strategy" => {
590                    annotations.string_strategy = self.parse_string_strategy(&value)?;
591                }
592                "hash_strategy" => {
593                    annotations.hash_strategy = self.parse_hash_strategy(&value)?;
594                }
595                "panic_behavior" => {
596                    annotations.panic_behavior = self.parse_panic_behavior(&value)?;
597                }
598                "error_strategy" => {
599                    annotations.error_strategy = self.parse_error_strategy(&value)?;
600                }
601                "global_strategy" => {
602                    annotations.global_strategy = self.parse_global_strategy(&value)?;
603                }
604                "termination" => {
605                    annotations.termination = self.parse_termination(&value)?;
606                }
607                "invariant" => {
608                    annotations.invariants.push(value);
609                }
610                "verify_bounds" => {
611                    annotations.verify_bounds = value == "true";
612                }
613                "service_type" => {
614                    annotations.service_type = Some(self.parse_service_type(&value)?);
615                }
616                "migration_strategy" => {
617                    annotations.migration_strategy = Some(self.parse_migration_strategy(&value)?);
618                }
619                "compatibility_layer" => {
620                    annotations.compatibility_layer = Some(self.parse_compatibility_layer(&value)?);
621                }
622                "pattern" => {
623                    annotations.pattern = Some(value);
624                }
625                // Lambda-specific annotations
626                "lambda_runtime" => {
627                    let lambda_annotations = annotations
628                        .lambda_annotations
629                        .get_or_insert_with(LambdaAnnotations::default);
630                    lambda_annotations.runtime = self.parse_lambda_runtime(&value)?;
631                }
632                "event_type" => {
633                    let lambda_annotations = annotations
634                        .lambda_annotations
635                        .get_or_insert_with(LambdaAnnotations::default);
636                    lambda_annotations.event_type = Some(self.parse_lambda_event_type(&value)?);
637                }
638                "cold_start_optimize" => {
639                    let lambda_annotations = annotations
640                        .lambda_annotations
641                        .get_or_insert_with(LambdaAnnotations::default);
642                    lambda_annotations.cold_start_optimize = value == "true";
643                }
644                "memory_size" => {
645                    let lambda_annotations = annotations
646                        .lambda_annotations
647                        .get_or_insert_with(LambdaAnnotations::default);
648                    lambda_annotations.memory_size =
649                        value.parse().map_err(|_| AnnotationError::InvalidValue {
650                            key: key.clone(),
651                            value: value.clone(),
652                        })?;
653                }
654                "architecture" => {
655                    let lambda_annotations = annotations
656                        .lambda_annotations
657                        .get_or_insert_with(LambdaAnnotations::default);
658                    lambda_annotations.architecture = self.parse_architecture(&value)?;
659                }
660                "batch_failure_reporting" => {
661                    let lambda_annotations = annotations
662                        .lambda_annotations
663                        .get_or_insert_with(LambdaAnnotations::default);
664                    lambda_annotations.batch_failure_reporting = value == "true";
665                }
666                "custom_serialization" => {
667                    let lambda_annotations = annotations
668                        .lambda_annotations
669                        .get_or_insert_with(LambdaAnnotations::default);
670                    lambda_annotations.custom_serialization = value == "true";
671                }
672                "timeout" => {
673                    let lambda_annotations = annotations
674                        .lambda_annotations
675                        .get_or_insert_with(LambdaAnnotations::default);
676                    lambda_annotations.timeout =
677                        Some(value.parse().map_err(|_| AnnotationError::InvalidValue {
678                            key: key.clone(),
679                            value: value.clone(),
680                        })?);
681                }
682                "tracing" => {
683                    let lambda_annotations = annotations
684                        .lambda_annotations
685                        .get_or_insert_with(LambdaAnnotations::default);
686                    lambda_annotations.tracing_enabled = value == "true" || value == "Active";
687                }
688                _ => return Err(AnnotationError::UnknownKey(key)),
689            }
690        }
691        Ok(())
692    }
693
694    fn parse_type_strategy(&self, value: &str) -> Result<TypeStrategy, AnnotationError> {
695        match value {
696            "conservative" => Ok(TypeStrategy::Conservative),
697            "aggressive" => Ok(TypeStrategy::Aggressive),
698            "zero_copy" => Ok(TypeStrategy::ZeroCopy),
699            "always_owned" => Ok(TypeStrategy::AlwaysOwned),
700            _ => Err(AnnotationError::InvalidValue {
701                key: "type_strategy".to_string(),
702                value: value.to_string(),
703            }),
704        }
705    }
706
707    fn parse_ownership_model(&self, value: &str) -> Result<OwnershipModel, AnnotationError> {
708        match value {
709            "owned" => Ok(OwnershipModel::Owned),
710            "borrowed" => Ok(OwnershipModel::Borrowed),
711            "shared" => Ok(OwnershipModel::Shared),
712            _ => Err(AnnotationError::InvalidValue {
713                key: "ownership".to_string(),
714                value: value.to_string(),
715            }),
716        }
717    }
718
719    fn parse_safety_level(&self, value: &str) -> Result<SafetyLevel, AnnotationError> {
720        match value {
721            "safe" => Ok(SafetyLevel::Safe),
722            "unsafe_allowed" => Ok(SafetyLevel::UnsafeAllowed),
723            _ => Err(AnnotationError::InvalidValue {
724                key: "safety_level".to_string(),
725                value: value.to_string(),
726            }),
727        }
728    }
729
730    fn parse_fallback_strategy(&self, value: &str) -> Result<FallbackStrategy, AnnotationError> {
731        match value {
732            "mcp" => Ok(FallbackStrategy::Mcp),
733            "manual" => Ok(FallbackStrategy::Manual),
734            "error" => Ok(FallbackStrategy::Error),
735            _ => Err(AnnotationError::InvalidValue {
736                key: "fallback".to_string(),
737                value: value.to_string(),
738            }),
739        }
740    }
741
742    fn parse_bounds_checking(&self, value: &str) -> Result<BoundsChecking, AnnotationError> {
743        match value {
744            "explicit" => Ok(BoundsChecking::Explicit),
745            "implicit" => Ok(BoundsChecking::Implicit),
746            "disabled" => Ok(BoundsChecking::Disabled),
747            _ => Err(AnnotationError::InvalidValue {
748                key: "bounds_checking".to_string(),
749                value: value.to_string(),
750            }),
751        }
752    }
753
754    fn parse_optimization_level(&self, value: &str) -> Result<OptimizationLevel, AnnotationError> {
755        match value {
756            "standard" => Ok(OptimizationLevel::Standard),
757            "aggressive" => Ok(OptimizationLevel::Aggressive),
758            "conservative" => Ok(OptimizationLevel::Conservative),
759            _ => Err(AnnotationError::InvalidValue {
760                key: "optimization_level".to_string(),
761                value: value.to_string(),
762            }),
763        }
764    }
765
766    fn parse_thread_safety(&self, value: &str) -> Result<ThreadSafety, AnnotationError> {
767        match value {
768            "required" => Ok(ThreadSafety::Required),
769            "not_required" => Ok(ThreadSafety::NotRequired),
770            _ => Err(AnnotationError::InvalidValue {
771                key: "thread_safety".to_string(),
772                value: value.to_string(),
773            }),
774        }
775    }
776
777    fn parse_interior_mutability(
778        &self,
779        value: &str,
780    ) -> Result<InteriorMutability, AnnotationError> {
781        match value {
782            "none" => Ok(InteriorMutability::None),
783            "arc_mutex" => Ok(InteriorMutability::ArcMutex),
784            "ref_cell" => Ok(InteriorMutability::RefCell),
785            "cell" => Ok(InteriorMutability::Cell),
786            _ => Err(AnnotationError::InvalidValue {
787                key: "interior_mutability".to_string(),
788                value: value.to_string(),
789            }),
790        }
791    }
792
793    fn parse_string_strategy(&self, value: &str) -> Result<StringStrategy, AnnotationError> {
794        match value {
795            "conservative" => Ok(StringStrategy::Conservative),
796            "always_owned" => Ok(StringStrategy::AlwaysOwned),
797            "zero_copy" => Ok(StringStrategy::ZeroCopy),
798            _ => Err(AnnotationError::InvalidValue {
799                key: "string_strategy".to_string(),
800                value: value.to_string(),
801            }),
802        }
803    }
804
805    fn parse_hash_strategy(&self, value: &str) -> Result<HashStrategy, AnnotationError> {
806        match value {
807            "standard" => Ok(HashStrategy::Standard),
808            "fnv" => Ok(HashStrategy::Fnv),
809            "ahash" => Ok(HashStrategy::AHash),
810            _ => Err(AnnotationError::InvalidValue {
811                key: "hash_strategy".to_string(),
812                value: value.to_string(),
813            }),
814        }
815    }
816
817    fn parse_panic_behavior(&self, value: &str) -> Result<PanicBehavior, AnnotationError> {
818        match value {
819            "propagate" => Ok(PanicBehavior::Propagate),
820            "return_error" => Ok(PanicBehavior::ReturnError),
821            "abort" => Ok(PanicBehavior::Abort),
822            _ => Err(AnnotationError::InvalidValue {
823                key: "panic_behavior".to_string(),
824                value: value.to_string(),
825            }),
826        }
827    }
828
829    fn parse_error_strategy(&self, value: &str) -> Result<ErrorStrategy, AnnotationError> {
830        match value {
831            "panic" => Ok(ErrorStrategy::Panic),
832            "result_type" => Ok(ErrorStrategy::ResultType),
833            "option_type" => Ok(ErrorStrategy::OptionType),
834            _ => Err(AnnotationError::InvalidValue {
835                key: "error_strategy".to_string(),
836                value: value.to_string(),
837            }),
838        }
839    }
840
841    fn parse_global_strategy(&self, value: &str) -> Result<GlobalStrategy, AnnotationError> {
842        match value {
843            "none" => Ok(GlobalStrategy::None),
844            "lazy_static" => Ok(GlobalStrategy::LazyStatic),
845            "once_cell" => Ok(GlobalStrategy::OnceCell),
846            _ => Err(AnnotationError::InvalidValue {
847                key: "global_strategy".to_string(),
848                value: value.to_string(),
849            }),
850        }
851    }
852
853    fn parse_termination(&self, value: &str) -> Result<Termination, AnnotationError> {
854        match value {
855            "unknown" => Ok(Termination::Unknown),
856            "proven" => Ok(Termination::Proven),
857            _ => {
858                if value.starts_with("bounded_") {
859                    if let Some(num_str) = value.strip_prefix("bounded_") {
860                        if let Ok(bound) = num_str.parse::<u32>() {
861                            return Ok(Termination::BoundedLoop(bound));
862                        }
863                    }
864                }
865                Err(AnnotationError::InvalidValue {
866                    key: "termination".to_string(),
867                    value: value.to_string(),
868                })
869            }
870        }
871    }
872
873    fn parse_service_type(&self, value: &str) -> Result<ServiceType, AnnotationError> {
874        match value {
875            "web_api" => Ok(ServiceType::WebApi),
876            "cli" => Ok(ServiceType::Cli),
877            "library" => Ok(ServiceType::Library),
878            _ => Err(AnnotationError::InvalidValue {
879                key: "service_type".to_string(),
880                value: value.to_string(),
881            }),
882        }
883    }
884
885    fn parse_migration_strategy(&self, value: &str) -> Result<MigrationStrategy, AnnotationError> {
886        match value {
887            "incremental" => Ok(MigrationStrategy::Incremental),
888            "big_bang" => Ok(MigrationStrategy::BigBang),
889            "hybrid" => Ok(MigrationStrategy::Hybrid),
890            _ => Err(AnnotationError::InvalidValue {
891                key: "migration_strategy".to_string(),
892                value: value.to_string(),
893            }),
894        }
895    }
896
897    fn parse_compatibility_layer(
898        &self,
899        value: &str,
900    ) -> Result<CompatibilityLayer, AnnotationError> {
901        match value {
902            "pyo3" => Ok(CompatibilityLayer::PyO3),
903            "ctypes" => Ok(CompatibilityLayer::CTypes),
904            "none" => Ok(CompatibilityLayer::None),
905            _ => Err(AnnotationError::InvalidValue {
906                key: "compatibility_layer".to_string(),
907                value: value.to_string(),
908            }),
909        }
910    }
911
912    fn parse_lambda_runtime(&self, value: &str) -> Result<LambdaRuntime, AnnotationError> {
913        match value {
914            "provided.al2" => Ok(LambdaRuntime::ProvidedAl2),
915            "provided.al2023" => Ok(LambdaRuntime::ProvidedAl2023),
916            _ => Ok(LambdaRuntime::Custom(value.to_string())),
917        }
918    }
919
920    fn parse_lambda_event_type(&self, value: &str) -> Result<LambdaEventType, AnnotationError> {
921        match value {
922            "auto" => Ok(LambdaEventType::Auto),
923            "S3Event" => Ok(LambdaEventType::S3Event),
924            "APIGatewayProxyRequest" => Ok(LambdaEventType::ApiGatewayProxyRequest),
925            "APIGatewayV2HttpRequest" => Ok(LambdaEventType::ApiGatewayV2HttpRequest),
926            "SqsEvent" => Ok(LambdaEventType::SqsEvent),
927            "SnsEvent" => Ok(LambdaEventType::SnsEvent),
928            "DynamodbEvent" => Ok(LambdaEventType::DynamodbEvent),
929            "CloudwatchEvent" => Ok(LambdaEventType::CloudwatchEvent),
930            "KinesisEvent" => Ok(LambdaEventType::KinesisEvent),
931            _ => {
932                if value.starts_with("EventBridgeEvent<") && value.ends_with('>') {
933                    let inner = &value[17..value.len() - 1];
934                    Ok(LambdaEventType::EventBridgeEvent(Some(inner.to_string())))
935                } else if value == "EventBridgeEvent" {
936                    Ok(LambdaEventType::EventBridgeEvent(None))
937                } else {
938                    Ok(LambdaEventType::Custom(value.to_string()))
939                }
940            }
941        }
942    }
943
944    fn parse_architecture(&self, value: &str) -> Result<Architecture, AnnotationError> {
945        match value {
946            "x86_64" | "x64" => Ok(Architecture::X86_64),
947            "arm64" | "aarch64" => Ok(Architecture::Arm64),
948            _ => Err(AnnotationError::InvalidValue {
949                key: "architecture".to_string(),
950                value: value.to_string(),
951            }),
952        }
953    }
954}
955
956#[cfg(test)]
957mod tests {
958    use super::*;
959
960    #[test]
961    fn test_parse_basic_annotations() {
962        let parser = AnnotationParser::new();
963        let source = r#"
964# @depyler: type_strategy = "conservative"
965# @depyler: ownership = "borrowed"
966def test_function():
967    pass
968        "#;
969
970        let annotations = parser.parse_annotations(source).unwrap();
971        assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
972        assert_eq!(annotations.ownership_model, OwnershipModel::Borrowed);
973    }
974
975    #[test]
976    fn test_parse_performance_annotations() {
977        let parser = AnnotationParser::new();
978        let source = r#"
979# @depyler: performance_critical = "true"
980# @depyler: vectorize = "true"
981# @depyler: unroll_loops = "4"
982def fast_function():
983    pass
984        "#;
985
986        let annotations = parser.parse_annotations(source).unwrap();
987        assert!(annotations
988            .performance_hints
989            .contains(&PerformanceHint::PerformanceCritical));
990        assert!(annotations
991            .performance_hints
992            .contains(&PerformanceHint::Vectorize));
993        assert!(annotations
994            .performance_hints
995            .contains(&PerformanceHint::UnrollLoops(4)));
996    }
997
998    #[test]
999    fn test_parse_safety_annotations() {
1000        let parser = AnnotationParser::new();
1001        let source = r#"
1002# @depyler: safety_level = "unsafe_allowed"
1003# @depyler: bounds_checking = "disabled"
1004def unsafe_function():
1005    pass
1006        "#;
1007
1008        let annotations = parser.parse_annotations(source).unwrap();
1009        assert_eq!(annotations.safety_level, SafetyLevel::UnsafeAllowed);
1010        assert_eq!(annotations.bounds_checking, BoundsChecking::Disabled);
1011    }
1012
1013    #[test]
1014    fn test_parse_fallback_strategy() {
1015        let parser = AnnotationParser::new();
1016        let source = r#"
1017# @depyler: fallback = "mcp"
1018def complex_function():
1019    pass
1020        "#;
1021
1022        let annotations = parser.parse_annotations(source).unwrap();
1023        assert_eq!(annotations.fallback_strategy, FallbackStrategy::Mcp);
1024    }
1025
1026    #[test]
1027    fn test_parse_thread_safety() {
1028        let parser = AnnotationParser::new();
1029        let source = r#"
1030# @depyler: thread_safety = "required"
1031# @depyler: interior_mutability = "arc_mutex"
1032def thread_safe_function():
1033    pass
1034        "#;
1035
1036        let annotations = parser.parse_annotations(source).unwrap();
1037        assert_eq!(annotations.thread_safety, ThreadSafety::Required);
1038        assert_eq!(
1039            annotations.interior_mutability,
1040            InteriorMutability::ArcMutex
1041        );
1042    }
1043
1044    #[test]
1045    fn test_invalid_annotation_key() {
1046        let parser = AnnotationParser::new();
1047        let source = r#"
1048# @depyler: invalid_key = "value"
1049def test_function():
1050    pass
1051        "#;
1052
1053        let result = parser.parse_annotations(source);
1054        assert!(matches!(result, Err(AnnotationError::UnknownKey(_))));
1055    }
1056
1057    #[test]
1058    fn test_invalid_annotation_value() {
1059        let parser = AnnotationParser::new();
1060        let source = r#"
1061# @depyler: type_strategy = "invalid_value"
1062def test_function():
1063    pass
1064        "#;
1065
1066        let result = parser.parse_annotations(source);
1067        assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1068    }
1069
1070    #[test]
1071    fn test_default_annotations() {
1072        let annotations = TranspilationAnnotations::default();
1073        assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
1074        assert_eq!(annotations.ownership_model, OwnershipModel::Owned);
1075        assert_eq!(annotations.safety_level, SafetyLevel::Safe);
1076        assert_eq!(annotations.fallback_strategy, FallbackStrategy::Error);
1077    }
1078
1079    #[test]
1080    fn test_optimization_hints() {
1081        let parser = AnnotationParser::new();
1082        let source = r#"
1083# @depyler: optimization_hint = "vectorize"
1084# @depyler: optimization_level = "aggressive"
1085def optimized_function():
1086    pass
1087        "#;
1088
1089        let annotations = parser.parse_annotations(source).unwrap();
1090        assert!(annotations
1091            .performance_hints
1092            .contains(&PerformanceHint::Vectorize));
1093        assert_eq!(
1094            annotations.optimization_level,
1095            OptimizationLevel::Aggressive
1096        );
1097    }
1098
1099    #[test]
1100    fn test_string_and_hash_strategies() {
1101        let parser = AnnotationParser::new();
1102        let source = r#"
1103# @depyler: string_strategy = "zero_copy"
1104# @depyler: hash_strategy = "fnv"
1105def string_function():
1106    pass
1107        "#;
1108
1109        let annotations = parser.parse_annotations(source).unwrap();
1110        assert_eq!(annotations.string_strategy, StringStrategy::ZeroCopy);
1111        assert_eq!(annotations.hash_strategy, HashStrategy::Fnv);
1112    }
1113
1114    #[test]
1115    fn test_error_handling_annotations() {
1116        let parser = AnnotationParser::new();
1117        let source = r#"
1118# @depyler: panic_behavior = "return_error"
1119# @depyler: error_strategy = "result_type"
1120def error_function():
1121    pass
1122        "#;
1123
1124        let annotations = parser.parse_annotations(source).unwrap();
1125        assert_eq!(annotations.panic_behavior, PanicBehavior::ReturnError);
1126        assert_eq!(annotations.error_strategy, ErrorStrategy::ResultType);
1127    }
1128
1129    #[test]
1130    fn test_service_and_migration_annotations() {
1131        let parser = AnnotationParser::new();
1132        let source = r#"
1133# @depyler: service_type = "web_api"
1134# @depyler: migration_strategy = "incremental"
1135# @depyler: compatibility_layer = "pyo3"
1136def service_function():
1137    pass
1138        "#;
1139
1140        let annotations = parser.parse_annotations(source).unwrap();
1141        assert_eq!(annotations.service_type, Some(ServiceType::WebApi));
1142        assert_eq!(
1143            annotations.migration_strategy,
1144            Some(MigrationStrategy::Incremental)
1145        );
1146        assert_eq!(
1147            annotations.compatibility_layer,
1148            Some(CompatibilityLayer::PyO3)
1149        );
1150    }
1151
1152    #[test]
1153    fn test_verification_annotations() {
1154        let parser = AnnotationParser::new();
1155        let source = r#"
1156# @depyler: termination = "proven"
1157# @depyler: invariant = "left <= right"
1158# @depyler: verify_bounds = "true"
1159def verified_function():
1160    pass
1161        "#;
1162
1163        let annotations = parser.parse_annotations(source).unwrap();
1164        assert_eq!(annotations.termination, Termination::Proven);
1165        assert!(annotations
1166            .invariants
1167            .contains(&"left <= right".to_string()));
1168        assert!(annotations.verify_bounds);
1169    }
1170
1171    #[test]
1172    fn test_global_strategy() {
1173        let parser = AnnotationParser::new();
1174        let source = r#"
1175# @depyler: global_strategy = "lazy_static"
1176def global_function():
1177    pass
1178        "#;
1179
1180        let annotations = parser.parse_annotations(source).unwrap();
1181        assert_eq!(annotations.global_strategy, GlobalStrategy::LazyStatic);
1182    }
1183
1184    #[test]
1185    fn test_lambda_annotations_basic() {
1186        let parser = AnnotationParser::new();
1187        let source = r#"
1188# @depyler: lambda_runtime = "provided.al2"
1189# @depyler: event_type = "APIGatewayProxyRequest"
1190# @depyler: cold_start_optimize = "true"
1191def handler(event, context):
1192    pass
1193        "#;
1194
1195        let annotations = parser.parse_annotations(source).unwrap();
1196        assert!(annotations.lambda_annotations.is_some());
1197
1198        let lambda_annotations = annotations.lambda_annotations.unwrap();
1199        assert_eq!(lambda_annotations.runtime, LambdaRuntime::ProvidedAl2);
1200        assert_eq!(
1201            lambda_annotations.event_type,
1202            Some(LambdaEventType::ApiGatewayProxyRequest)
1203        );
1204        assert!(lambda_annotations.cold_start_optimize);
1205    }
1206
1207    #[test]
1208    fn test_lambda_annotations_memory_and_architecture() {
1209        let parser = AnnotationParser::new();
1210        let source = r#"
1211# @depyler: memory_size = "256"
1212# @depyler: architecture = "arm64"
1213# @depyler: timeout = "30"
1214def handler(event, context):
1215    pass
1216        "#;
1217
1218        let annotations = parser.parse_annotations(source).unwrap();
1219        let lambda_annotations = annotations.lambda_annotations.unwrap();
1220        assert_eq!(lambda_annotations.memory_size, 256);
1221        assert_eq!(lambda_annotations.architecture, Architecture::Arm64);
1222        assert_eq!(lambda_annotations.timeout, Some(30));
1223    }
1224
1225    #[test]
1226    fn test_lambda_eventbridge_with_custom_type() {
1227        let parser = AnnotationParser::new();
1228        let source = r#"
1229# @depyler: event_type = "EventBridgeEvent<OrderEvent>"
1230# @depyler: custom_serialization = "true"
1231def handler(event, context):
1232    pass
1233        "#;
1234
1235        let annotations = parser.parse_annotations(source).unwrap();
1236        let lambda_annotations = annotations.lambda_annotations.unwrap();
1237        assert_eq!(
1238            lambda_annotations.event_type,
1239            Some(LambdaEventType::EventBridgeEvent(Some(
1240                "OrderEvent".to_string()
1241            )))
1242        );
1243        assert!(lambda_annotations.custom_serialization);
1244    }
1245
1246    #[test]
1247    fn test_lambda_sqs_batch_processing() {
1248        let parser = AnnotationParser::new();
1249        let source = r#"
1250# @depyler: event_type = "SqsEvent"
1251# @depyler: batch_failure_reporting = "true"
1252# @depyler: tracing = "Active"
1253def handler(event, context):
1254    pass
1255        "#;
1256
1257        let annotations = parser.parse_annotations(source).unwrap();
1258        let lambda_annotations = annotations.lambda_annotations.unwrap();
1259        assert_eq!(
1260            lambda_annotations.event_type,
1261            Some(LambdaEventType::SqsEvent)
1262        );
1263        assert!(lambda_annotations.batch_failure_reporting);
1264        assert!(lambda_annotations.tracing_enabled);
1265    }
1266
1267    #[test]
1268    fn test_lambda_auto_event_type() {
1269        let parser = AnnotationParser::new();
1270        let source = r#"
1271# @depyler: event_type = "auto"
1272# @depyler: cold_start_optimize = "true"
1273def handler(event, context):
1274    pass
1275        "#;
1276
1277        let annotations = parser.parse_annotations(source).unwrap();
1278        let lambda_annotations = annotations.lambda_annotations.unwrap();
1279        assert_eq!(lambda_annotations.event_type, Some(LambdaEventType::Auto));
1280        assert!(lambda_annotations.cold_start_optimize);
1281    }
1282
1283    #[test]
1284    fn test_lambda_custom_runtime() {
1285        let parser = AnnotationParser::new();
1286        let source = r#"
1287# @depyler: lambda_runtime = "rust-runtime-1.0"
1288def handler(event, context):
1289    pass
1290        "#;
1291
1292        let annotations = parser.parse_annotations(source).unwrap();
1293        let lambda_annotations = annotations.lambda_annotations.unwrap();
1294        assert_eq!(
1295            lambda_annotations.runtime,
1296            LambdaRuntime::Custom("rust-runtime-1.0".to_string())
1297        );
1298    }
1299}