1#![allow(clippy::missing_errors_doc)] use 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)] pub 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 pub lambda_annotations: Option<LambdaAnnotations>,
44 pub custom_attributes: Vec<String>,
45}
46
47impl Default for TranspilationAnnotations {
48 fn default() -> Self {
49 Self {
50 type_strategy: TypeStrategy::Conservative,
51 ownership_model: OwnershipModel::Owned,
52 safety_level: SafetyLevel::Safe,
53 performance_hints: Vec::new(),
54 fallback_strategy: FallbackStrategy::Error,
55 bounds_checking: BoundsChecking::Explicit,
56 optimization_level: OptimizationLevel::Standard,
57 thread_safety: ThreadSafety::NotRequired,
58 interior_mutability: InteriorMutability::None,
59 string_strategy: StringStrategy::Conservative,
60 hash_strategy: HashStrategy::Standard,
61 panic_behavior: PanicBehavior::Propagate,
62 error_strategy: ErrorStrategy::Panic,
63 global_strategy: GlobalStrategy::None,
64 termination: Termination::Unknown,
65 invariants: Vec::new(),
66 verify_bounds: false,
67 service_type: None,
68 migration_strategy: None,
69 compatibility_layer: None,
70 pattern: None,
71 lambda_annotations: None,
72 custom_attributes: Vec::new(),
73 }
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[allow(clippy::struct_excessive_bools)] pub struct LambdaAnnotations {
80 pub runtime: LambdaRuntime,
81 pub event_type: Option<LambdaEventType>,
82 pub cold_start_optimize: bool,
83 pub memory_size: u16,
84 pub architecture: Architecture,
85 pub pre_warm_paths: Vec<String>,
86 pub custom_serialization: bool,
87 pub batch_failure_reporting: bool,
88 pub timeout: Option<u16>,
89 pub tracing_enabled: bool,
90 pub environment_variables: Vec<(String, String)>,
91}
92
93impl Default for LambdaAnnotations {
94 fn default() -> Self {
95 Self {
96 runtime: LambdaRuntime::ProvidedAl2,
97 event_type: None,
98 cold_start_optimize: true,
99 memory_size: 128,
100 architecture: Architecture::Arm64,
101 pre_warm_paths: vec![],
102 custom_serialization: false,
103 batch_failure_reporting: false,
104 timeout: None,
105 tracing_enabled: false,
106 environment_variables: vec![],
107 }
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
112pub enum LambdaRuntime {
113 ProvidedAl2,
114 ProvidedAl2023,
115 Custom(String),
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
119pub enum LambdaEventType {
120 Auto,
121 S3Event,
122 ApiGatewayProxyRequest,
123 ApiGatewayV2HttpRequest,
124 SqsEvent,
125 SnsEvent,
126 DynamodbEvent,
127 EventBridgeEvent(Option<String>),
128 CloudwatchEvent,
129 KinesisEvent,
130 Custom(String),
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub enum Architecture {
135 X86_64,
136 Arm64,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub enum TypeStrategy {
141 Conservative,
142 Aggressive,
143 ZeroCopy,
144 AlwaysOwned,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
148pub enum OwnershipModel {
149 Owned,
150 Borrowed,
151 Shared,
152}
153
154#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
155pub enum SafetyLevel {
156 Safe,
157 UnsafeAllowed,
158}
159
160#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub enum PerformanceHint {
162 Vectorize,
163 UnrollLoops(u32),
164 OptimizeForLatency,
165 OptimizeForThroughput,
166 PerformanceCritical,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
170pub enum FallbackStrategy {
171 Mcp,
172 Manual,
173 Error,
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
177pub enum BoundsChecking {
178 Explicit,
179 Implicit,
180 Disabled,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
184pub enum OptimizationLevel {
185 Standard,
186 Aggressive,
187 Conservative,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
191pub enum ThreadSafety {
192 Required,
193 NotRequired,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
197pub enum InteriorMutability {
198 None,
199 ArcMutex,
200 RefCell,
201 Cell,
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
205pub enum StringStrategy {
206 Conservative,
207 AlwaysOwned,
208 ZeroCopy,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
212pub enum HashStrategy {
213 Standard,
214 Fnv,
215 AHash,
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
219pub enum PanicBehavior {
220 Propagate,
221 ReturnError,
222 Abort,
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
226pub enum ErrorStrategy {
227 Panic,
228 ResultType,
229 OptionType,
230}
231
232#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
233pub enum GlobalStrategy {
234 None,
235 LazyStatic,
236 OnceCell,
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
240pub enum Termination {
241 Unknown,
242 Proven,
243 BoundedLoop(u32),
244}
245
246#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
247pub enum ServiceType {
248 WebApi,
249 Cli,
250 Library,
251}
252
253#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
254pub enum MigrationStrategy {
255 Incremental,
256 BigBang,
257 Hybrid,
258}
259
260#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
261pub enum CompatibilityLayer {
262 PyO3,
263 CTypes,
264 None,
265}
266
267pub struct AnnotationParser {
268 pattern: Regex,
269}
270
271#[derive(Debug, Clone, Default)]
272pub struct AnnotationValidator;
273
274impl AnnotationValidator {
275 pub fn new() -> Self {
277 Self
278 }
279
280 pub fn validate(&self, annotations: &TranspilationAnnotations) -> Result<(), Vec<String>> {
286 let mut errors = Vec::new();
287
288 if annotations.string_strategy == StringStrategy::ZeroCopy
290 && annotations.ownership_model == OwnershipModel::Owned
291 {
292 errors
293 .push("Zero-copy string strategy conflicts with owned ownership model".to_string());
294 }
295
296 if annotations.thread_safety == ThreadSafety::Required
297 && annotations.interior_mutability == InteriorMutability::RefCell
298 {
299 errors.push("RefCell is not thread-safe, use Arc<Mutex<T>> instead".to_string());
300 }
301
302 if annotations.panic_behavior == PanicBehavior::ReturnError
303 && annotations.error_strategy == ErrorStrategy::Panic
304 {
305 errors.push("Conflicting panic behavior and error strategy".to_string());
306 }
307
308 if annotations.optimization_level == OptimizationLevel::Aggressive
309 && annotations.bounds_checking == BoundsChecking::Explicit
310 {
311 errors.push(
312 "Aggressive optimization may conflict with explicit bounds checking".to_string(),
313 );
314 }
315
316 if errors.is_empty() {
317 Ok(())
318 } else {
319 Err(errors)
320 }
321 }
322
323 pub fn suggest_improvements(&self, annotations: &TranspilationAnnotations) -> Vec<String> {
324 let mut suggestions = Vec::new();
325
326 if annotations
327 .performance_hints
328 .contains(&PerformanceHint::PerformanceCritical)
329 && annotations.optimization_level != OptimizationLevel::Aggressive
330 {
331 suggestions.push(
332 "Consider using optimization_level = \"aggressive\" for performance critical code"
333 .to_string(),
334 );
335 }
336
337 if annotations.thread_safety == ThreadSafety::Required
338 && annotations.ownership_model != OwnershipModel::Shared
339 {
340 suggestions
341 .push("Consider using ownership = \"shared\" for thread-safe code".to_string());
342 }
343
344 if annotations.service_type == Some(ServiceType::WebApi)
345 && !annotations
346 .performance_hints
347 .contains(&PerformanceHint::OptimizeForLatency)
348 {
349 suggestions
350 .push("Consider adding optimization_hint = \"latency\" for web APIs".to_string());
351 }
352
353 suggestions
354 }
355}
356
357#[derive(Debug, Clone)]
358pub struct AnnotationExtractor {
359 function_pattern: Regex,
360 class_pattern: Regex,
361}
362
363impl Default for AnnotationExtractor {
364 fn default() -> Self {
365 Self {
366 function_pattern: Regex::new(r"(?m)^def\s+(\w+)\s*\(").expect("static regex"),
367 class_pattern: Regex::new(r"(?m)^class\s+(\w+)\s*[\(:]").expect("static regex"),
368 }
369 }
370}
371
372impl AnnotationExtractor {
373 pub fn new() -> Self {
375 Self::default()
376 }
377
378 pub fn extract_function_annotations(
384 &self,
385 source: &str,
386 function_name: &str,
387 ) -> Option<String> {
388 let lines: Vec<&str> = source.lines().collect();
389
390 for (i, line) in lines.iter().enumerate() {
391 if let Some(captures) = self.function_pattern.captures(line) {
392 if captures.get(1).expect("capture group 1 exists").as_str() == function_name {
393 let mut annotations = Vec::new();
395 let mut j = i.saturating_sub(1);
396
397 while j < i && (lines[j].trim().starts_with('#') || lines[j].trim().is_empty())
398 {
399 if lines[j].contains("@depyler:") {
400 annotations.push(lines[j]);
401 }
402 if j == 0 {
403 break;
404 }
405 j = j.saturating_sub(1);
406 }
407
408 if !annotations.is_empty() {
409 annotations.reverse();
410 return Some(annotations.join("\n"));
411 }
412 }
413 }
414 }
415 None
416 }
417
418 pub fn extract_class_annotations(&self, source: &str, class_name: &str) -> Option<String> {
424 let lines: Vec<&str> = source.lines().collect();
425
426 for (i, line) in lines.iter().enumerate() {
427 if let Some(captures) = self.class_pattern.captures(line) {
428 if captures.get(1).expect("capture group 1 exists").as_str() == class_name {
429 let mut annotations = Vec::new();
431 let mut j = i.saturating_sub(1);
432
433 while j < i && (lines[j].trim().starts_with('#') || lines[j].trim().is_empty())
434 {
435 if lines[j].contains("@depyler:") {
436 annotations.push(lines[j]);
437 }
438 if j == 0 {
439 break;
440 }
441 j = j.saturating_sub(1);
442 }
443
444 if !annotations.is_empty() {
445 annotations.reverse();
446 return Some(annotations.join("\n"));
447 }
448 }
449 }
450 }
451 None
452 }
453}
454
455impl Default for AnnotationParser {
456 fn default() -> Self {
457 Self::new()
458 }
459}
460
461impl AnnotationParser {
462 pub fn new() -> Self {
468 let pattern =
469 Regex::new(r"#\s*@depyler:\s*(\w+)\s*=\s*(.+)")
471 .unwrap_or_else(|e| panic!("Failed to compile annotation regex: {e}"));
472 Self { pattern }
473 }
474
475 pub fn parse_annotations(
485 &self,
486 source: &str,
487 ) -> Result<TranspilationAnnotations, AnnotationError> {
488 let mut annotations = TranspilationAnnotations::default();
489 let mut parsed_values: HashMap<String, String> = HashMap::new();
490
491 for line in source.lines() {
492 if let Some(captures) = self.pattern.captures(line) {
493 let key = captures
494 .get(1)
495 .expect("capture group 1 exists")
496 .as_str()
497 .to_string();
498 let value = captures
499 .get(2)
500 .expect("capture group 2 exists")
501 .as_str()
502 .trim_matches('"')
503 .trim();
504
505 if key == "custom_attribute" {
507 annotations.custom_attributes.push(value.to_string());
508 } else {
509 parsed_values.insert(key, value.to_string());
510 }
511 }
512 }
513
514 self.apply_annotations(&mut annotations, parsed_values)?;
515 Ok(annotations)
516 }
517
518 pub fn parse_function_annotations(
524 &self,
525 function_source: &str,
526 ) -> Result<TranspilationAnnotations, AnnotationError> {
527 self.parse_annotations(function_source)
528 }
529
530 fn apply_annotations(
531 &self,
532 annotations: &mut TranspilationAnnotations,
533 values: HashMap<String, String>,
534 ) -> Result<(), AnnotationError> {
535 for (key, value) in values {
536 match key.as_str() {
538 "type_strategy" | "ownership" | "safety_level" | "fallback" | "bounds_checking" => {
540 self.apply_core_annotation(annotations, &key, &value)?;
541 }
542
543 "optimization_level"
545 | "performance_critical"
546 | "vectorize"
547 | "unroll_loops"
548 | "optimization_hint" => {
549 self.apply_optimization_annotation(annotations, &key, &value)?;
550 }
551
552 "thread_safety" | "interior_mutability" => {
554 self.apply_thread_safety_annotation(annotations, &key, &value)?;
555 }
556
557 "string_strategy" | "hash_strategy" => {
559 self.apply_string_hash_annotation(annotations, &key, &value)?;
560 }
561
562 "panic_behavior" | "error_strategy" => {
564 self.apply_error_handling_annotation(annotations, &key, &value)?;
565 }
566
567 "global_strategy" => {
569 self.apply_global_strategy_annotation(annotations, &value)?;
570 }
571
572 "termination" | "invariant" | "verify_bounds" => {
574 self.apply_verification_annotation(annotations, &key, &value)?;
575 }
576
577 "service_type" | "migration_strategy" | "compatibility_layer" | "pattern" => {
579 self.apply_service_metadata_annotation(annotations, &key, &value)?;
580 }
581
582 "lambda_runtime"
584 | "event_type"
585 | "cold_start_optimize"
586 | "memory_size"
587 | "architecture"
588 | "batch_failure_reporting"
589 | "custom_serialization"
590 | "timeout"
591 | "tracing" => {
592 self.apply_lambda_annotation(annotations, &key, &value)?;
593 }
594
595 _ => return Err(AnnotationError::UnknownKey(key)),
596 }
597 }
598 Ok(())
599 }
600
601 #[inline]
603 fn apply_core_annotation(
604 &self,
605 annotations: &mut TranspilationAnnotations,
606 key: &str,
607 value: &str,
608 ) -> Result<(), AnnotationError> {
609 match key {
610 "type_strategy" => {
611 annotations.type_strategy = self.parse_type_strategy(value)?;
612 }
613 "ownership" => {
614 annotations.ownership_model = self.parse_ownership_model(value)?;
615 }
616 "safety_level" => {
617 annotations.safety_level = self.parse_safety_level(value)?;
618 }
619 "fallback" => {
620 annotations.fallback_strategy = self.parse_fallback_strategy(value)?;
621 }
622 "bounds_checking" => {
623 annotations.bounds_checking = self.parse_bounds_checking(value)?;
624 }
625 _ => unreachable!("apply_core_annotation called with non-core key"),
626 }
627 Ok(())
628 }
629
630 #[inline]
632 fn apply_optimization_annotation(
633 &self,
634 annotations: &mut TranspilationAnnotations,
635 key: &str,
636 value: &str,
637 ) -> Result<(), AnnotationError> {
638 match key {
639 "optimization_level" => {
640 annotations.optimization_level = self.parse_optimization_level(value)?;
641 }
642 "performance_critical" => {
643 if value == "true" {
644 annotations
645 .performance_hints
646 .push(PerformanceHint::PerformanceCritical);
647 }
648 }
649 "vectorize" => {
650 if value == "true" {
651 annotations
652 .performance_hints
653 .push(PerformanceHint::Vectorize);
654 }
655 }
656 "unroll_loops" => {
657 let count: u32 = value.parse().map_err(|_| AnnotationError::InvalidValue {
658 key: key.to_string(),
659 value: value.to_string(),
660 })?;
661 annotations
662 .performance_hints
663 .push(PerformanceHint::UnrollLoops(count));
664 }
665 "optimization_hint" => {
666 self.apply_optimization_hint(annotations, value)?;
667 }
668 _ => unreachable!("apply_optimization_annotation called with non-optimization key"),
669 }
670 Ok(())
671 }
672
673 #[inline]
675 fn apply_optimization_hint(
676 &self,
677 annotations: &mut TranspilationAnnotations,
678 value: &str,
679 ) -> Result<(), AnnotationError> {
680 match value {
681 "vectorize" => annotations
682 .performance_hints
683 .push(PerformanceHint::Vectorize),
684 "latency" => annotations
685 .performance_hints
686 .push(PerformanceHint::OptimizeForLatency),
687 "throughput" => annotations
688 .performance_hints
689 .push(PerformanceHint::OptimizeForThroughput),
690 "async_ready" => {
691 eprintln!("Warning: async_ready is experimental and not yet fully supported");
692 }
693 _ => {
694 return Err(AnnotationError::InvalidValue {
695 key: "optimization_hint".to_string(),
696 value: value.to_string(),
697 })
698 }
699 }
700 Ok(())
701 }
702
703 #[inline]
705 fn apply_thread_safety_annotation(
706 &self,
707 annotations: &mut TranspilationAnnotations,
708 key: &str,
709 value: &str,
710 ) -> Result<(), AnnotationError> {
711 match key {
712 "thread_safety" => {
713 annotations.thread_safety = self.parse_thread_safety(value)?;
714 }
715 "interior_mutability" => {
716 annotations.interior_mutability = self.parse_interior_mutability(value)?;
717 }
718 _ => unreachable!("apply_thread_safety_annotation called with non-thread-safety key"),
719 }
720 Ok(())
721 }
722
723 #[inline]
725 fn apply_global_strategy_annotation(
726 &self,
727 annotations: &mut TranspilationAnnotations,
728 value: &str,
729 ) -> Result<(), AnnotationError> {
730 annotations.global_strategy = self.parse_global_strategy(value)?;
731 Ok(())
732 }
733
734 #[inline]
736 fn apply_string_hash_annotation(
737 &self,
738 annotations: &mut TranspilationAnnotations,
739 key: &str,
740 value: &str,
741 ) -> Result<(), AnnotationError> {
742 match key {
743 "string_strategy" => {
744 annotations.string_strategy = self.parse_string_strategy(value)?;
745 }
746 "hash_strategy" => {
747 annotations.hash_strategy = self.parse_hash_strategy(value)?;
748 }
749 _ => unreachable!("apply_string_hash_annotation called with non-string/hash key"),
750 }
751 Ok(())
752 }
753
754 #[inline]
756 fn apply_error_handling_annotation(
757 &self,
758 annotations: &mut TranspilationAnnotations,
759 key: &str,
760 value: &str,
761 ) -> Result<(), AnnotationError> {
762 match key {
763 "panic_behavior" => {
764 annotations.panic_behavior = self.parse_panic_behavior(value)?;
765 }
766 "error_strategy" => {
767 annotations.error_strategy = self.parse_error_strategy(value)?;
768 }
769 _ => unreachable!("apply_error_handling_annotation called with non-error key"),
770 }
771 Ok(())
772 }
773
774 #[inline]
776 fn apply_verification_annotation(
777 &self,
778 annotations: &mut TranspilationAnnotations,
779 key: &str,
780 value: &str,
781 ) -> Result<(), AnnotationError> {
782 match key {
783 "termination" => {
784 annotations.termination = self.parse_termination(value)?;
785 }
786 "invariant" => {
787 annotations.invariants.push(value.to_string());
788 }
789 "verify_bounds" => {
790 annotations.verify_bounds = value == "true";
791 }
792 _ => unreachable!("apply_verification_annotation called with non-verification key"),
793 }
794 Ok(())
795 }
796
797 #[inline]
799 fn apply_service_metadata_annotation(
800 &self,
801 annotations: &mut TranspilationAnnotations,
802 key: &str,
803 value: &str,
804 ) -> Result<(), AnnotationError> {
805 match key {
806 "service_type" => {
807 annotations.service_type = Some(self.parse_service_type(value)?);
808 }
809 "migration_strategy" => {
810 annotations.migration_strategy = Some(self.parse_migration_strategy(value)?);
811 }
812 "compatibility_layer" => {
813 annotations.compatibility_layer = Some(self.parse_compatibility_layer(value)?);
814 }
815 "pattern" => {
816 annotations.pattern = Some(value.to_string());
817 }
818 _ => unreachable!("apply_service_metadata_annotation called with non-service key"),
819 }
820 Ok(())
821 }
822
823 #[inline]
825 fn apply_lambda_annotation(
826 &self,
827 annotations: &mut TranspilationAnnotations,
828 key: &str,
829 value: &str,
830 ) -> Result<(), AnnotationError> {
831 let lambda_annotations = annotations
832 .lambda_annotations
833 .get_or_insert_with(LambdaAnnotations::default);
834
835 match key {
836 "lambda_runtime" | "event_type" | "architecture" => {
837 self.apply_lambda_config(lambda_annotations, key, value)?;
838 }
839 "cold_start_optimize"
840 | "batch_failure_reporting"
841 | "custom_serialization"
842 | "tracing" => {
843 self.apply_lambda_flags(lambda_annotations, key, value);
844 }
845 "memory_size" | "timeout" => {
846 self.apply_lambda_numeric(lambda_annotations, key, value)?;
847 }
848 _ => unreachable!("apply_lambda_annotation called with non-lambda key"),
849 }
850 Ok(())
851 }
852
853 #[inline]
855 fn apply_lambda_config(
856 &self,
857 lambda_annotations: &mut LambdaAnnotations,
858 key: &str,
859 value: &str,
860 ) -> Result<(), AnnotationError> {
861 match key {
862 "lambda_runtime" => {
863 lambda_annotations.runtime = self.parse_lambda_runtime(value)?;
864 }
865 "event_type" => {
866 lambda_annotations.event_type = Some(self.parse_lambda_event_type(value)?);
867 }
868 "architecture" => {
869 lambda_annotations.architecture = self.parse_architecture(value)?;
870 }
871 _ => unreachable!("apply_lambda_config called with non-config key"),
872 }
873 Ok(())
874 }
875
876 #[inline]
878 fn apply_lambda_flags(
879 &self,
880 lambda_annotations: &mut LambdaAnnotations,
881 key: &str,
882 value: &str,
883 ) {
884 match key {
885 "cold_start_optimize" => {
886 lambda_annotations.cold_start_optimize = value == "true";
887 }
888 "batch_failure_reporting" => {
889 lambda_annotations.batch_failure_reporting = value == "true";
890 }
891 "custom_serialization" => {
892 lambda_annotations.custom_serialization = value == "true";
893 }
894 "tracing" => {
895 lambda_annotations.tracing_enabled = value == "true" || value == "Active";
896 }
897 _ => unreachable!("apply_lambda_flags called with non-flag key"),
898 }
899 }
900
901 #[inline]
903 fn apply_lambda_numeric(
904 &self,
905 lambda_annotations: &mut LambdaAnnotations,
906 key: &str,
907 value: &str,
908 ) -> Result<(), AnnotationError> {
909 match key {
910 "memory_size" => {
911 lambda_annotations.memory_size =
912 value.parse().map_err(|_| AnnotationError::InvalidValue {
913 key: key.to_string(),
914 value: value.to_string(),
915 })?;
916 }
917 "timeout" => {
918 lambda_annotations.timeout =
919 Some(value.parse().map_err(|_| AnnotationError::InvalidValue {
920 key: key.to_string(),
921 value: value.to_string(),
922 })?);
923 }
924 _ => unreachable!("apply_lambda_numeric called with non-numeric key"),
925 }
926 Ok(())
927 }
928
929 fn parse_type_strategy(&self, value: &str) -> Result<TypeStrategy, AnnotationError> {
930 match value {
931 "conservative" => Ok(TypeStrategy::Conservative),
932 "aggressive" => Ok(TypeStrategy::Aggressive),
933 "zero_copy" => Ok(TypeStrategy::ZeroCopy),
934 "always_owned" => Ok(TypeStrategy::AlwaysOwned),
935 _ => Err(AnnotationError::InvalidValue {
936 key: "type_strategy".to_string(),
937 value: value.to_string(),
938 }),
939 }
940 }
941
942 fn parse_ownership_model(&self, value: &str) -> Result<OwnershipModel, AnnotationError> {
943 match value {
944 "owned" => Ok(OwnershipModel::Owned),
945 "borrowed" => Ok(OwnershipModel::Borrowed),
946 "shared" => Ok(OwnershipModel::Shared),
947 _ => Err(AnnotationError::InvalidValue {
948 key: "ownership".to_string(),
949 value: value.to_string(),
950 }),
951 }
952 }
953
954 fn parse_safety_level(&self, value: &str) -> Result<SafetyLevel, AnnotationError> {
955 match value {
956 "safe" => Ok(SafetyLevel::Safe),
957 "unsafe_allowed" => Ok(SafetyLevel::UnsafeAllowed),
958 _ => Err(AnnotationError::InvalidValue {
959 key: "safety_level".to_string(),
960 value: value.to_string(),
961 }),
962 }
963 }
964
965 fn parse_fallback_strategy(&self, value: &str) -> Result<FallbackStrategy, AnnotationError> {
966 match value {
967 "mcp" => Ok(FallbackStrategy::Mcp),
968 "manual" => Ok(FallbackStrategy::Manual),
969 "error" => Ok(FallbackStrategy::Error),
970 _ => Err(AnnotationError::InvalidValue {
971 key: "fallback".to_string(),
972 value: value.to_string(),
973 }),
974 }
975 }
976
977 fn parse_bounds_checking(&self, value: &str) -> Result<BoundsChecking, AnnotationError> {
978 match value {
979 "explicit" => Ok(BoundsChecking::Explicit),
980 "implicit" => Ok(BoundsChecking::Implicit),
981 "disabled" => Ok(BoundsChecking::Disabled),
982 _ => Err(AnnotationError::InvalidValue {
983 key: "bounds_checking".to_string(),
984 value: value.to_string(),
985 }),
986 }
987 }
988
989 fn parse_optimization_level(&self, value: &str) -> Result<OptimizationLevel, AnnotationError> {
990 match value {
991 "standard" => Ok(OptimizationLevel::Standard),
992 "aggressive" => Ok(OptimizationLevel::Aggressive),
993 "conservative" => Ok(OptimizationLevel::Conservative),
994 _ => Err(AnnotationError::InvalidValue {
995 key: "optimization_level".to_string(),
996 value: value.to_string(),
997 }),
998 }
999 }
1000
1001 fn parse_thread_safety(&self, value: &str) -> Result<ThreadSafety, AnnotationError> {
1002 match value {
1003 "required" => Ok(ThreadSafety::Required),
1004 "not_required" => Ok(ThreadSafety::NotRequired),
1005 _ => Err(AnnotationError::InvalidValue {
1006 key: "thread_safety".to_string(),
1007 value: value.to_string(),
1008 }),
1009 }
1010 }
1011
1012 fn parse_interior_mutability(
1013 &self,
1014 value: &str,
1015 ) -> Result<InteriorMutability, AnnotationError> {
1016 match value {
1017 "none" => Ok(InteriorMutability::None),
1018 "arc_mutex" => Ok(InteriorMutability::ArcMutex),
1019 "ref_cell" => Ok(InteriorMutability::RefCell),
1020 "cell" => Ok(InteriorMutability::Cell),
1021 _ => Err(AnnotationError::InvalidValue {
1022 key: "interior_mutability".to_string(),
1023 value: value.to_string(),
1024 }),
1025 }
1026 }
1027
1028 fn parse_string_strategy(&self, value: &str) -> Result<StringStrategy, AnnotationError> {
1029 match value {
1030 "conservative" => Ok(StringStrategy::Conservative),
1031 "always_owned" => Ok(StringStrategy::AlwaysOwned),
1032 "zero_copy" => Ok(StringStrategy::ZeroCopy),
1033 _ => Err(AnnotationError::InvalidValue {
1034 key: "string_strategy".to_string(),
1035 value: value.to_string(),
1036 }),
1037 }
1038 }
1039
1040 fn parse_hash_strategy(&self, value: &str) -> Result<HashStrategy, AnnotationError> {
1041 match value {
1042 "standard" => Ok(HashStrategy::Standard),
1043 "fnv" => Ok(HashStrategy::Fnv),
1044 "ahash" => Ok(HashStrategy::AHash),
1045 _ => Err(AnnotationError::InvalidValue {
1046 key: "hash_strategy".to_string(),
1047 value: value.to_string(),
1048 }),
1049 }
1050 }
1051
1052 fn parse_panic_behavior(&self, value: &str) -> Result<PanicBehavior, AnnotationError> {
1053 match value {
1054 "propagate" => Ok(PanicBehavior::Propagate),
1055 "return_error" => Ok(PanicBehavior::ReturnError),
1056 "abort" => Ok(PanicBehavior::Abort),
1057 _ => Err(AnnotationError::InvalidValue {
1058 key: "panic_behavior".to_string(),
1059 value: value.to_string(),
1060 }),
1061 }
1062 }
1063
1064 fn parse_error_strategy(&self, value: &str) -> Result<ErrorStrategy, AnnotationError> {
1065 match value {
1066 "panic" => Ok(ErrorStrategy::Panic),
1067 "result_type" => Ok(ErrorStrategy::ResultType),
1068 "option_type" => Ok(ErrorStrategy::OptionType),
1069 _ => Err(AnnotationError::InvalidValue {
1070 key: "error_strategy".to_string(),
1071 value: value.to_string(),
1072 }),
1073 }
1074 }
1075
1076 fn parse_global_strategy(&self, value: &str) -> Result<GlobalStrategy, AnnotationError> {
1077 match value {
1078 "none" => Ok(GlobalStrategy::None),
1079 "lazy_static" => Ok(GlobalStrategy::LazyStatic),
1080 "once_cell" => Ok(GlobalStrategy::OnceCell),
1081 _ => Err(AnnotationError::InvalidValue {
1082 key: "global_strategy".to_string(),
1083 value: value.to_string(),
1084 }),
1085 }
1086 }
1087
1088 fn parse_termination(&self, value: &str) -> Result<Termination, AnnotationError> {
1089 match value {
1090 "unknown" => Ok(Termination::Unknown),
1091 "proven" => Ok(Termination::Proven),
1092 _ => {
1093 if value.starts_with("bounded_") {
1094 if let Some(num_str) = value.strip_prefix("bounded_") {
1095 if let Ok(bound) = num_str.parse::<u32>() {
1096 return Ok(Termination::BoundedLoop(bound));
1097 }
1098 }
1099 }
1100 Err(AnnotationError::InvalidValue {
1101 key: "termination".to_string(),
1102 value: value.to_string(),
1103 })
1104 }
1105 }
1106 }
1107
1108 fn parse_service_type(&self, value: &str) -> Result<ServiceType, AnnotationError> {
1109 match value {
1110 "web_api" => Ok(ServiceType::WebApi),
1111 "cli" => Ok(ServiceType::Cli),
1112 "library" => Ok(ServiceType::Library),
1113 _ => Err(AnnotationError::InvalidValue {
1114 key: "service_type".to_string(),
1115 value: value.to_string(),
1116 }),
1117 }
1118 }
1119
1120 fn parse_migration_strategy(&self, value: &str) -> Result<MigrationStrategy, AnnotationError> {
1121 match value {
1122 "incremental" => Ok(MigrationStrategy::Incremental),
1123 "big_bang" => Ok(MigrationStrategy::BigBang),
1124 "hybrid" => Ok(MigrationStrategy::Hybrid),
1125 _ => Err(AnnotationError::InvalidValue {
1126 key: "migration_strategy".to_string(),
1127 value: value.to_string(),
1128 }),
1129 }
1130 }
1131
1132 fn parse_compatibility_layer(
1133 &self,
1134 value: &str,
1135 ) -> Result<CompatibilityLayer, AnnotationError> {
1136 match value {
1137 "pyo3" => Ok(CompatibilityLayer::PyO3),
1138 "ctypes" => Ok(CompatibilityLayer::CTypes),
1139 "none" => Ok(CompatibilityLayer::None),
1140 _ => Err(AnnotationError::InvalidValue {
1141 key: "compatibility_layer".to_string(),
1142 value: value.to_string(),
1143 }),
1144 }
1145 }
1146
1147 fn parse_lambda_runtime(&self, value: &str) -> Result<LambdaRuntime, AnnotationError> {
1148 match value {
1149 "provided.al2" => Ok(LambdaRuntime::ProvidedAl2),
1150 "provided.al2023" => Ok(LambdaRuntime::ProvidedAl2023),
1151 _ => Ok(LambdaRuntime::Custom(value.to_string())),
1152 }
1153 }
1154
1155 fn parse_lambda_event_type(&self, value: &str) -> Result<LambdaEventType, AnnotationError> {
1156 let event_type = match value {
1158 "auto" => LambdaEventType::Auto,
1159 "S3Event" | "SqsEvent" | "SnsEvent" | "DynamodbEvent" | "CloudwatchEvent"
1160 | "KinesisEvent" => self.parse_aws_service_event(value),
1161 "APIGatewayProxyRequest" | "APIGatewayV2HttpRequest" => {
1162 self.parse_api_gateway_event(value)
1163 }
1164 _ => self.parse_custom_event_type(value),
1165 };
1166 Ok(event_type)
1167 }
1168
1169 #[inline]
1171 fn parse_aws_service_event(&self, value: &str) -> LambdaEventType {
1172 match value {
1173 "S3Event" => LambdaEventType::S3Event,
1174 "SqsEvent" => LambdaEventType::SqsEvent,
1175 "SnsEvent" => LambdaEventType::SnsEvent,
1176 "DynamodbEvent" => LambdaEventType::DynamodbEvent,
1177 "CloudwatchEvent" => LambdaEventType::CloudwatchEvent,
1178 "KinesisEvent" => LambdaEventType::KinesisEvent,
1179 _ => unreachable!("parse_aws_service_event called with non-AWS-service event"),
1180 }
1181 }
1182
1183 #[inline]
1185 fn parse_api_gateway_event(&self, value: &str) -> LambdaEventType {
1186 match value {
1187 "APIGatewayProxyRequest" => LambdaEventType::ApiGatewayProxyRequest,
1188 "APIGatewayV2HttpRequest" => LambdaEventType::ApiGatewayV2HttpRequest,
1189 _ => unreachable!("parse_api_gateway_event called with non-API-Gateway event"),
1190 }
1191 }
1192
1193 #[inline]
1195 fn parse_custom_event_type(&self, value: &str) -> LambdaEventType {
1196 if value.starts_with("EventBridgeEvent<") && value.ends_with('>') {
1197 let inner = &value[17..value.len() - 1];
1198 LambdaEventType::EventBridgeEvent(Some(inner.to_string()))
1199 } else if value == "EventBridgeEvent" {
1200 LambdaEventType::EventBridgeEvent(None)
1201 } else {
1202 LambdaEventType::Custom(value.to_string())
1203 }
1204 }
1205
1206 fn parse_architecture(&self, value: &str) -> Result<Architecture, AnnotationError> {
1207 match value {
1208 "x86_64" | "x64" => Ok(Architecture::X86_64),
1209 "arm64" | "aarch64" => Ok(Architecture::Arm64),
1210 _ => Err(AnnotationError::InvalidValue {
1211 key: "architecture".to_string(),
1212 value: value.to_string(),
1213 }),
1214 }
1215 }
1216}
1217
1218#[cfg(test)]
1219mod tests {
1220 use super::*;
1221
1222 #[test]
1227 fn test_default_annotations() {
1228 let annotations = TranspilationAnnotations::default();
1229 assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
1230 assert_eq!(annotations.ownership_model, OwnershipModel::Owned);
1231 assert_eq!(annotations.safety_level, SafetyLevel::Safe);
1232 assert_eq!(annotations.fallback_strategy, FallbackStrategy::Error);
1233 }
1234
1235 #[test]
1236 fn test_default_annotations_all_fields() {
1237 let a = TranspilationAnnotations::default();
1238 assert_eq!(a.bounds_checking, BoundsChecking::Explicit);
1239 assert_eq!(a.optimization_level, OptimizationLevel::Standard);
1240 assert_eq!(a.thread_safety, ThreadSafety::NotRequired);
1241 assert_eq!(a.interior_mutability, InteriorMutability::None);
1242 assert_eq!(a.string_strategy, StringStrategy::Conservative);
1243 assert_eq!(a.hash_strategy, HashStrategy::Standard);
1244 assert_eq!(a.panic_behavior, PanicBehavior::Propagate);
1245 assert_eq!(a.error_strategy, ErrorStrategy::Panic);
1246 assert_eq!(a.global_strategy, GlobalStrategy::None);
1247 assert_eq!(a.termination, Termination::Unknown);
1248 assert!(a.invariants.is_empty());
1249 assert!(!a.verify_bounds);
1250 assert!(a.service_type.is_none());
1251 assert!(a.migration_strategy.is_none());
1252 assert!(a.compatibility_layer.is_none());
1253 assert!(a.pattern.is_none());
1254 assert!(a.lambda_annotations.is_none());
1255 assert!(a.custom_attributes.is_empty());
1256 assert!(a.performance_hints.is_empty());
1257 }
1258
1259 #[test]
1260 fn test_default_lambda_annotations() {
1261 let la = LambdaAnnotations::default();
1262 assert_eq!(la.runtime, LambdaRuntime::ProvidedAl2);
1263 assert!(la.event_type.is_none());
1264 assert!(la.cold_start_optimize);
1265 assert_eq!(la.memory_size, 128);
1266 assert_eq!(la.architecture, Architecture::Arm64);
1267 assert!(la.pre_warm_paths.is_empty());
1268 assert!(!la.custom_serialization);
1269 assert!(!la.batch_failure_reporting);
1270 assert!(la.timeout.is_none());
1271 assert!(!la.tracing_enabled);
1272 assert!(la.environment_variables.is_empty());
1273 }
1274
1275 #[test]
1276 fn test_annotation_validator_default() {
1277 let v = AnnotationValidator;
1278 let a = TranspilationAnnotations::default();
1279 assert!(v.validate(&a).is_ok());
1280 }
1281
1282 #[test]
1283 fn test_annotation_extractor_default() {
1284 let e = AnnotationExtractor::default();
1285 let result = e.extract_function_annotations("def foo():\n pass", "foo");
1286 assert!(result.is_none());
1287 }
1288
1289 #[test]
1290 fn test_annotation_parser_default() {
1291 let p = AnnotationParser::default();
1292 let a = p.parse_annotations("# no annotations here").unwrap();
1293 assert_eq!(a, TranspilationAnnotations::default());
1294 }
1295
1296 #[test]
1301 fn test_parse_basic_annotations() {
1302 let parser = AnnotationParser::new();
1303 let source = r#"
1304# @depyler: type_strategy = "conservative"
1305# @depyler: ownership = "borrowed"
1306def test_function():
1307 pass
1308 "#;
1309
1310 let annotations = parser.parse_annotations(source).unwrap();
1311 assert_eq!(annotations.type_strategy, TypeStrategy::Conservative);
1312 assert_eq!(annotations.ownership_model, OwnershipModel::Borrowed);
1313 }
1314
1315 #[test]
1316 fn test_parse_empty_source() {
1317 let parser = AnnotationParser::new();
1318 let annotations = parser.parse_annotations("").unwrap();
1319 assert_eq!(annotations, TranspilationAnnotations::default());
1320 }
1321
1322 #[test]
1323 fn test_parse_no_annotations_in_source() {
1324 let parser = AnnotationParser::new();
1325 let source = "def foo():\n return 42\n";
1326 let annotations = parser.parse_annotations(source).unwrap();
1327 assert_eq!(annotations, TranspilationAnnotations::default());
1328 }
1329
1330 #[test]
1331 fn test_parse_function_annotations_delegates() {
1332 let parser = AnnotationParser::new();
1333 let source = "# @depyler: ownership = \"shared\"\ndef foo(): pass";
1334 let a = parser.parse_function_annotations(source).unwrap();
1335 assert_eq!(a.ownership_model, OwnershipModel::Shared);
1336 }
1337
1338 #[test]
1343 fn test_parse_type_strategy_all_variants() {
1344 let parser = AnnotationParser::new();
1345 let cases = [
1346 ("conservative", TypeStrategy::Conservative),
1347 ("aggressive", TypeStrategy::Aggressive),
1348 ("zero_copy", TypeStrategy::ZeroCopy),
1349 ("always_owned", TypeStrategy::AlwaysOwned),
1350 ];
1351 for (input, expected) in &cases {
1352 let source = format!("# @depyler: type_strategy = \"{input}\"");
1353 let a = parser.parse_annotations(&source).unwrap();
1354 assert_eq!(a.type_strategy, *expected);
1355 }
1356 }
1357
1358 #[test]
1359 fn test_parse_type_strategy_invalid() {
1360 let parser = AnnotationParser::new();
1361 let source = "# @depyler: type_strategy = \"bogus\"";
1362 let result = parser.parse_annotations(source);
1363 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1364 }
1365
1366 #[test]
1371 fn test_parse_ownership_model_all_variants() {
1372 let parser = AnnotationParser::new();
1373 let cases = [
1374 ("owned", OwnershipModel::Owned),
1375 ("borrowed", OwnershipModel::Borrowed),
1376 ("shared", OwnershipModel::Shared),
1377 ];
1378 for (input, expected) in &cases {
1379 let source = format!("# @depyler: ownership = \"{input}\"");
1380 let a = parser.parse_annotations(&source).unwrap();
1381 assert_eq!(a.ownership_model, *expected);
1382 }
1383 }
1384
1385 #[test]
1386 fn test_parse_ownership_invalid() {
1387 let parser = AnnotationParser::new();
1388 let source = "# @depyler: ownership = \"moved\"";
1389 let result = parser.parse_annotations(source);
1390 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1391 }
1392
1393 #[test]
1398 fn test_parse_safety_annotations() {
1399 let parser = AnnotationParser::new();
1400 let source = r#"
1401# @depyler: safety_level = "unsafe_allowed"
1402# @depyler: bounds_checking = "disabled"
1403def unsafe_function():
1404 pass
1405 "#;
1406
1407 let annotations = parser.parse_annotations(source).unwrap();
1408 assert_eq!(annotations.safety_level, SafetyLevel::UnsafeAllowed);
1409 assert_eq!(annotations.bounds_checking, BoundsChecking::Disabled);
1410 }
1411
1412 #[test]
1413 fn test_parse_safety_level_safe() {
1414 let parser = AnnotationParser::new();
1415 let source = "# @depyler: safety_level = \"safe\"";
1416 let a = parser.parse_annotations(source).unwrap();
1417 assert_eq!(a.safety_level, SafetyLevel::Safe);
1418 }
1419
1420 #[test]
1421 fn test_parse_safety_level_invalid() {
1422 let parser = AnnotationParser::new();
1423 let source = "# @depyler: safety_level = \"yolo\"";
1424 let result = parser.parse_annotations(source);
1425 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1426 }
1427
1428 #[test]
1433 fn test_parse_fallback_strategy() {
1434 let parser = AnnotationParser::new();
1435 let source = r#"
1436# @depyler: fallback = "mcp"
1437def complex_function():
1438 pass
1439 "#;
1440
1441 let annotations = parser.parse_annotations(source).unwrap();
1442 assert_eq!(annotations.fallback_strategy, FallbackStrategy::Mcp);
1443 }
1444
1445 #[test]
1446 fn test_parse_fallback_all_variants() {
1447 let parser = AnnotationParser::new();
1448 let cases = [
1449 ("mcp", FallbackStrategy::Mcp),
1450 ("manual", FallbackStrategy::Manual),
1451 ("error", FallbackStrategy::Error),
1452 ];
1453 for (input, expected) in &cases {
1454 let source = format!("# @depyler: fallback = \"{input}\"");
1455 let a = parser.parse_annotations(&source).unwrap();
1456 assert_eq!(a.fallback_strategy, *expected);
1457 }
1458 }
1459
1460 #[test]
1461 fn test_parse_fallback_invalid() {
1462 let parser = AnnotationParser::new();
1463 let source = "# @depyler: fallback = \"skip\"";
1464 let result = parser.parse_annotations(source);
1465 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1466 }
1467
1468 #[test]
1473 fn test_parse_bounds_checking_all_variants() {
1474 let parser = AnnotationParser::new();
1475 let cases = [
1476 ("explicit", BoundsChecking::Explicit),
1477 ("implicit", BoundsChecking::Implicit),
1478 ("disabled", BoundsChecking::Disabled),
1479 ];
1480 for (input, expected) in &cases {
1481 let source = format!("# @depyler: bounds_checking = \"{input}\"");
1482 let a = parser.parse_annotations(&source).unwrap();
1483 assert_eq!(a.bounds_checking, *expected);
1484 }
1485 }
1486
1487 #[test]
1492 fn test_parse_performance_annotations() {
1493 let parser = AnnotationParser::new();
1494 let source = r#"
1495# @depyler: performance_critical = "true"
1496# @depyler: vectorize = "true"
1497# @depyler: unroll_loops = "4"
1498def fast_function():
1499 pass
1500 "#;
1501
1502 let annotations = parser.parse_annotations(source).unwrap();
1503 assert!(annotations
1504 .performance_hints
1505 .contains(&PerformanceHint::PerformanceCritical));
1506 assert!(annotations
1507 .performance_hints
1508 .contains(&PerformanceHint::Vectorize));
1509 assert!(annotations
1510 .performance_hints
1511 .contains(&PerformanceHint::UnrollLoops(4)));
1512 }
1513
1514 #[test]
1515 fn test_optimization_hints() {
1516 let parser = AnnotationParser::new();
1517 let source = r#"
1518# @depyler: optimization_hint = "vectorize"
1519# @depyler: optimization_level = "aggressive"
1520def optimized_function():
1521 pass
1522 "#;
1523
1524 let annotations = parser.parse_annotations(source).unwrap();
1525 assert!(annotations
1526 .performance_hints
1527 .contains(&PerformanceHint::Vectorize));
1528 assert_eq!(
1529 annotations.optimization_level,
1530 OptimizationLevel::Aggressive
1531 );
1532 }
1533
1534 #[test]
1535 fn test_parse_optimization_hint_latency() {
1536 let parser = AnnotationParser::new();
1537 let source = "# @depyler: optimization_hint = \"latency\"";
1538 let a = parser.parse_annotations(source).unwrap();
1539 assert!(a
1540 .performance_hints
1541 .contains(&PerformanceHint::OptimizeForLatency));
1542 }
1543
1544 #[test]
1545 fn test_parse_optimization_hint_throughput() {
1546 let parser = AnnotationParser::new();
1547 let source = "# @depyler: optimization_hint = \"throughput\"";
1548 let a = parser.parse_annotations(source).unwrap();
1549 assert!(a
1550 .performance_hints
1551 .contains(&PerformanceHint::OptimizeForThroughput));
1552 }
1553
1554 #[test]
1555 fn test_parse_optimization_hint_invalid() {
1556 let parser = AnnotationParser::new();
1557 let source = "# @depyler: optimization_hint = \"magic\"";
1558 let result = parser.parse_annotations(source);
1559 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1560 }
1561
1562 #[test]
1563 fn test_parse_unroll_loops_invalid_value() {
1564 let parser = AnnotationParser::new();
1565 let source = "# @depyler: unroll_loops = \"not_a_number\"";
1566 let result = parser.parse_annotations(source);
1567 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1568 }
1569
1570 #[test]
1571 fn test_parse_performance_critical_false() {
1572 let parser = AnnotationParser::new();
1573 let source = "# @depyler: performance_critical = \"false\"";
1574 let a = parser.parse_annotations(source).unwrap();
1575 assert!(!a
1576 .performance_hints
1577 .contains(&PerformanceHint::PerformanceCritical));
1578 }
1579
1580 #[test]
1581 fn test_parse_vectorize_false() {
1582 let parser = AnnotationParser::new();
1583 let source = "# @depyler: vectorize = \"false\"";
1584 let a = parser.parse_annotations(source).unwrap();
1585 assert!(!a
1586 .performance_hints
1587 .contains(&PerformanceHint::Vectorize));
1588 }
1589
1590 #[test]
1591 fn test_parse_optimization_level_all_variants() {
1592 let parser = AnnotationParser::new();
1593 let cases = [
1594 ("standard", OptimizationLevel::Standard),
1595 ("aggressive", OptimizationLevel::Aggressive),
1596 ("conservative", OptimizationLevel::Conservative),
1597 ];
1598 for (input, expected) in &cases {
1599 let source = format!("# @depyler: optimization_level = \"{input}\"");
1600 let a = parser.parse_annotations(&source).unwrap();
1601 assert_eq!(a.optimization_level, *expected);
1602 }
1603 }
1604
1605 #[test]
1610 fn test_parse_thread_safety() {
1611 let parser = AnnotationParser::new();
1612 let source = r#"
1613# @depyler: thread_safety = "required"
1614# @depyler: interior_mutability = "arc_mutex"
1615def thread_safe_function():
1616 pass
1617 "#;
1618
1619 let annotations = parser.parse_annotations(source).unwrap();
1620 assert_eq!(annotations.thread_safety, ThreadSafety::Required);
1621 assert_eq!(
1622 annotations.interior_mutability,
1623 InteriorMutability::ArcMutex
1624 );
1625 }
1626
1627 #[test]
1628 fn test_parse_interior_mutability_all_variants() {
1629 let parser = AnnotationParser::new();
1630 let cases = [
1631 ("none", InteriorMutability::None),
1632 ("arc_mutex", InteriorMutability::ArcMutex),
1633 ("ref_cell", InteriorMutability::RefCell),
1634 ("cell", InteriorMutability::Cell),
1635 ];
1636 for (input, expected) in &cases {
1637 let source = format!("# @depyler: interior_mutability = \"{input}\"");
1638 let a = parser.parse_annotations(&source).unwrap();
1639 assert_eq!(a.interior_mutability, *expected);
1640 }
1641 }
1642
1643 #[test]
1644 fn test_parse_thread_safety_not_required() {
1645 let parser = AnnotationParser::new();
1646 let source = "# @depyler: thread_safety = \"not_required\"";
1647 let a = parser.parse_annotations(source).unwrap();
1648 assert_eq!(a.thread_safety, ThreadSafety::NotRequired);
1649 }
1650
1651 #[test]
1656 fn test_string_and_hash_strategies() {
1657 let parser = AnnotationParser::new();
1658 let source = r#"
1659# @depyler: string_strategy = "zero_copy"
1660# @depyler: hash_strategy = "fnv"
1661def string_function():
1662 pass
1663 "#;
1664
1665 let annotations = parser.parse_annotations(source).unwrap();
1666 assert_eq!(annotations.string_strategy, StringStrategy::ZeroCopy);
1667 assert_eq!(annotations.hash_strategy, HashStrategy::Fnv);
1668 }
1669
1670 #[test]
1671 fn test_parse_string_strategy_all_variants() {
1672 let parser = AnnotationParser::new();
1673 let cases = [
1674 ("conservative", StringStrategy::Conservative),
1675 ("always_owned", StringStrategy::AlwaysOwned),
1676 ("zero_copy", StringStrategy::ZeroCopy),
1677 ];
1678 for (input, expected) in &cases {
1679 let source = format!("# @depyler: string_strategy = \"{input}\"");
1680 let a = parser.parse_annotations(&source).unwrap();
1681 assert_eq!(a.string_strategy, *expected);
1682 }
1683 }
1684
1685 #[test]
1686 fn test_parse_hash_strategy_all_variants() {
1687 let parser = AnnotationParser::new();
1688 let cases = [
1689 ("standard", HashStrategy::Standard),
1690 ("fnv", HashStrategy::Fnv),
1691 ("ahash", HashStrategy::AHash),
1692 ];
1693 for (input, expected) in &cases {
1694 let source = format!("# @depyler: hash_strategy = \"{input}\"");
1695 let a = parser.parse_annotations(&source).unwrap();
1696 assert_eq!(a.hash_strategy, *expected);
1697 }
1698 }
1699
1700 #[test]
1705 fn test_error_handling_annotations() {
1706 let parser = AnnotationParser::new();
1707 let source = r#"
1708# @depyler: panic_behavior = "return_error"
1709# @depyler: error_strategy = "result_type"
1710def error_function():
1711 pass
1712 "#;
1713
1714 let annotations = parser.parse_annotations(source).unwrap();
1715 assert_eq!(annotations.panic_behavior, PanicBehavior::ReturnError);
1716 assert_eq!(annotations.error_strategy, ErrorStrategy::ResultType);
1717 }
1718
1719 #[test]
1720 fn test_parse_panic_behavior_all_variants() {
1721 let parser = AnnotationParser::new();
1722 let cases = [
1723 ("propagate", PanicBehavior::Propagate),
1724 ("return_error", PanicBehavior::ReturnError),
1725 ("abort", PanicBehavior::Abort),
1726 ];
1727 for (input, expected) in &cases {
1728 let source = format!("# @depyler: panic_behavior = \"{input}\"");
1729 let a = parser.parse_annotations(&source).unwrap();
1730 assert_eq!(a.panic_behavior, *expected);
1731 }
1732 }
1733
1734 #[test]
1735 fn test_parse_error_strategy_all_variants() {
1736 let parser = AnnotationParser::new();
1737 let cases = [
1738 ("panic", ErrorStrategy::Panic),
1739 ("result_type", ErrorStrategy::ResultType),
1740 ("option_type", ErrorStrategy::OptionType),
1741 ];
1742 for (input, expected) in &cases {
1743 let source = format!("# @depyler: error_strategy = \"{input}\"");
1744 let a = parser.parse_annotations(&source).unwrap();
1745 assert_eq!(a.error_strategy, *expected);
1746 }
1747 }
1748
1749 #[test]
1754 fn test_global_strategy() {
1755 let parser = AnnotationParser::new();
1756 let source = r#"
1757# @depyler: global_strategy = "lazy_static"
1758def global_function():
1759 pass
1760 "#;
1761
1762 let annotations = parser.parse_annotations(source).unwrap();
1763 assert_eq!(annotations.global_strategy, GlobalStrategy::LazyStatic);
1764 }
1765
1766 #[test]
1767 fn test_parse_global_strategy_all_variants() {
1768 let parser = AnnotationParser::new();
1769 let cases = [
1770 ("none", GlobalStrategy::None),
1771 ("lazy_static", GlobalStrategy::LazyStatic),
1772 ("once_cell", GlobalStrategy::OnceCell),
1773 ];
1774 for (input, expected) in &cases {
1775 let source = format!("# @depyler: global_strategy = \"{input}\"");
1776 let a = parser.parse_annotations(&source).unwrap();
1777 assert_eq!(a.global_strategy, *expected);
1778 }
1779 }
1780
1781 #[test]
1786 fn test_parse_termination_unknown() {
1787 let parser = AnnotationParser::new();
1788 let source = "# @depyler: termination = \"unknown\"";
1789 let a = parser.parse_annotations(source).unwrap();
1790 assert_eq!(a.termination, Termination::Unknown);
1791 }
1792
1793 #[test]
1794 fn test_parse_termination_proven() {
1795 let parser = AnnotationParser::new();
1796 let source = "# @depyler: termination = \"proven\"";
1797 let a = parser.parse_annotations(source).unwrap();
1798 assert_eq!(a.termination, Termination::Proven);
1799 }
1800
1801 #[test]
1802 fn test_parse_termination_bounded_loop() {
1803 let parser = AnnotationParser::new();
1804 let source = "# @depyler: termination = \"bounded_100\"";
1805 let a = parser.parse_annotations(source).unwrap();
1806 assert_eq!(a.termination, Termination::BoundedLoop(100));
1807 }
1808
1809 #[test]
1810 fn test_parse_termination_bounded_loop_zero() {
1811 let parser = AnnotationParser::new();
1812 let source = "# @depyler: termination = \"bounded_0\"";
1813 let a = parser.parse_annotations(source).unwrap();
1814 assert_eq!(a.termination, Termination::BoundedLoop(0));
1815 }
1816
1817 #[test]
1818 fn test_parse_termination_invalid() {
1819 let parser = AnnotationParser::new();
1820 let source = "# @depyler: termination = \"infinite\"";
1821 let result = parser.parse_annotations(source);
1822 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1823 }
1824
1825 #[test]
1826 fn test_parse_termination_bounded_non_numeric() {
1827 let parser = AnnotationParser::new();
1828 let source = "# @depyler: termination = \"bounded_abc\"";
1829 let result = parser.parse_annotations(source);
1830 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1831 }
1832
1833 #[test]
1838 fn test_verification_annotations() {
1839 let parser = AnnotationParser::new();
1840 let source = r#"
1841# @depyler: termination = "proven"
1842# @depyler: invariant = "left <= right"
1843# @depyler: verify_bounds = "true"
1844def verified_function():
1845 pass
1846 "#;
1847
1848 let annotations = parser.parse_annotations(source).unwrap();
1849 assert_eq!(annotations.termination, Termination::Proven);
1850 assert!(annotations
1851 .invariants
1852 .contains(&"left <= right".to_string()));
1853 assert!(annotations.verify_bounds);
1854 }
1855
1856 #[test]
1857 fn test_parse_verify_bounds_false() {
1858 let parser = AnnotationParser::new();
1859 let source = "# @depyler: verify_bounds = \"false\"";
1860 let a = parser.parse_annotations(source).unwrap();
1861 assert!(!a.verify_bounds);
1862 }
1863
1864 #[test]
1869 fn test_service_and_migration_annotations() {
1870 let parser = AnnotationParser::new();
1871 let source = r#"
1872# @depyler: service_type = "web_api"
1873# @depyler: migration_strategy = "incremental"
1874# @depyler: compatibility_layer = "pyo3"
1875def service_function():
1876 pass
1877 "#;
1878
1879 let annotations = parser.parse_annotations(source).unwrap();
1880 assert_eq!(annotations.service_type, Some(ServiceType::WebApi));
1881 assert_eq!(
1882 annotations.migration_strategy,
1883 Some(MigrationStrategy::Incremental)
1884 );
1885 assert_eq!(
1886 annotations.compatibility_layer,
1887 Some(CompatibilityLayer::PyO3)
1888 );
1889 }
1890
1891 #[test]
1892 fn test_parse_service_type_all_variants() {
1893 let parser = AnnotationParser::new();
1894 let cases = [
1895 ("web_api", ServiceType::WebApi),
1896 ("cli", ServiceType::Cli),
1897 ("library", ServiceType::Library),
1898 ];
1899 for (input, expected) in &cases {
1900 let source = format!("# @depyler: service_type = \"{input}\"");
1901 let a = parser.parse_annotations(&source).unwrap();
1902 assert_eq!(a.service_type, Some(expected.clone()));
1903 }
1904 }
1905
1906 #[test]
1907 fn test_parse_migration_strategy_all_variants() {
1908 let parser = AnnotationParser::new();
1909 let cases = [
1910 ("incremental", MigrationStrategy::Incremental),
1911 ("big_bang", MigrationStrategy::BigBang),
1912 ("hybrid", MigrationStrategy::Hybrid),
1913 ];
1914 for (input, expected) in &cases {
1915 let source = format!("# @depyler: migration_strategy = \"{input}\"");
1916 let a = parser.parse_annotations(&source).unwrap();
1917 assert_eq!(a.migration_strategy, Some(expected.clone()));
1918 }
1919 }
1920
1921 #[test]
1922 fn test_parse_compatibility_layer_all_variants() {
1923 let parser = AnnotationParser::new();
1924 let cases = [
1925 ("pyo3", CompatibilityLayer::PyO3),
1926 ("ctypes", CompatibilityLayer::CTypes),
1927 ("none", CompatibilityLayer::None),
1928 ];
1929 for (input, expected) in &cases {
1930 let source = format!("# @depyler: compatibility_layer = \"{input}\"");
1931 let a = parser.parse_annotations(&source).unwrap();
1932 assert_eq!(a.compatibility_layer, Some(expected.clone()));
1933 }
1934 }
1935
1936 #[test]
1937 fn test_parse_pattern_annotation() {
1938 let parser = AnnotationParser::new();
1939 let source = "# @depyler: pattern = \"observer\"";
1940 let a = parser.parse_annotations(source).unwrap();
1941 assert_eq!(a.pattern, Some("observer".to_string()));
1942 }
1943
1944 #[test]
1949 fn test_invalid_annotation_key() {
1950 let parser = AnnotationParser::new();
1951 let source = r#"
1952# @depyler: invalid_key = "value"
1953def test_function():
1954 pass
1955 "#;
1956
1957 let result = parser.parse_annotations(source);
1958 assert!(matches!(result, Err(AnnotationError::UnknownKey(_))));
1959 }
1960
1961 #[test]
1962 fn test_invalid_annotation_value() {
1963 let parser = AnnotationParser::new();
1964 let source = r#"
1965# @depyler: type_strategy = "invalid_value"
1966def test_function():
1967 pass
1968 "#;
1969
1970 let result = parser.parse_annotations(source);
1971 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
1972 }
1973
1974 #[test]
1975 fn test_annotation_error_display_invalid_syntax() {
1976 let err = AnnotationError::InvalidSyntax("bad line".to_string());
1977 let msg = format!("{err}");
1978 assert!(msg.contains("Invalid annotation syntax"));
1979 assert!(msg.contains("bad line"));
1980 }
1981
1982 #[test]
1983 fn test_annotation_error_display_unknown_key() {
1984 let err = AnnotationError::UnknownKey("foo_bar".to_string());
1985 let msg = format!("{err}");
1986 assert!(msg.contains("Unknown annotation key"));
1987 assert!(msg.contains("foo_bar"));
1988 }
1989
1990 #[test]
1991 fn test_annotation_error_display_invalid_value() {
1992 let err = AnnotationError::InvalidValue {
1993 key: "type_strategy".to_string(),
1994 value: "bogus".to_string(),
1995 };
1996 let msg = format!("{err}");
1997 assert!(msg.contains("Invalid value for key type_strategy"));
1998 assert!(msg.contains("bogus"));
1999 }
2000
2001 #[test]
2002 fn test_annotation_error_is_debug() {
2003 let err = AnnotationError::UnknownKey("test".to_string());
2004 let debug = format!("{err:?}");
2005 assert!(debug.contains("UnknownKey"));
2006 }
2007
2008 #[test]
2013 fn test_lambda_annotations_basic() {
2014 let parser = AnnotationParser::new();
2015 let source = r#"
2016# @depyler: lambda_runtime = "provided.al2"
2017# @depyler: event_type = "APIGatewayProxyRequest"
2018# @depyler: cold_start_optimize = "true"
2019def handler(event, context):
2020 pass
2021 "#;
2022
2023 let annotations = parser.parse_annotations(source).unwrap();
2024 assert!(annotations.lambda_annotations.is_some());
2025
2026 let lambda_annotations = annotations.lambda_annotations.unwrap();
2027 assert_eq!(lambda_annotations.runtime, LambdaRuntime::ProvidedAl2);
2028 assert_eq!(
2029 lambda_annotations.event_type,
2030 Some(LambdaEventType::ApiGatewayProxyRequest)
2031 );
2032 assert!(lambda_annotations.cold_start_optimize);
2033 }
2034
2035 #[test]
2036 fn test_lambda_annotations_memory_and_architecture() {
2037 let parser = AnnotationParser::new();
2038 let source = r#"
2039# @depyler: memory_size = "256"
2040# @depyler: architecture = "arm64"
2041# @depyler: timeout = "30"
2042def handler(event, context):
2043 pass
2044 "#;
2045
2046 let annotations = parser.parse_annotations(source).unwrap();
2047 let lambda_annotations = annotations.lambda_annotations.unwrap();
2048 assert_eq!(lambda_annotations.memory_size, 256);
2049 assert_eq!(lambda_annotations.architecture, Architecture::Arm64);
2050 assert_eq!(lambda_annotations.timeout, Some(30));
2051 }
2052
2053 #[test]
2054 fn test_lambda_eventbridge_with_custom_type() {
2055 let parser = AnnotationParser::new();
2056 let source = r#"
2057# @depyler: event_type = "EventBridgeEvent<OrderEvent>"
2058# @depyler: custom_serialization = "true"
2059def handler(event, context):
2060 pass
2061 "#;
2062
2063 let annotations = parser.parse_annotations(source).unwrap();
2064 let lambda_annotations = annotations.lambda_annotations.unwrap();
2065 assert_eq!(
2066 lambda_annotations.event_type,
2067 Some(LambdaEventType::EventBridgeEvent(Some(
2068 "OrderEvent".to_string()
2069 )))
2070 );
2071 assert!(lambda_annotations.custom_serialization);
2072 }
2073
2074 #[test]
2075 fn test_lambda_eventbridge_without_type_parameter() {
2076 let parser = AnnotationParser::new();
2077 let source = "# @depyler: event_type = \"EventBridgeEvent\"";
2078 let a = parser.parse_annotations(source).unwrap();
2079 let la = a.lambda_annotations.unwrap();
2080 assert_eq!(
2081 la.event_type,
2082 Some(LambdaEventType::EventBridgeEvent(None))
2083 );
2084 }
2085
2086 #[test]
2087 fn test_lambda_sqs_batch_processing() {
2088 let parser = AnnotationParser::new();
2089 let source = r#"
2090# @depyler: event_type = "SqsEvent"
2091# @depyler: batch_failure_reporting = "true"
2092# @depyler: tracing = "Active"
2093def handler(event, context):
2094 pass
2095 "#;
2096
2097 let annotations = parser.parse_annotations(source).unwrap();
2098 let lambda_annotations = annotations.lambda_annotations.unwrap();
2099 assert_eq!(
2100 lambda_annotations.event_type,
2101 Some(LambdaEventType::SqsEvent)
2102 );
2103 assert!(lambda_annotations.batch_failure_reporting);
2104 assert!(lambda_annotations.tracing_enabled);
2105 }
2106
2107 #[test]
2108 fn test_lambda_auto_event_type() {
2109 let parser = AnnotationParser::new();
2110 let source = r#"
2111# @depyler: event_type = "auto"
2112# @depyler: cold_start_optimize = "true"
2113def handler(event, context):
2114 pass
2115 "#;
2116
2117 let annotations = parser.parse_annotations(source).unwrap();
2118 let lambda_annotations = annotations.lambda_annotations.unwrap();
2119 assert_eq!(lambda_annotations.event_type, Some(LambdaEventType::Auto));
2120 assert!(lambda_annotations.cold_start_optimize);
2121 }
2122
2123 #[test]
2124 fn test_lambda_custom_runtime() {
2125 let parser = AnnotationParser::new();
2126 let source = r#"
2127# @depyler: lambda_runtime = "rust-runtime-1.0"
2128def handler(event, context):
2129 pass
2130 "#;
2131
2132 let annotations = parser.parse_annotations(source).unwrap();
2133 let lambda_annotations = annotations.lambda_annotations.unwrap();
2134 assert_eq!(
2135 lambda_annotations.runtime,
2136 LambdaRuntime::Custom("rust-runtime-1.0".to_string())
2137 );
2138 }
2139
2140 #[test]
2141 fn test_lambda_runtime_provided_al2023() {
2142 let parser = AnnotationParser::new();
2143 let source = "# @depyler: lambda_runtime = \"provided.al2023\"";
2144 let a = parser.parse_annotations(source).unwrap();
2145 let la = a.lambda_annotations.unwrap();
2146 assert_eq!(la.runtime, LambdaRuntime::ProvidedAl2023);
2147 }
2148
2149 #[test]
2150 fn test_lambda_architecture_x86_64() {
2151 let parser = AnnotationParser::new();
2152 let source = "# @depyler: architecture = \"x86_64\"";
2153 let a = parser.parse_annotations(source).unwrap();
2154 let la = a.lambda_annotations.unwrap();
2155 assert_eq!(la.architecture, Architecture::X86_64);
2156 }
2157
2158 #[test]
2159 fn test_lambda_architecture_x64_alias() {
2160 let parser = AnnotationParser::new();
2161 let source = "# @depyler: architecture = \"x64\"";
2162 let a = parser.parse_annotations(source).unwrap();
2163 let la = a.lambda_annotations.unwrap();
2164 assert_eq!(la.architecture, Architecture::X86_64);
2165 }
2166
2167 #[test]
2168 fn test_lambda_architecture_aarch64_alias() {
2169 let parser = AnnotationParser::new();
2170 let source = "# @depyler: architecture = \"aarch64\"";
2171 let a = parser.parse_annotations(source).unwrap();
2172 let la = a.lambda_annotations.unwrap();
2173 assert_eq!(la.architecture, Architecture::Arm64);
2174 }
2175
2176 #[test]
2177 fn test_lambda_architecture_invalid() {
2178 let parser = AnnotationParser::new();
2179 let source = "# @depyler: architecture = \"mips\"";
2180 let result = parser.parse_annotations(source);
2181 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
2182 }
2183
2184 #[test]
2185 fn test_lambda_memory_size_invalid() {
2186 let parser = AnnotationParser::new();
2187 let source = "# @depyler: memory_size = \"lots\"";
2188 let result = parser.parse_annotations(source);
2189 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
2190 }
2191
2192 #[test]
2193 fn test_lambda_timeout_invalid() {
2194 let parser = AnnotationParser::new();
2195 let source = "# @depyler: timeout = \"forever\"";
2196 let result = parser.parse_annotations(source);
2197 assert!(matches!(result, Err(AnnotationError::InvalidValue { .. })));
2198 }
2199
2200 #[test]
2201 fn test_lambda_tracing_true() {
2202 let parser = AnnotationParser::new();
2203 let source = "# @depyler: tracing = \"true\"";
2204 let a = parser.parse_annotations(source).unwrap();
2205 let la = a.lambda_annotations.unwrap();
2206 assert!(la.tracing_enabled);
2207 }
2208
2209 #[test]
2210 fn test_lambda_tracing_false() {
2211 let parser = AnnotationParser::new();
2212 let source = "# @depyler: tracing = \"false\"";
2213 let a = parser.parse_annotations(source).unwrap();
2214 let la = a.lambda_annotations.unwrap();
2215 assert!(!la.tracing_enabled);
2216 }
2217
2218 #[test]
2219 fn test_lambda_cold_start_optimize_false() {
2220 let parser = AnnotationParser::new();
2221 let source = "# @depyler: cold_start_optimize = \"false\"";
2222 let a = parser.parse_annotations(source).unwrap();
2223 let la = a.lambda_annotations.unwrap();
2224 assert!(!la.cold_start_optimize);
2225 }
2226
2227 #[test]
2228 fn test_lambda_event_type_s3() {
2229 let parser = AnnotationParser::new();
2230 let source = "# @depyler: event_type = \"S3Event\"";
2231 let a = parser.parse_annotations(source).unwrap();
2232 let la = a.lambda_annotations.unwrap();
2233 assert_eq!(la.event_type, Some(LambdaEventType::S3Event));
2234 }
2235
2236 #[test]
2237 fn test_lambda_event_type_sns() {
2238 let parser = AnnotationParser::new();
2239 let source = "# @depyler: event_type = \"SnsEvent\"";
2240 let a = parser.parse_annotations(source).unwrap();
2241 let la = a.lambda_annotations.unwrap();
2242 assert_eq!(la.event_type, Some(LambdaEventType::SnsEvent));
2243 }
2244
2245 #[test]
2246 fn test_lambda_event_type_dynamodb() {
2247 let parser = AnnotationParser::new();
2248 let source = "# @depyler: event_type = \"DynamodbEvent\"";
2249 let a = parser.parse_annotations(source).unwrap();
2250 let la = a.lambda_annotations.unwrap();
2251 assert_eq!(la.event_type, Some(LambdaEventType::DynamodbEvent));
2252 }
2253
2254 #[test]
2255 fn test_lambda_event_type_cloudwatch() {
2256 let parser = AnnotationParser::new();
2257 let source = "# @depyler: event_type = \"CloudwatchEvent\"";
2258 let a = parser.parse_annotations(source).unwrap();
2259 let la = a.lambda_annotations.unwrap();
2260 assert_eq!(la.event_type, Some(LambdaEventType::CloudwatchEvent));
2261 }
2262
2263 #[test]
2264 fn test_lambda_event_type_kinesis() {
2265 let parser = AnnotationParser::new();
2266 let source = "# @depyler: event_type = \"KinesisEvent\"";
2267 let a = parser.parse_annotations(source).unwrap();
2268 let la = a.lambda_annotations.unwrap();
2269 assert_eq!(la.event_type, Some(LambdaEventType::KinesisEvent));
2270 }
2271
2272 #[test]
2273 fn test_lambda_event_type_api_gateway_v2() {
2274 let parser = AnnotationParser::new();
2275 let source = "# @depyler: event_type = \"APIGatewayV2HttpRequest\"";
2276 let a = parser.parse_annotations(source).unwrap();
2277 let la = a.lambda_annotations.unwrap();
2278 assert_eq!(
2279 la.event_type,
2280 Some(LambdaEventType::ApiGatewayV2HttpRequest)
2281 );
2282 }
2283
2284 #[test]
2285 fn test_lambda_event_type_custom() {
2286 let parser = AnnotationParser::new();
2287 let source = "# @depyler: event_type = \"MyCustomEvent\"";
2288 let a = parser.parse_annotations(source).unwrap();
2289 let la = a.lambda_annotations.unwrap();
2290 assert_eq!(
2291 la.event_type,
2292 Some(LambdaEventType::Custom("MyCustomEvent".to_string()))
2293 );
2294 }
2295
2296 #[test]
2301 fn test_custom_custom_attribute_single() {
2302 let parser = AnnotationParser::new();
2303 let source = r#"
2304# @depyler: custom_attribute = "inline"
2305def my_function():
2306 pass
2307 "#;
2308
2309 let annotations = parser.parse_annotations(source).unwrap();
2310 assert_eq!(annotations.custom_attributes.len(), 1);
2311 assert_eq!(annotations.custom_attributes[0], "inline");
2312 }
2313
2314 #[test]
2315 fn test_custom_custom_attribute_multiple() {
2316 let parser = AnnotationParser::new();
2317 let source = r#"
2318# @depyler: custom_attribute = "inline"
2319# @depyler: custom_attribute = "must_use"
2320# @depyler: custom_attribute = "cold"
2321def my_function():
2322 pass
2323 "#;
2324
2325 let annotations = parser.parse_annotations(source).unwrap();
2326 assert_eq!(annotations.custom_attributes.len(), 3);
2327 assert_eq!(annotations.custom_attributes[0], "inline");
2328 assert_eq!(annotations.custom_attributes[1], "must_use");
2329 assert_eq!(annotations.custom_attributes[2], "cold");
2330 }
2331
2332 #[test]
2333 fn test_custom_custom_attribute_with_other_annotations() {
2334 let parser = AnnotationParser::new();
2335 let source = r#"
2336# @depyler: optimization_level = "aggressive"
2337# @depyler: custom_attribute = "inline(always)"
2338# @depyler: performance_critical = "true"
2339def hot_function():
2340 pass
2341 "#;
2342
2343 let annotations = parser.parse_annotations(source).unwrap();
2344 assert_eq!(
2345 annotations.optimization_level,
2346 OptimizationLevel::Aggressive
2347 );
2348 assert_eq!(annotations.custom_attributes.len(), 1);
2349 assert_eq!(annotations.custom_attributes[0], "inline(always)");
2350 assert!(annotations
2351 .performance_hints
2352 .contains(&PerformanceHint::PerformanceCritical));
2353 }
2354
2355 #[test]
2356 fn test_custom_custom_attribute_empty() {
2357 let parser = AnnotationParser::new();
2358 let source = r#"
2359def my_function():
2360 pass
2361 "#;
2362
2363 let annotations = parser.parse_annotations(source).unwrap();
2364 assert_eq!(annotations.custom_attributes.len(), 0);
2365 }
2366
2367 #[test]
2372 fn test_validator_new() {
2373 let v = AnnotationValidator::new();
2374 let a = TranspilationAnnotations::default();
2375 assert!(v.validate(&a).is_ok());
2376 }
2377
2378 #[test]
2379 fn test_validator_zero_copy_string_with_owned_conflict() {
2380 let v = AnnotationValidator::new();
2381 let a = TranspilationAnnotations {
2382 string_strategy: StringStrategy::ZeroCopy,
2383 ownership_model: OwnershipModel::Owned,
2384 ..Default::default()
2385 };
2386 let result = v.validate(&a);
2387 assert!(result.is_err());
2388 let errors = result.unwrap_err();
2389 assert!(errors
2390 .iter()
2391 .any(|e| e.contains("Zero-copy string strategy")));
2392 }
2393
2394 #[test]
2395 fn test_validator_refcell_with_thread_safety_conflict() {
2396 let v = AnnotationValidator::new();
2397 let a = TranspilationAnnotations {
2398 thread_safety: ThreadSafety::Required,
2399 interior_mutability: InteriorMutability::RefCell,
2400 ..Default::default()
2401 };
2402 let result = v.validate(&a);
2403 assert!(result.is_err());
2404 let errors = result.unwrap_err();
2405 assert!(errors.iter().any(|e| e.contains("RefCell is not thread-safe")));
2406 }
2407
2408 #[test]
2409 fn test_validator_conflicting_panic_and_error_strategy() {
2410 let v = AnnotationValidator::new();
2411 let a = TranspilationAnnotations {
2412 panic_behavior: PanicBehavior::ReturnError,
2413 error_strategy: ErrorStrategy::Panic,
2414 ..Default::default()
2415 };
2416 let result = v.validate(&a);
2417 assert!(result.is_err());
2418 let errors = result.unwrap_err();
2419 assert!(errors
2420 .iter()
2421 .any(|e| e.contains("Conflicting panic behavior")));
2422 }
2423
2424 #[test]
2425 fn test_validator_aggressive_opt_with_explicit_bounds_conflict() {
2426 let v = AnnotationValidator::new();
2427 let a = TranspilationAnnotations {
2428 optimization_level: OptimizationLevel::Aggressive,
2429 bounds_checking: BoundsChecking::Explicit,
2430 ..Default::default()
2431 };
2432 let result = v.validate(&a);
2433 assert!(result.is_err());
2434 let errors = result.unwrap_err();
2435 assert!(errors
2436 .iter()
2437 .any(|e| e.contains("Aggressive optimization")));
2438 }
2439
2440 #[test]
2441 fn test_validator_multiple_conflicts() {
2442 let v = AnnotationValidator::new();
2443 let a = TranspilationAnnotations {
2444 string_strategy: StringStrategy::ZeroCopy,
2445 ownership_model: OwnershipModel::Owned,
2446 thread_safety: ThreadSafety::Required,
2447 interior_mutability: InteriorMutability::RefCell,
2448 ..Default::default()
2449 };
2450 let result = v.validate(&a);
2451 assert!(result.is_err());
2452 let errors = result.unwrap_err();
2453 assert!(errors.len() >= 2);
2454 }
2455
2456 #[test]
2457 fn test_validator_no_conflict_with_valid_combination() {
2458 let v = AnnotationValidator::new();
2459 let a = TranspilationAnnotations {
2460 string_strategy: StringStrategy::AlwaysOwned,
2461 ownership_model: OwnershipModel::Owned,
2462 thread_safety: ThreadSafety::Required,
2463 interior_mutability: InteriorMutability::ArcMutex,
2464 ..Default::default()
2465 };
2466 assert!(v.validate(&a).is_ok());
2467 }
2468
2469 #[test]
2474 fn test_suggest_improvements_perf_critical_not_aggressive() {
2475 let v = AnnotationValidator::new();
2476 let a = TranspilationAnnotations {
2477 performance_hints: vec![PerformanceHint::PerformanceCritical],
2478 optimization_level: OptimizationLevel::Standard,
2479 ..Default::default()
2480 };
2481 let suggestions = v.suggest_improvements(&a);
2482 assert!(suggestions.iter().any(|s| s.contains("aggressive")));
2483 }
2484
2485 #[test]
2486 fn test_suggest_improvements_thread_safe_not_shared() {
2487 let v = AnnotationValidator::new();
2488 let a = TranspilationAnnotations {
2489 thread_safety: ThreadSafety::Required,
2490 ownership_model: OwnershipModel::Owned,
2491 ..Default::default()
2492 };
2493 let suggestions = v.suggest_improvements(&a);
2494 assert!(suggestions.iter().any(|s| s.contains("shared")));
2495 }
2496
2497 #[test]
2498 fn test_suggest_improvements_web_api_no_latency() {
2499 let v = AnnotationValidator::new();
2500 let a = TranspilationAnnotations {
2501 service_type: Some(ServiceType::WebApi),
2502 ..Default::default()
2503 };
2504 let suggestions = v.suggest_improvements(&a);
2505 assert!(suggestions.iter().any(|s| s.contains("latency")));
2506 }
2507
2508 #[test]
2509 fn test_suggest_improvements_none_when_optimal() {
2510 let v = AnnotationValidator::new();
2511 let a = TranspilationAnnotations::default();
2512 let suggestions = v.suggest_improvements(&a);
2513 assert!(suggestions.is_empty());
2514 }
2515
2516 #[test]
2517 fn test_suggest_improvements_web_api_with_latency_no_suggestion() {
2518 let v = AnnotationValidator::new();
2519 let a = TranspilationAnnotations {
2520 service_type: Some(ServiceType::WebApi),
2521 performance_hints: vec![PerformanceHint::OptimizeForLatency],
2522 ..Default::default()
2523 };
2524 let suggestions = v.suggest_improvements(&a);
2525 assert!(!suggestions.iter().any(|s| s.contains("latency")));
2526 }
2527
2528 #[test]
2533 fn test_extractor_new() {
2534 let e = AnnotationExtractor::new();
2535 let result = e.extract_function_annotations("def foo():\n pass", "bar");
2536 assert!(result.is_none());
2537 }
2538
2539 #[test]
2540 fn test_extractor_function_with_annotation() {
2541 let e = AnnotationExtractor::new();
2542 let source = "# @depyler: ownership = \"borrowed\"\ndef my_func(x):\n return x";
2543 let result = e.extract_function_annotations(source, "my_func");
2544 assert!(result.is_some());
2545 assert!(result.unwrap().contains("@depyler:"));
2546 }
2547
2548 #[test]
2549 fn test_extractor_function_no_annotation() {
2550 let e = AnnotationExtractor::new();
2551 let source = "# just a regular comment\ndef my_func(x):\n return x";
2552 let result = e.extract_function_annotations(source, "my_func");
2553 assert!(result.is_none());
2554 }
2555
2556 #[test]
2557 fn test_extractor_function_not_found() {
2558 let e = AnnotationExtractor::new();
2559 let source = "# @depyler: ownership = \"borrowed\"\ndef foo():\n pass";
2560 let result = e.extract_function_annotations(source, "bar");
2561 assert!(result.is_none());
2562 }
2563
2564 #[test]
2565 fn test_extractor_class_with_annotation() {
2566 let e = AnnotationExtractor::new();
2567 let source = "# @depyler: service_type = \"web_api\"\nclass MyService:\n pass";
2568 let result = e.extract_class_annotations(source, "MyService");
2569 assert!(result.is_some());
2570 assert!(result.unwrap().contains("@depyler:"));
2571 }
2572
2573 #[test]
2574 fn test_extractor_class_no_annotation() {
2575 let e = AnnotationExtractor::new();
2576 let source = "# regular comment\nclass MyClass:\n pass";
2577 let result = e.extract_class_annotations(source, "MyClass");
2578 assert!(result.is_none());
2579 }
2580
2581 #[test]
2582 fn test_extractor_class_not_found() {
2583 let e = AnnotationExtractor::new();
2584 let source = "# @depyler: ownership = \"borrowed\"\nclass Foo:\n pass";
2585 let result = e.extract_class_annotations(source, "Bar");
2586 assert!(result.is_none());
2587 }
2588
2589 #[test]
2590 fn test_extractor_class_with_parentheses() {
2591 let e = AnnotationExtractor::new();
2592 let source = "# @depyler: ownership = \"shared\"\nclass Child(Parent):\n pass";
2593 let result = e.extract_class_annotations(source, "Child");
2594 assert!(result.is_some());
2595 }
2596
2597 #[test]
2602 fn test_serialize_transpilation_annotations() {
2603 let a = TranspilationAnnotations::default();
2604 let json = serde_json::to_string(&a).unwrap();
2605 assert!(json.contains("Conservative"));
2606 assert!(json.contains("Owned"));
2607 }
2608
2609 #[test]
2610 fn test_deserialize_transpilation_annotations() {
2611 let a = TranspilationAnnotations::default();
2612 let json = serde_json::to_string(&a).unwrap();
2613 let deserialized: TranspilationAnnotations = serde_json::from_str(&json).unwrap();
2614 assert_eq!(a, deserialized);
2615 }
2616
2617 #[test]
2618 fn test_serialize_lambda_annotations() {
2619 let la = LambdaAnnotations::default();
2620 let json = serde_json::to_string(&la).unwrap();
2621 assert!(json.contains("ProvidedAl2"));
2622 assert!(json.contains("Arm64"));
2623 }
2624
2625 #[test]
2626 fn test_deserialize_lambda_annotations() {
2627 let la = LambdaAnnotations::default();
2628 let json = serde_json::to_string(&la).unwrap();
2629 let deserialized: LambdaAnnotations = serde_json::from_str(&json).unwrap();
2630 assert_eq!(la, deserialized);
2631 }
2632
2633 #[test]
2634 fn test_serialize_roundtrip_all_event_types() {
2635 let event_types = vec![
2636 LambdaEventType::Auto,
2637 LambdaEventType::S3Event,
2638 LambdaEventType::ApiGatewayProxyRequest,
2639 LambdaEventType::ApiGatewayV2HttpRequest,
2640 LambdaEventType::SqsEvent,
2641 LambdaEventType::SnsEvent,
2642 LambdaEventType::DynamodbEvent,
2643 LambdaEventType::EventBridgeEvent(None),
2644 LambdaEventType::EventBridgeEvent(Some("Order".to_string())),
2645 LambdaEventType::CloudwatchEvent,
2646 LambdaEventType::KinesisEvent,
2647 LambdaEventType::Custom("MyEvent".to_string()),
2648 ];
2649 for et in event_types {
2650 let json = serde_json::to_string(&et).unwrap();
2651 let deserialized: LambdaEventType = serde_json::from_str(&json).unwrap();
2652 assert_eq!(et, deserialized);
2653 }
2654 }
2655
2656 #[test]
2657 fn test_serialize_roundtrip_with_lambda_annotations() {
2658 let la = LambdaAnnotations {
2659 event_type: Some(LambdaEventType::SqsEvent),
2660 memory_size: 512,
2661 timeout: Some(60),
2662 tracing_enabled: true,
2663 batch_failure_reporting: true,
2664 ..Default::default()
2665 };
2666 let a = TranspilationAnnotations {
2667 lambda_annotations: Some(la),
2668 service_type: Some(ServiceType::WebApi),
2669 pattern: Some("microservice".to_string()),
2670 ..Default::default()
2671 };
2672
2673 let json = serde_json::to_string(&a).unwrap();
2674 let deserialized: TranspilationAnnotations = serde_json::from_str(&json).unwrap();
2675 assert_eq!(a, deserialized);
2676 }
2677
2678 #[test]
2683 fn test_transpilation_annotations_clone() {
2684 let a = TranspilationAnnotations {
2685 type_strategy: TypeStrategy::Aggressive,
2686 invariants: vec!["x > 0".to_string()],
2687 ..Default::default()
2688 };
2689 let b = a.clone();
2690 assert_eq!(a, b);
2691 }
2692
2693 #[test]
2694 fn test_lambda_annotations_clone() {
2695 let la = LambdaAnnotations {
2696 memory_size: 1024,
2697 event_type: Some(LambdaEventType::S3Event),
2698 ..Default::default()
2699 };
2700 let cloned = la.clone();
2701 assert_eq!(la, cloned);
2702 }
2703
2704 #[test]
2705 fn test_annotation_extractor_clone() {
2706 let e = AnnotationExtractor::new();
2707 let _cloned = e.clone();
2708 }
2710
2711 #[test]
2712 fn test_annotation_parser_new_and_default_equivalent() {
2713 let p1 = AnnotationParser::new();
2714 let p2 = AnnotationParser::default();
2715 let source = "# @depyler: ownership = \"shared\"";
2717 let a1 = p1.parse_annotations(source).unwrap();
2718 let a2 = p2.parse_annotations(source).unwrap();
2719 assert_eq!(a1, a2);
2720 }
2721
2722 #[test]
2723 fn test_annotation_validator_debug() {
2724 let v = AnnotationValidator::new();
2725 let debug_str = format!("{v:?}");
2726 assert!(debug_str.contains("AnnotationValidator"));
2727 }
2728
2729 #[test]
2730 fn test_annotation_extractor_debug() {
2731 let e = AnnotationExtractor::new();
2732 let debug_str = format!("{e:?}");
2733 assert!(debug_str.contains("AnnotationExtractor"));
2734 }
2735
2736 #[test]
2741 fn test_lambda_event_type_hash_in_collections() {
2742 use std::collections::HashSet;
2743 let mut set = HashSet::new();
2744 set.insert(LambdaEventType::Auto);
2745 set.insert(LambdaEventType::S3Event);
2746 set.insert(LambdaEventType::Auto); assert_eq!(set.len(), 2);
2748 }
2749
2750 #[test]
2751 fn test_enum_equality() {
2752 assert_eq!(TypeStrategy::Conservative, TypeStrategy::Conservative);
2753 assert_ne!(TypeStrategy::Conservative, TypeStrategy::Aggressive);
2754 assert_eq!(OwnershipModel::Owned, OwnershipModel::Owned);
2755 assert_ne!(OwnershipModel::Owned, OwnershipModel::Borrowed);
2756 assert_eq!(
2757 Termination::BoundedLoop(10),
2758 Termination::BoundedLoop(10)
2759 );
2760 assert_ne!(Termination::BoundedLoop(10), Termination::BoundedLoop(20));
2761 }
2762
2763 #[test]
2768 fn test_parse_annotation_with_extra_whitespace_before_key() {
2769 let parser = AnnotationParser::new();
2770 let source = "# @depyler: ownership = \"shared\"";
2772 let a = parser.parse_annotations(source).unwrap();
2773 assert_eq!(a.ownership_model, OwnershipModel::Shared);
2774 }
2775
2776 #[test]
2777 fn test_parse_annotation_mixed_with_plain_comments() {
2778 let parser = AnnotationParser::new();
2779 let source = r#"
2780# This is a regular comment
2781# @depyler: ownership = "borrowed"
2782# Another plain comment
2783def foo():
2784 pass
2785 "#;
2786 let a = parser.parse_annotations(source).unwrap();
2787 assert_eq!(a.ownership_model, OwnershipModel::Borrowed);
2788 }
2789
2790 #[test]
2791 fn test_parse_all_annotations_combined() {
2792 let parser = AnnotationParser::new();
2793 let source = r#"
2794# @depyler: type_strategy = "aggressive"
2795# @depyler: ownership = "shared"
2796# @depyler: safety_level = "unsafe_allowed"
2797# @depyler: fallback = "manual"
2798# @depyler: bounds_checking = "implicit"
2799# @depyler: optimization_level = "conservative"
2800# @depyler: thread_safety = "required"
2801# @depyler: interior_mutability = "arc_mutex"
2802# @depyler: string_strategy = "always_owned"
2803# @depyler: hash_strategy = "ahash"
2804# @depyler: panic_behavior = "abort"
2805# @depyler: error_strategy = "option_type"
2806# @depyler: global_strategy = "once_cell"
2807# @depyler: termination = "bounded_50"
2808# @depyler: verify_bounds = "true"
2809# @depyler: service_type = "cli"
2810# @depyler: migration_strategy = "hybrid"
2811# @depyler: compatibility_layer = "ctypes"
2812# @depyler: pattern = "singleton"
2813def full_function():
2814 pass
2815 "#;
2816
2817 let a = parser.parse_annotations(source).unwrap();
2818 assert_eq!(a.type_strategy, TypeStrategy::Aggressive);
2819 assert_eq!(a.ownership_model, OwnershipModel::Shared);
2820 assert_eq!(a.safety_level, SafetyLevel::UnsafeAllowed);
2821 assert_eq!(a.fallback_strategy, FallbackStrategy::Manual);
2822 assert_eq!(a.bounds_checking, BoundsChecking::Implicit);
2823 assert_eq!(a.optimization_level, OptimizationLevel::Conservative);
2824 assert_eq!(a.thread_safety, ThreadSafety::Required);
2825 assert_eq!(a.interior_mutability, InteriorMutability::ArcMutex);
2826 assert_eq!(a.string_strategy, StringStrategy::AlwaysOwned);
2827 assert_eq!(a.hash_strategy, HashStrategy::AHash);
2828 assert_eq!(a.panic_behavior, PanicBehavior::Abort);
2829 assert_eq!(a.error_strategy, ErrorStrategy::OptionType);
2830 assert_eq!(a.global_strategy, GlobalStrategy::OnceCell);
2831 assert_eq!(a.termination, Termination::BoundedLoop(50));
2832 assert!(a.verify_bounds);
2833 assert_eq!(a.service_type, Some(ServiceType::Cli));
2834 assert_eq!(a.migration_strategy, Some(MigrationStrategy::Hybrid));
2835 assert_eq!(a.compatibility_layer, Some(CompatibilityLayer::CTypes));
2836 assert_eq!(a.pattern, Some("singleton".to_string()));
2837 }
2838
2839 #[test]
2840 fn test_parse_only_comments_no_depyler_prefix() {
2841 let parser = AnnotationParser::new();
2842 let source = "# just a comment\n# another one\n";
2843 let a = parser.parse_annotations(source).unwrap();
2844 assert_eq!(a, TranspilationAnnotations::default());
2845 }
2846
2847 #[test]
2848 fn test_extractor_function_at_first_line() {
2849 let e = AnnotationExtractor::new();
2850 let source = "def first_func():\n pass";
2851 let result = e.extract_function_annotations(source, "first_func");
2852 assert!(result.is_none());
2853 }
2854
2855 #[test]
2856 fn test_extractor_empty_source() {
2857 let e = AnnotationExtractor::new();
2858 let result = e.extract_function_annotations("", "anything");
2859 assert!(result.is_none());
2860 }
2861
2862 #[test]
2863 fn test_extractor_class_empty_source() {
2864 let e = AnnotationExtractor::new();
2865 let result = e.extract_class_annotations("", "anything");
2866 assert!(result.is_none());
2867 }
2868
2869 #[test]
2874 fn test_s9b7_annotation_error_display_invalid_syntax() {
2875 let err = AnnotationError::InvalidSyntax("bad format".to_string());
2876 assert_eq!(err.to_string(), "Invalid annotation syntax: bad format");
2877 }
2878
2879 #[test]
2880 fn test_s9b7_annotation_error_display_unknown_key() {
2881 let err = AnnotationError::UnknownKey("foobar".to_string());
2882 assert_eq!(err.to_string(), "Unknown annotation key: foobar");
2883 }
2884
2885 #[test]
2886 fn test_s9b7_annotation_error_display_invalid_value() {
2887 let err = AnnotationError::InvalidValue {
2888 key: "type_strategy".to_string(),
2889 value: "bad_val".to_string(),
2890 };
2891 let msg = err.to_string();
2892 assert!(msg.contains("type_strategy"));
2893 assert!(msg.contains("bad_val"));
2894 }
2895
2896 #[test]
2897 fn test_s9b7_annotation_error_debug() {
2898 let err = AnnotationError::UnknownKey("x".to_string());
2899 let debug = format!("{err:?}");
2900 assert!(debug.contains("UnknownKey"));
2901 }
2902
2903 #[test]
2904 fn test_s9b7_validator_no_conflicts_default() {
2905 let validator = AnnotationValidator::new();
2906 let annotations = TranspilationAnnotations::default();
2907 assert!(validator.validate(&annotations).is_ok());
2908 }
2909
2910 #[test]
2911 fn test_s9b7_validator_thread_safety_refcell_conflict() {
2912 let validator = AnnotationValidator::new();
2913 let annotations = TranspilationAnnotations {
2914 thread_safety: ThreadSafety::Required,
2915 interior_mutability: InteriorMutability::RefCell,
2916 ..Default::default()
2917 };
2918 let result = validator.validate(&annotations);
2919 assert!(result.is_err());
2920 let errors = result.unwrap_err();
2921 assert!(errors.iter().any(|e| e.contains("RefCell")));
2922 }
2923
2924 #[test]
2925 fn test_s9b7_validator_panic_error_conflict() {
2926 let validator = AnnotationValidator::new();
2927 let annotations = TranspilationAnnotations {
2928 panic_behavior: PanicBehavior::ReturnError,
2929 error_strategy: ErrorStrategy::Panic,
2930 ..Default::default()
2931 };
2932 let result = validator.validate(&annotations);
2933 assert!(result.is_err());
2934 let errors = result.unwrap_err();
2935 assert!(errors.iter().any(|e| e.contains("Conflicting panic")));
2936 }
2937
2938 #[test]
2939 fn test_s9b7_validator_aggressive_opt_bounds_conflict() {
2940 let validator = AnnotationValidator::new();
2941 let annotations = TranspilationAnnotations {
2942 optimization_level: OptimizationLevel::Aggressive,
2943 bounds_checking: BoundsChecking::Explicit,
2944 ..Default::default()
2945 };
2946 let result = validator.validate(&annotations);
2947 assert!(result.is_err());
2948 let errors = result.unwrap_err();
2949 assert!(errors.iter().any(|e| e.contains("bounds checking")));
2950 }
2951
2952 #[test]
2953 fn test_s9b7_suggest_improvements_performance_critical() {
2954 let validator = AnnotationValidator::new();
2955 let mut annotations = TranspilationAnnotations::default();
2956 annotations
2957 .performance_hints
2958 .push(PerformanceHint::PerformanceCritical);
2959 let suggestions = validator.suggest_improvements(&annotations);
2960 assert!(suggestions.iter().any(|s| s.contains("aggressive")));
2961 }
2962
2963 #[test]
2964 fn test_s9b7_suggest_improvements_thread_safety_shared() {
2965 let validator = AnnotationValidator::new();
2966 let annotations = TranspilationAnnotations {
2967 thread_safety: ThreadSafety::Required,
2968 ownership_model: OwnershipModel::Owned,
2969 ..Default::default()
2970 };
2971 let suggestions = validator.suggest_improvements(&annotations);
2972 assert!(suggestions.iter().any(|s| s.contains("shared")));
2973 }
2974
2975 #[test]
2976 fn test_s9b7_suggest_improvements_web_api_latency() {
2977 let validator = AnnotationValidator::new();
2978 let annotations = TranspilationAnnotations {
2979 service_type: Some(ServiceType::WebApi),
2980 ..Default::default()
2981 };
2982 let suggestions = validator.suggest_improvements(&annotations);
2983 assert!(suggestions.iter().any(|s| s.contains("latency")));
2984 }
2985
2986 #[test]
2987 fn test_s9b7_suggest_improvements_no_suggestions() {
2988 let validator = AnnotationValidator::new();
2989 let annotations = TranspilationAnnotations::default();
2990 let suggestions = validator.suggest_improvements(&annotations);
2991 assert!(suggestions.is_empty());
2992 }
2993
2994 #[test]
2995 fn test_s9b7_lambda_annotations_default() {
2996 let la = LambdaAnnotations::default();
2997 assert!(matches!(la.runtime, LambdaRuntime::ProvidedAl2));
2998 assert!(la.event_type.is_none());
2999 assert!(la.cold_start_optimize);
3000 assert_eq!(la.memory_size, 128);
3001 assert!(matches!(la.architecture, Architecture::Arm64));
3002 assert!(!la.custom_serialization);
3003 assert!(!la.batch_failure_reporting);
3004 assert!(la.timeout.is_none());
3005 assert!(!la.tracing_enabled);
3006 assert!(la.environment_variables.is_empty());
3007 }
3008
3009 #[test]
3010 fn test_s9b7_parse_termination_bounded_loop() {
3011 let parser = AnnotationParser::new();
3012 let source = "# @depyler: termination = bounded_100\n";
3013 let annotations = parser.parse_annotations(source).unwrap();
3014 assert_eq!(annotations.termination, Termination::BoundedLoop(100));
3015 }
3016
3017 #[test]
3018 fn test_s9b7_parse_termination_invalid() {
3019 let parser = AnnotationParser::new();
3020 let source = "# @depyler: termination = bounded_abc\n";
3021 let result = parser.parse_annotations(source);
3022 assert!(result.is_err());
3023 }
3024
3025 #[test]
3026 fn test_s9b7_parse_invariant() {
3027 let parser = AnnotationParser::new();
3028 let source = "# @depyler: invariant = x_greater_zero\n";
3029 let annotations = parser.parse_annotations(source).unwrap();
3030 assert!(annotations.invariants.contains(&"x_greater_zero".to_string()));
3031 }
3032
3033 #[test]
3034 fn test_s9b7_parse_verify_bounds_true() {
3035 let parser = AnnotationParser::new();
3036 let source = "# @depyler: verify_bounds = true\n";
3037 let annotations = parser.parse_annotations(source).unwrap();
3038 assert!(annotations.verify_bounds);
3039 }
3040
3041 #[test]
3042 fn test_s9b7_parse_verify_bounds_false() {
3043 let parser = AnnotationParser::new();
3044 let source = "# @depyler: verify_bounds = false\n";
3045 let annotations = parser.parse_annotations(source).unwrap();
3046 assert!(!annotations.verify_bounds);
3047 }
3048
3049 #[test]
3050 fn test_s9b7_parse_pattern() {
3051 let parser = AnnotationParser::new();
3052 let source = "# @depyler: pattern = singleton\n";
3053 let annotations = parser.parse_annotations(source).unwrap();
3054 assert_eq!(annotations.pattern, Some("singleton".to_string()));
3055 }
3056
3057 #[test]
3058 fn test_s9b7_parse_custom_attribute() {
3059 let parser = AnnotationParser::new();
3060 let source = "# @depyler: custom_attribute = my_attr\n# @depyler: custom_attribute = another\n";
3061 let annotations = parser.parse_annotations(source).unwrap();
3062 assert_eq!(annotations.custom_attributes.len(), 2);
3063 assert!(annotations.custom_attributes.contains(&"my_attr".to_string()));
3064 assert!(annotations.custom_attributes.contains(&"another".to_string()));
3065 }
3066
3067 #[test]
3068 fn test_s9b7_parse_global_strategy_lazy_static() {
3069 let parser = AnnotationParser::new();
3070 let source = "# @depyler: global_strategy = lazy_static\n";
3071 let annotations = parser.parse_annotations(source).unwrap();
3072 assert_eq!(annotations.global_strategy, GlobalStrategy::LazyStatic);
3073 }
3074
3075 #[test]
3076 fn test_s9b7_parse_global_strategy_once_cell() {
3077 let parser = AnnotationParser::new();
3078 let source = "# @depyler: global_strategy = once_cell\n";
3079 let annotations = parser.parse_annotations(source).unwrap();
3080 assert_eq!(annotations.global_strategy, GlobalStrategy::OnceCell);
3081 }
3082
3083 #[test]
3084 fn test_s9b7_parse_function_annotations_delegates() {
3085 let parser = AnnotationParser::new();
3086 let source = "# @depyler: ownership = borrowed\n";
3087 let annotations = parser.parse_function_annotations(source).unwrap();
3088 assert_eq!(annotations.ownership_model, OwnershipModel::Borrowed);
3089 }
3090
3091 #[test]
3092 fn test_s9b7_extractor_no_annotation_above_function() {
3093 let e = AnnotationExtractor::new();
3094 let source = "# just a comment\ndef my_func():\n pass";
3095 let result = e.extract_function_annotations(source, "my_func");
3096 assert!(result.is_none());
3097 }
3098
3099 #[test]
3100 fn test_s9b7_extractor_no_matching_function() {
3101 let e = AnnotationExtractor::new();
3102 let source = "# @depyler: ownership = owned\ndef other():\n pass";
3103 let result = e.extract_function_annotations(source, "nonexistent");
3104 assert!(result.is_none());
3105 }
3106
3107 #[test]
3108 fn test_s9b7_extractor_class_no_annotation() {
3109 let e = AnnotationExtractor::new();
3110 let source = "# just a comment\nclass MyClass:\n pass";
3111 let result = e.extract_class_annotations(source, "MyClass");
3112 assert!(result.is_none());
3113 }
3114
3115 #[test]
3116 fn test_s9b7_extractor_class_no_match() {
3117 let e = AnnotationExtractor::new();
3118 let source = "# @depyler: ownership = shared\nclass Other:\n pass";
3119 let result = e.extract_class_annotations(source, "NotHere");
3120 assert!(result.is_none());
3121 }
3122
3123 #[test]
3124 fn test_s9b7_annotation_validator_default() {
3125 let v = AnnotationValidator;
3126 let debug = format!("{:?}", v);
3127 assert!(debug.contains("AnnotationValidator"));
3128 }
3129
3130 #[test]
3131 fn test_s9b7_lambda_event_type_hash() {
3132 use std::collections::HashSet;
3133 let mut set = HashSet::new();
3134 set.insert(LambdaEventType::Auto);
3135 set.insert(LambdaEventType::S3Event);
3136 set.insert(LambdaEventType::SqsEvent);
3137 assert_eq!(set.len(), 3);
3138 }
3139
3140 #[test]
3145 fn test_s11_parse_optimization_hint_async_ready() {
3146 let parser = AnnotationParser::new();
3147 let source = "# @depyler: optimization_hint = \"async_ready\"";
3148 let result = parser.parse_annotations(source);
3149 assert!(result.is_ok());
3151 let annotations = result.unwrap();
3153 assert!(!annotations
3154 .performance_hints
3155 .contains(&PerformanceHint::Vectorize));
3156 }
3157
3158 #[test]
3159 fn test_s11_parse_optimization_hint_vectorize() {
3160 let parser = AnnotationParser::new();
3161 let source = "# @depyler: optimization_hint = \"vectorize\"";
3162 let result = parser.parse_annotations(source).unwrap();
3163 assert!(result
3164 .performance_hints
3165 .contains(&PerformanceHint::Vectorize));
3166 }
3167
3168 #[test]
3169 fn test_s11_parse_custom_attribute_serde_roundtrip() {
3170 let parser = AnnotationParser::new();
3171 let source = "# @depyler: custom_attribute = \"#[derive(Clone)]\"";
3172 let result = parser.parse_annotations(source).unwrap();
3173 assert!(result
3174 .custom_attributes
3175 .contains(&"#[derive(Clone)]".to_string()));
3176
3177 let json = serde_json::to_string(&result).unwrap();
3178 let deserialized: TranspilationAnnotations = serde_json::from_str(&json).unwrap();
3179 assert_eq!(result.custom_attributes, deserialized.custom_attributes);
3180 }
3181
3182 #[test]
3183 fn test_s11_parse_invariant_annotation() {
3184 let parser = AnnotationParser::new();
3185 let source = "# @depyler: invariant = \"x > 0\"";
3186 let result = parser.parse_annotations(source).unwrap();
3187 assert_eq!(result.invariants.len(), 1);
3188 assert!(result.invariants.contains(&"x > 0".to_string()));
3189 }
3190
3191 #[test]
3192 fn test_s11_parse_batch_failure_reporting() {
3193 let parser = AnnotationParser::new();
3194 let source = "# @depyler: batch_failure_reporting = \"true\"";
3195 let result = parser.parse_annotations(source).unwrap();
3196 let lambda = result.lambda_annotations.unwrap();
3197 assert!(lambda.batch_failure_reporting);
3198 }
3199
3200 #[test]
3201 fn test_s11_parse_custom_serialization() {
3202 let parser = AnnotationParser::new();
3203 let source = "# @depyler: custom_serialization = \"true\"";
3204 let result = parser.parse_annotations(source).unwrap();
3205 let lambda = result.lambda_annotations.unwrap();
3206 assert!(lambda.custom_serialization);
3207 }
3208
3209 #[test]
3212 fn test_s12_extract_function_annotations_found() {
3213 let extractor = AnnotationExtractor::new();
3214 let source = r#"
3215# @depyler: ownership = "borrowed"
3216def my_func(x: int) -> int:
3217 return x + 1
3218"#;
3219 let result = extractor.extract_function_annotations(source, "my_func");
3220 assert!(result.is_some(), "Expected to find annotations for my_func");
3221 assert!(result.unwrap().contains("@depyler: ownership"));
3222 }
3223
3224 #[test]
3225 fn test_s12_extract_function_annotations_not_found() {
3226 let extractor = AnnotationExtractor::new();
3227 let source = r#"
3228def my_func(x: int) -> int:
3229 return x + 1
3230"#;
3231 let result = extractor.extract_function_annotations(source, "my_func");
3232 assert!(result.is_none());
3233 }
3234
3235 #[test]
3236 fn test_s12_extract_function_annotations_wrong_name() {
3237 let extractor = AnnotationExtractor::new();
3238 let source = r#"
3239# @depyler: ownership = "borrowed"
3240def other_func(x: int) -> int:
3241 return x + 1
3242"#;
3243 let result = extractor.extract_function_annotations(source, "my_func");
3244 assert!(result.is_none());
3245 }
3246
3247 #[test]
3248 fn test_s12_extract_function_annotations_multiple() {
3249 let extractor = AnnotationExtractor::new();
3250 let source = r#"
3251# @depyler: ownership = "borrowed"
3252# @depyler: string_strategy = "zero_copy"
3253def my_func(x: int) -> int:
3254 return x + 1
3255"#;
3256 let result = extractor.extract_function_annotations(source, "my_func");
3257 assert!(result.is_some());
3258 let anno = result.unwrap();
3259 assert!(anno.contains("ownership"));
3260 assert!(anno.contains("string_strategy"));
3261 }
3262
3263 #[test]
3264 fn test_s12_extract_class_annotations_found() {
3265 let extractor = AnnotationExtractor::new();
3266 let source = r#"
3267# @depyler: ownership = "owned"
3268class MyClass:
3269 def __init__(self):
3270 pass
3271"#;
3272 let result = extractor.extract_class_annotations(source, "MyClass");
3273 assert!(result.is_some(), "Expected to find annotations for MyClass");
3274 assert!(result.unwrap().contains("@depyler: ownership"));
3275 }
3276
3277 #[test]
3278 fn test_s12_extract_class_annotations_not_found() {
3279 let extractor = AnnotationExtractor::new();
3280 let source = r#"
3281class MyClass:
3282 pass
3283"#;
3284 let result = extractor.extract_class_annotations(source, "MyClass");
3285 assert!(result.is_none());
3286 }
3287
3288 #[test]
3289 fn test_s12_extract_class_annotations_with_parent() {
3290 let extractor = AnnotationExtractor::new();
3291 let source = r#"
3292# @depyler: ownership = "borrowed"
3293class Child(Parent):
3294 pass
3295"#;
3296 let result = extractor.extract_class_annotations(source, "Child");
3297 assert!(result.is_some());
3298 }
3299
3300 #[test]
3301 fn test_s12_extract_function_at_start_of_file() {
3302 let extractor = AnnotationExtractor::new();
3303 let source = r#"# @depyler: ownership = "borrowed"
3304def first_func():
3305 pass
3306"#;
3307 let result = extractor.extract_function_annotations(source, "first_func");
3308 assert!(result.is_some());
3309 }
3310
3311 #[test]
3312 fn test_s12_extractor_default() {
3313 let extractor = AnnotationExtractor::default();
3314 let source = "def foo():\n pass\n";
3315 let result = extractor.extract_function_annotations(source, "foo");
3316 assert!(result.is_none());
3317 }
3318
3319 #[test]
3320 fn test_s12_extract_function_among_many() {
3321 let extractor = AnnotationExtractor::new();
3322 let source = r#"
3323def func_a():
3324 pass
3325
3326# @depyler: bounds_checking = "explicit"
3327def func_b():
3328 pass
3329
3330def func_c():
3331 pass
3332"#;
3333 let result = extractor.extract_function_annotations(source, "func_b");
3334 assert!(result.is_some());
3335 assert!(result.unwrap().contains("bounds_checking"));
3336
3337 let result_a = extractor.extract_function_annotations(source, "func_a");
3338 assert!(result_a.is_none());
3339
3340 let result_c = extractor.extract_function_annotations(source, "func_c");
3341 assert!(result_c.is_none());
3342 }
3343
3344 #[test]
3347 fn test_s12_extract_class_annotations_multiple() {
3348 let extractor = AnnotationExtractor::new();
3349 let source = r#"# @depyler: ownership = "shared"
3350# @depyler: thread_safety = "required"
3351class MyService:
3352 pass
3353"#;
3354 let result = extractor.extract_class_annotations(source, "MyService");
3355 assert!(result.is_some(), "Expected annotations");
3356 let annotations = result.unwrap();
3357 assert!(annotations.contains("ownership"));
3358 assert!(annotations.contains("thread_safety"));
3359 }
3360
3361 #[test]
3362 fn test_s12_extract_class_annotations_wrong_name() {
3363 let extractor = AnnotationExtractor::new();
3364 let source = r#"# @depyler: ownership = "shared"
3365class MyService:
3366 pass
3367"#;
3368 let result = extractor.extract_class_annotations(source, "OtherService");
3369 assert!(result.is_none());
3370 }
3371
3372 #[test]
3373 fn test_s12_extract_class_annotations_with_base_class() {
3374 let extractor = AnnotationExtractor::new();
3375 let source = r#"# @depyler: thread_safety = "required"
3376class MyService(BaseService):
3377 pass
3378"#;
3379 let result = extractor.extract_class_annotations(source, "MyService");
3380 assert!(result.is_some());
3381 }
3382
3383 #[test]
3384 fn test_s12_suggest_improvements_multiple_triggers() {
3385 let validator = AnnotationValidator::new();
3386 let mut annotations = TranspilationAnnotations::default();
3387 annotations
3388 .performance_hints
3389 .push(PerformanceHint::PerformanceCritical);
3390 annotations.optimization_level = OptimizationLevel::Standard;
3391 annotations.thread_safety = ThreadSafety::Required;
3392 annotations.ownership_model = OwnershipModel::Owned;
3393 annotations.service_type = Some(ServiceType::WebApi);
3394
3395 let suggestions = validator.suggest_improvements(&annotations);
3396 assert!(
3397 suggestions.len() >= 2,
3398 "Expected at least 2 suggestions, got {}",
3399 suggestions.len()
3400 );
3401 }
3402
3403 #[test]
3404 fn test_s12_suggest_improvements_perf_with_aggressive() {
3405 let validator = AnnotationValidator::new();
3406 let mut annotations = TranspilationAnnotations::default();
3407 annotations
3408 .performance_hints
3409 .push(PerformanceHint::PerformanceCritical);
3410 annotations.optimization_level = OptimizationLevel::Aggressive;
3411
3412 let suggestions = validator.suggest_improvements(&annotations);
3413 assert!(
3414 !suggestions
3415 .iter()
3416 .any(|s: &String| s.contains("optimization_level")),
3417 "Should not suggest optimization_level when already aggressive"
3418 );
3419 }
3420
3421 #[test]
3422 fn test_s12_suggest_improvements_thread_with_shared() {
3423 let validator = AnnotationValidator::new();
3424 let annotations = TranspilationAnnotations {
3425 thread_safety: ThreadSafety::Required,
3426 ownership_model: OwnershipModel::Shared,
3427 ..Default::default()
3428 };
3429 let suggestions = validator.suggest_improvements(&annotations);
3430 assert!(
3431 !suggestions
3432 .iter()
3433 .any(|s: &String| s.contains("ownership")),
3434 "Should not suggest ownership when already shared"
3435 );
3436 }
3437
3438 #[test]
3439 fn test_s12_parse_annotations_empty_source() {
3440 let parser = AnnotationParser::new();
3441 let result = parser.parse_annotations("");
3442 assert!(result.is_ok());
3443 let annotations = result.unwrap();
3444 assert_eq!(annotations.optimization_level, OptimizationLevel::Standard);
3445 }
3446
3447 #[test]
3448 fn test_s12_parse_annotations_no_depyler_comments() {
3449 let parser = AnnotationParser::new();
3450 let source = "# This is a regular comment\ndef foo():\n pass\n";
3451 let result = parser.parse_annotations(source);
3452 assert!(result.is_ok());
3453 let annotations = result.unwrap();
3454 assert_eq!(annotations.optimization_level, OptimizationLevel::Standard);
3455 }
3456
3457 #[test]
3458 fn test_s12_parse_annotations_full() {
3459 let parser = AnnotationParser::new();
3460 let source = r#"# @depyler: optimization_level = "aggressive"
3461# @depyler: ownership = "shared"
3462# @depyler: thread_safety = "required"
3463# @depyler: optimization_hint = "latency"
3464def serve():
3465 pass
3466"#;
3467 let result = parser.parse_annotations(source);
3468 assert!(result.is_ok());
3469 let annotations = result.unwrap();
3470 assert_eq!(annotations.optimization_level, OptimizationLevel::Aggressive);
3471 assert_eq!(annotations.ownership_model, OwnershipModel::Shared);
3472 assert_eq!(annotations.thread_safety, ThreadSafety::Required);
3473 }
3474
3475 #[test]
3476 fn test_s12_parse_annotations_unknown_key() {
3477 let parser = AnnotationParser::new();
3478 let source = "# @depyler: unknown_key = \"value\"\n";
3479 let result = parser.parse_annotations(source);
3480 assert!(result.is_err());
3481 }
3482
3483 #[test]
3484 fn test_s12_parse_annotations_lambda_runtime() {
3485 let parser = AnnotationParser::new();
3486 let source = "# @depyler: lambda_runtime = \"provided.al2\"\n";
3487 let result = parser.parse_annotations(source);
3488 assert!(result.is_ok());
3489 let annotations = result.unwrap();
3490 assert!(annotations.lambda_annotations.is_some());
3491 }
3492
3493 #[test]
3494 fn test_s12_validate_annotations_valid() {
3495 let validator = AnnotationValidator::new();
3496 let annotations = TranspilationAnnotations::default();
3497 let result = validator.validate(&annotations);
3498 assert!(result.is_ok());
3499 }
3500
3501 #[test]
3502 fn test_s12_validate_annotations_unsafe_with_bounds() {
3503 let validator = AnnotationValidator::new();
3504 let annotations = TranspilationAnnotations {
3505 safety_level: SafetyLevel::UnsafeAllowed,
3506 bounds_checking: BoundsChecking::Explicit,
3507 ..Default::default()
3508 };
3509 let _ = validator.validate(&annotations);
3510 }
3511
3512 #[test]
3513 fn test_s12_extract_func_annotations_with_gap() {
3514 let extractor = AnnotationExtractor::new();
3515 let source = r#"# @depyler: optimization_level = "aggressive"
3516
3517def process(data):
3518 return data
3519"#;
3520 let _ = extractor.extract_function_annotations(source, "process");
3521 }
3522
3523 #[test]
3524 fn test_s12_parse_function_annotations() {
3525 let parser = AnnotationParser::new();
3526 let source = r#"# @depyler: optimization_level = "aggressive"
3527def process(data):
3528 return data
3529"#;
3530 let result = parser.parse_function_annotations(source);
3531 assert!(result.is_ok());
3532 }
3533
3534 #[test]
3535 fn test_s12_parse_function_annotations_missing() {
3536 let parser = AnnotationParser::new();
3537 let source = r#"def process(data):
3538 return data
3539"#;
3540 let result = parser.parse_function_annotations(source);
3541 assert!(result.is_ok());
3542 }
3543}