depyler_annotations/
lib.rs

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