scirs2_core/
apiversioning.rs

1//! API versioning system for backward compatibility
2//!
3//! This module provides version management for scirs2-core APIs,
4//! ensuring smooth transitions between versions and maintaining
5//! backward compatibility.
6
7use std::fmt;
8use std::sync::{Mutex, OnceLock};
9
10/// Represents a semantic version number
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Version {
13    /// Major version (breaking changes)
14    pub major: u32,
15    /// Minor version (new features, backward compatible)
16    pub minor: u32,
17    /// Patch version (bug fixes)
18    pub patch: u32,
19}
20
21impl Version {
22    /// Create a new version
23    pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
24        Self {
25            major,
26            minor,
27            patch,
28        }
29    }
30
31    /// Parse a version string like "1.2.3" or "1.2.3-beta.1"
32    pub fn parse(versionstr: &str) -> Result<Self, String> {
33        // Split on '-' to handle version suffixes like "-beta.1"
34        let base_version = versionstr.split('-').next().unwrap_or(versionstr);
35
36        // Split the base version on '.'
37        let parts: Vec<&str> = base_version.split('.').collect();
38
39        if parts.len() < 3 {
40            return Err(format!("Invalid version format: {versionstr}"));
41        }
42
43        let major = parts[0].parse::<u32>().map_err(|_| parts[0].to_string())?;
44        let minor = parts[1].parse::<u32>().map_err(|_| parts[1].to_string())?;
45        let patch = parts[2].parse::<u32>().map_err(|_| parts[2].to_string())?;
46
47        Ok(Self::new(major, minor, patch))
48    }
49
50    /// Current version of scirs2-core (Beta 1)
51    pub const CURRENT: Self = Self::new(0, 1, 0);
52
53    /// Current beta release identifier
54    pub const CURRENT_BETA: &'static str = "0.1.0";
55
56    /// Check if this version is compatible with another
57    pub fn is_compatible_with(&self, other: &Version) -> bool {
58        // Same major version and greater or equal minor/patch
59        self.major == other.major
60            && (self.minor > other.minor
61                || (self.minor == other.minor && self.patch >= other.patch))
62    }
63}
64
65impl fmt::Display for Version {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
68    }
69}
70
71/// Trait for versioned APIs
72pub trait Versioned {
73    /// Get the version this API was introduced in
74    fn since_version() -> Version;
75
76    /// Get the version this API was deprecated in (if any)
77    fn deprecated_version() -> Option<Version> {
78        None
79    }
80
81    /// Check if this API is available in a given version
82    fn is_available_in(version: &Version) -> bool {
83        version.is_compatible_with(&Self::since_version())
84            && Self::deprecated_version()
85                .map(|dep| version < &dep)
86                .unwrap_or(true)
87    }
88}
89
90/// Macro to mark APIs with version information
91#[macro_export]
92macro_rules! since_version {
93    ($major:expr, $minor:expr, $patch:expr) => {
94        fn since_version() -> $crate::apiversioning::Version {
95            $crate::apiversioning::Version::new($major, $minor, $patch)
96        }
97    };
98}
99
100/// Macro to mark deprecated APIs
101#[macro_export]
102macro_rules! deprecated_in {
103    ($major:expr, $minor:expr, $patch:expr) => {
104        fn deprecated_version() -> Option<$crate::apiversioning::Version> {
105            Some($crate::apiversioning::Version::new($major, $minor, $patch))
106        }
107    };
108}
109
110/// Version registry for tracking API changes
111pub struct VersionRegistry {
112    entries: Vec<ApiEntry>,
113}
114
115#[derive(Debug, Clone)]
116pub struct ApiEntry {
117    pub name: String,
118    pub module: String,
119    pub since: Version,
120    pub deprecated: Option<Version>,
121    pub replacement: Option<String>,
122    pub breakingchanges: Vec<BreakingChange>,
123    pub example_usage: Option<String>,
124    pub migration_example: Option<String>,
125}
126
127#[derive(Debug, Clone)]
128pub struct BreakingChange {
129    pub version: Version,
130    pub description: String,
131    pub impact: BreakingChangeImpact,
132    pub mitigation: String,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
136pub enum BreakingChangeImpact {
137    Low,      // Minor API signature changes
138    Medium,   // Functionality changes
139    High,     // Major restructuring
140    Critical, // Complete removal
141}
142
143impl VersionRegistry {
144    /// Create a new version registry
145    pub fn new() -> Self {
146        Self {
147            entries: Vec::new(),
148        }
149    }
150
151    /// Register a new API
152    pub fn register_api(
153        &mut self,
154        name: impl Into<String>,
155        module: impl Into<String>,
156        since: Version,
157    ) -> &mut Self {
158        let name_str = name.into();
159        let module_str = module.into();
160
161        // Check if the API is already registered
162        if !self
163            .entries
164            .iter()
165            .any(|e| e.name == name_str && e.module == module_str)
166        {
167            self.entries.push(ApiEntry {
168                name: name_str,
169                module: module_str,
170                since,
171                deprecated: None,
172                replacement: None,
173                breakingchanges: Vec::new(),
174                example_usage: None,
175                migration_example: None,
176            });
177        }
178        self
179    }
180
181    /// Register an API with usage example
182    pub fn register_api_with_example(
183        &mut self,
184        name: impl Into<String>,
185        module: impl Into<String>,
186        since: Version,
187        example: impl Into<String>,
188    ) -> &mut Self {
189        let name_str = name.into();
190        let module_str = module.into();
191
192        if !self
193            .entries
194            .iter()
195            .any(|e| e.name == name_str && e.module == module_str)
196        {
197            self.entries.push(ApiEntry {
198                name: name_str,
199                module: module_str,
200                since,
201                deprecated: None,
202                replacement: None,
203                breakingchanges: Vec::new(),
204                example_usage: Some(example.into()),
205                migration_example: None,
206            });
207        }
208        self
209    }
210
211    /// Mark an API as deprecated
212    pub fn deprecate_api(
213        &mut self,
214        name: &str,
215        version: Version,
216        replacement: Option<String>,
217    ) -> Result<(), String> {
218        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == name) {
219            entry.deprecated = Some(version);
220            entry.replacement = replacement;
221            Ok(())
222        } else {
223            Err(format!("API '{name}' not found in registry"))
224        }
225    }
226
227    /// Mark an API as deprecated with migration example
228    pub fn deprecate_api_with_example(
229        &mut self,
230        name: &str,
231        version: Version,
232        replacement: Option<String>,
233        migration_example: impl Into<String>,
234    ) -> Result<(), String> {
235        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == name) {
236            entry.deprecated = Some(version);
237            entry.replacement = replacement;
238            entry.migration_example = Some(migration_example.into());
239            Ok(())
240        } else {
241            Err(format!("API '{name}' not found in registry"))
242        }
243    }
244
245    /// Add a breaking change to an API
246    pub fn add_breaking_change(
247        &mut self,
248        apiname: &str,
249        change: BreakingChange,
250    ) -> Result<(), String> {
251        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == apiname) {
252            entry.breakingchanges.push(change);
253            Ok(())
254        } else {
255            Err(format!("API '{apiname}' not found in registry"))
256        }
257    }
258
259    /// Get all APIs available in a specific version
260    pub fn apis_in_version(&self, version: &Version) -> Vec<&ApiEntry> {
261        self.entries
262            .iter()
263            .filter(|entry| {
264                version.is_compatible_with(&entry.since)
265                    && entry.deprecated.map(|dep| version < &dep).unwrap_or(true)
266            })
267            .collect()
268    }
269
270    /// Get all deprecated APIs in a version
271    pub fn deprecated_apis_in_version(&self, version: &Version) -> Vec<&ApiEntry> {
272        self.entries
273            .iter()
274            .filter(|entry| entry.deprecated.map(|dep| version >= &dep).unwrap_or(false))
275            .collect()
276    }
277
278    /// Generate migration guide between versions
279    pub fn migration_guide(&self, from: &Version, to: &Version) -> String {
280        let mut guide = format!("# Migration Guide: {from} → {to}\n\n");
281
282        guide.push_str(&format!(
283            "This guide helps you upgrade from scirs2-core {from} to {to}.\n\n"
284        ));
285
286        // Breaking changes analysis
287        let breakingchanges: Vec<_> = self
288            .entries
289            .iter()
290            .filter_map(|e| {
291                if !e.breakingchanges.is_empty() {
292                    let relevant_changes: Vec<_> = e
293                        .breakingchanges
294                        .iter()
295                        .filter(|bc| bc.version > *from && bc.version <= *to)
296                        .collect();
297                    if !relevant_changes.is_empty() {
298                        Some((e, relevant_changes))
299                    } else {
300                        None
301                    }
302                } else {
303                    None
304                }
305            })
306            .collect();
307
308        if !breakingchanges.is_empty() {
309            guide.push_str("## ⚠️ Breaking Changes\n\n");
310
311            for (api, changes) in breakingchanges {
312                guide.push_str(&format!(
313                    "### {name} ({module})\n\n",
314                    name = api.name,
315                    module = api.module
316                ));
317
318                for change in changes {
319                    let impact_icon = match change.impact {
320                        BreakingChangeImpact::Low => "🟡",
321                        BreakingChangeImpact::Medium => "🟠",
322                        BreakingChangeImpact::High => "🔴",
323                        BreakingChangeImpact::Critical => "💥",
324                    };
325
326                    guide.push_str(&format!(
327                        "{} **{}**: {}\n\n**Mitigation**: {}\n\n",
328                        impact_icon, change.version, change.description, change.mitigation
329                    ));
330                }
331            }
332        }
333
334        // Find removed APIs
335        let removed: Vec<_> = self
336            .entries
337            .iter()
338            .filter(|e| {
339                from.is_compatible_with(&e.since)
340                    && e.deprecated.map(|d| to >= &d && from < &d).unwrap_or(false)
341            })
342            .collect();
343
344        if !removed.is_empty() {
345            guide.push_str("## 🗑️ Removed APIs\n\n");
346
347            for api in removed {
348                guide.push_str(&format!(
349                    "### {name} ({module})\n\n",
350                    name = api.name,
351                    module = api.module
352                ));
353
354                if let Some(ref replacement) = api.replacement {
355                    guide.push_str(&format!("**Replacement**: {replacement}\n\n"));
356                }
357
358                if let Some(ref migration_example) = api.migration_example {
359                    guide.push_str("**Migration Example**:\n\n");
360                    guide.push_str("```rust\n");
361                    guide.push_str(migration_example);
362                    guide.push_str("\n```\n\n");
363                }
364            }
365        }
366
367        // Find new APIs
368        let new_apis: Vec<_> = self
369            .entries
370            .iter()
371            .filter(|e| to.is_compatible_with(&e.since) && !from.is_compatible_with(&e.since))
372            .collect();
373
374        if !new_apis.is_empty() {
375            guide.push_str("## ✨ New APIs\n\n");
376
377            for api in new_apis {
378                guide.push_str(&format!(
379                    "### {} ({}) - Since {}\n\n",
380                    api.name, api.module, api.since
381                ));
382
383                if let Some(ref example) = api.example_usage {
384                    guide.push_str("**Usage Example**:\n\n");
385                    guide.push_str("```rust\n");
386                    guide.push_str(example);
387                    guide.push_str("\n```\n\n");
388                }
389            }
390        }
391
392        // Migration checklist
393        guide.push_str("## 📋 Migration Checklist\n\n");
394        guide.push_str("- [ ] Update Cargo.toml dependencies\n");
395        guide.push_str("- [ ] Fix compilation errors\n");
396        guide.push_str("- [ ] Update deprecated API usage\n");
397        guide.push_str("- [ ] Run test suite\n");
398        guide.push_str("- [ ] Update documentation\n");
399        guide.push_str("- [ ] Performance testing\n\n");
400
401        guide.push_str("## 📚 Additional Resources\n\n");
402        guide.push_str(&format!(
403            "- [API Documentation](https://docs.rs/scirs2-core/{to})\n"
404        ));
405        guide.push_str(
406            "- [Changelog](https://github.com/cool-japan/scirs/blob/main/CHANGELOG.md)\n",
407        );
408        guide.push_str("- [Examples](https://github.com/cool-japan/scirs/tree/main/examples)\n");
409
410        guide
411    }
412
413    /// Generate a deprecation timeline
414    pub fn deprecation_timeline(&self) -> String {
415        let mut timeline = String::from("# API Deprecation Timeline\n\n");
416
417        let mut deprecated_apis: Vec<_> = self
418            .entries
419            .iter()
420            .filter(|e| e.deprecated.is_some())
421            .collect();
422
423        deprecated_apis.sort_by_key(|e| e.deprecated.expect("Operation failed"));
424
425        let mut current_version: Option<Version> = None;
426
427        for api in deprecated_apis {
428            let dep_version = api.deprecated.expect("Operation failed");
429
430            if current_version != Some(dep_version) {
431                timeline.push_str(&format!("\n## Version {dep_version}\n\n"));
432                current_version = Some(dep_version);
433            }
434
435            timeline.push_str(&format!(
436                "- **{name}** ({module})",
437                name = api.name,
438                module = api.module
439            ));
440
441            if let Some(ref replacement) = api.replacement {
442                timeline.push_str(&format!(" → {replacement}"));
443            }
444
445            timeline.push('\n');
446        }
447
448        timeline
449    }
450}
451
452impl Default for VersionRegistry {
453    fn default() -> Self {
454        Self::new()
455    }
456}
457
458/// API Freeze status for Beta 1 release
459#[derive(Debug, Clone, PartialEq, Eq)]
460pub enum ApiFreezeStatus {
461    /// APIs are still changing (Alpha phase)
462    Unfrozen,
463    /// APIs are frozen for this version (Beta phase)
464    Frozen,
465    /// APIs are stable (Release phase)
466    Stable,
467}
468
469/// Comprehensive API compatibility checker
470#[derive(Debug, Clone)]
471pub struct ApiCompatibilityChecker {
472    /// Current freeze status
473    freeze_status: ApiFreezeStatus,
474    /// Frozen API surface for comparison
475    frozen_apis: Vec<ApiSignature>,
476    /// Compatibility rules
477    #[allow(dead_code)]
478    compatibility_rules: Vec<CompatibilityRule>,
479}
480
481/// API signature for detailed compatibility checking
482#[derive(Debug, Clone, PartialEq, Eq, Hash)]
483pub struct ApiSignature {
484    pub name: String,
485    pub module: String,
486    pub signature_hash: u64,
487    pub parameters: Vec<Parameter>,
488    pub return_type: Option<String>,
489    pub visibility: Visibility,
490    pub stability: StabilityLevel,
491}
492
493/// Parameter definition for API signatures
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495pub struct Parameter {
496    pub name: String,
497    pub type_name: String,
498    pub is_optional: bool,
499    pub defaultvalue: Option<String>,
500}
501
502/// API visibility levels
503#[derive(Debug, Clone, PartialEq, Eq, Hash)]
504pub enum Visibility {
505    Public,
506    PublicCrate,
507    Private,
508}
509
510/// API stability levels
511#[derive(Debug, Clone, PartialEq, Eq, Hash)]
512pub enum StabilityLevel {
513    Stable,
514    Unstable,
515    Deprecated,
516    Experimental,
517}
518
519/// Compatibility rules for API changes
520#[derive(Debug, Clone)]
521pub struct CompatibilityRule {
522    pub rule_type: CompatibilityRuleType,
523    pub description: String,
524    pub severity: CompatibilitySeverity,
525    pub auto_fix: Option<String>,
526}
527
528/// Types of compatibility rules
529#[derive(Debug, Clone, PartialEq, Eq)]
530pub enum CompatibilityRuleType {
531    /// Function signature cannot change
532    SignatureChange,
533    /// Public APIs cannot be removed
534    PublicApiRemoval,
535    /// Parameter types cannot change
536    ParameterTypeChange,
537    /// Return types cannot change
538    ReturnTypeChange,
539    /// New required parameters cannot be added
540    NewRequiredParameter,
541    /// Visibility cannot be reduced
542    VisibilityReduction,
543}
544
545/// Severity of compatibility violations
546#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
547pub enum CompatibilitySeverity {
548    /// Will cause compilation failure
549    Breaking,
550    /// May cause runtime issues
551    Warning,
552    /// Informational only
553    Info,
554}
555
556/// Compatibility check result
557#[derive(Debug, Clone)]
558pub struct CompatibilityCheckResult {
559    pub is_compatible: bool,
560    pub violations: Vec<CompatibilityViolation>,
561    pub warnings: Vec<CompatibilityWarning>,
562    pub suggestions: Vec<CompatibilitySuggestion>,
563}
564
565/// Compatibility violation details
566#[derive(Debug, Clone)]
567pub struct CompatibilityViolation {
568    pub apiname: String,
569    pub violation_type: CompatibilityRuleType,
570    pub severity: CompatibilitySeverity,
571    pub description: String,
572    pub old_signature: Option<ApiSignature>,
573    pub new_signature: Option<ApiSignature>,
574    pub fix_suggestion: Option<String>,
575}
576
577/// Compatibility warning
578#[derive(Debug, Clone)]
579pub struct CompatibilityWarning {
580    pub apiname: String,
581    pub message: String,
582    pub impact: String,
583}
584
585/// Compatibility suggestion
586#[derive(Debug, Clone)]
587pub struct CompatibilitySuggestion {
588    pub apiname: String,
589    pub suggestion: String,
590    pub rationale: String,
591}
592
593impl ApiCompatibilityChecker {
594    /// Create a new compatibility checker
595    pub fn new() -> Self {
596        Self {
597            freeze_status: ApiFreezeStatus::Unfrozen,
598            frozen_apis: Vec::new(),
599            compatibility_rules: Self::default_compatibility_rules(),
600        }
601    }
602
603    /// Create checker for Beta 1 (frozen APIs)
604    pub fn for_beta1() -> Self {
605        Self {
606            freeze_status: ApiFreezeStatus::Frozen,
607            frozen_apis: Vec::new(),
608            compatibility_rules: Self::beta1_compatibility_rules(),
609        }
610    }
611
612    /// Default compatibility rules for general API evolution
613    fn default_compatibility_rules() -> Vec<CompatibilityRule> {
614        vec![
615            CompatibilityRule {
616                rule_type: CompatibilityRuleType::PublicApiRemoval,
617                description: "Public APIs cannot be removed without deprecation".to_string(),
618                severity: CompatibilitySeverity::Breaking,
619                auto_fix: Some("Add deprecation annotation".to_string()),
620            },
621            CompatibilityRule {
622                rule_type: CompatibilityRuleType::SignatureChange,
623                description: "Function signatures cannot change in breaking ways".to_string(),
624                severity: CompatibilitySeverity::Breaking,
625                auto_fix: None,
626            },
627            CompatibilityRule {
628                rule_type: CompatibilityRuleType::ParameterTypeChange,
629                description: "Parameter types cannot change".to_string(),
630                severity: CompatibilitySeverity::Breaking,
631                auto_fix: Some("Create new function with different name".to_string()),
632            },
633        ]
634    }
635
636    /// Stricter compatibility rules for Beta 1 API freeze
637    fn beta1_compatibility_rules() -> Vec<CompatibilityRule> {
638        vec![
639            CompatibilityRule {
640                rule_type: CompatibilityRuleType::PublicApiRemoval,
641                description: "No public APIs can be removed during Beta 1 freeze".to_string(),
642                severity: CompatibilitySeverity::Breaking,
643                auto_fix: None,
644            },
645            CompatibilityRule {
646                rule_type: CompatibilityRuleType::SignatureChange,
647                description: "No function signatures can change during API freeze".to_string(),
648                severity: CompatibilitySeverity::Breaking,
649                auto_fix: None,
650            },
651            CompatibilityRule {
652                rule_type: CompatibilityRuleType::NewRequiredParameter,
653                description: "No new required parameters can be added during freeze".to_string(),
654                severity: CompatibilitySeverity::Breaking,
655                auto_fix: Some("Make parameter optional with default value".to_string()),
656            },
657            CompatibilityRule {
658                rule_type: CompatibilityRuleType::VisibilityReduction,
659                description: "API visibility cannot be reduced during freeze".to_string(),
660                severity: CompatibilitySeverity::Breaking,
661                auto_fix: None,
662            },
663        ]
664    }
665
666    /// Freeze the current API surface
667    pub fn freeze_apis(&mut self, apis: Vec<ApiSignature>) -> Result<(), String> {
668        if self.freeze_status == ApiFreezeStatus::Stable {
669            return Err("Cannot freeze APIs that are already stable".to_string());
670        }
671
672        self.frozen_apis = apis;
673        self.freeze_status = ApiFreezeStatus::Frozen;
674        Ok(())
675    }
676
677    /// Check compatibility between current and frozen APIs
678    pub fn check_compatibility(&self, currentapis: &[ApiSignature]) -> CompatibilityCheckResult {
679        let mut violations = Vec::new();
680        let mut warnings = Vec::new();
681        let mut suggestions = Vec::new();
682
683        if self.freeze_status == ApiFreezeStatus::Unfrozen {
684            warnings.push(CompatibilityWarning {
685                apiname: "*".to_string(),
686                message: "APIs are not frozen - no compatibility checking performed".to_string(),
687                impact: "API changes may break compatibility".to_string(),
688            });
689
690            return CompatibilityCheckResult {
691                is_compatible: true,
692                violations,
693                warnings,
694                suggestions,
695            };
696        }
697
698        // Check for removed APIs
699        for frozen_api in &self.frozen_apis {
700            if frozen_api.visibility == Visibility::Public
701                && frozen_api.stability == StabilityLevel::Stable
702                && !currentapis
703                    .iter()
704                    .any(|api| api.name == frozen_api.name && api.module == frozen_api.module)
705            {
706                violations.push(CompatibilityViolation {
707                    apiname: format!(
708                        "{module}::{name}",
709                        module = frozen_api.module,
710                        name = frozen_api.name
711                    ),
712                    violation_type: CompatibilityRuleType::PublicApiRemoval,
713                    severity: CompatibilitySeverity::Breaking,
714                    description: "Public stable API was removed".to_string(),
715                    old_signature: Some(frozen_api.clone()),
716                    new_signature: None,
717                    fix_suggestion: Some("Restore the API or mark as deprecated".to_string()),
718                });
719            }
720        }
721
722        // Check for signature changes
723        for current_api in currentapis {
724            if let Some(frozen_api) = self
725                .frozen_apis
726                .iter()
727                .find(|api| api.name == current_api.name && api.module == current_api.module)
728            {
729                // Check parameter changes first (more specific)
730                if frozen_api.parameters != current_api.parameters {
731                    let has_new_required = current_api.parameters.iter().any(|p| {
732                        !p.is_optional && !frozen_api.parameters.iter().any(|fp| fp.name == p.name)
733                    });
734
735                    if has_new_required {
736                        violations.push(CompatibilityViolation {
737                            apiname: format!(
738                                "{module}::{name}",
739                                module = current_api.module,
740                                name = current_api.name
741                            ),
742                            violation_type: CompatibilityRuleType::NewRequiredParameter,
743                            severity: CompatibilitySeverity::Breaking,
744                            description: "New required parameter added".to_string(),
745                            old_signature: Some(frozen_api.clone()),
746                            new_signature: Some(current_api.clone()),
747                            fix_suggestion: Some("Make new parameters optional".to_string()),
748                        });
749                        continue; // Skip signature hash check for this API
750                    }
751                }
752
753                // Check visibility reduction
754                if Self::is_visibility_reduced(&frozen_api.visibility, &current_api.visibility) {
755                    violations.push(CompatibilityViolation {
756                        apiname: format!(
757                            "{module}::{name}",
758                            module = current_api.module,
759                            name = current_api.name
760                        ),
761                        violation_type: CompatibilityRuleType::VisibilityReduction,
762                        severity: CompatibilitySeverity::Breaking,
763                        description: "API visibility was reduced".to_string(),
764                        old_signature: Some(frozen_api.clone()),
765                        new_signature: Some(current_api.clone()),
766                        fix_suggestion: Some("Restore original visibility".to_string()),
767                    });
768                }
769
770                // Check return type changes
771                if frozen_api.return_type != current_api.return_type {
772                    violations.push(CompatibilityViolation {
773                        apiname: format!(
774                            "{module}::{name}",
775                            module = current_api.module,
776                            name = current_api.name
777                        ),
778                        violation_type: CompatibilityRuleType::ReturnTypeChange,
779                        severity: CompatibilitySeverity::Breaking,
780                        description: "Return type changed".to_string(),
781                        old_signature: Some(frozen_api.clone()),
782                        new_signature: Some(current_api.clone()),
783                        fix_suggestion: Some(
784                            "Restore original return type or create new API".to_string(),
785                        ),
786                    });
787                }
788
789                // Check for other parameter type changes
790                if frozen_api.parameters.len() == current_api.parameters.len() {
791                    for (old_param, new_param) in frozen_api
792                        .parameters
793                        .iter()
794                        .zip(current_api.parameters.iter())
795                    {
796                        if old_param.name == new_param.name
797                            && old_param.type_name != new_param.type_name
798                        {
799                            violations.push(CompatibilityViolation {
800                                apiname: {
801                                    let module = &current_api.module;
802                                    let name = &current_api.name;
803                                    format!("{module}::{name}")
804                                },
805                                violation_type: CompatibilityRuleType::ParameterTypeChange,
806                                severity: CompatibilitySeverity::Breaking,
807                                description: format!(
808                                    "Parameter '{param_name}' type changed from '{old_type}' to '{new_type}'",
809                                    param_name = old_param.name, old_type = old_param.type_name, new_type = new_param.type_name
810                                ),
811                                old_signature: Some(frozen_api.clone()),
812                                new_signature: Some(current_api.clone()),
813                                fix_suggestion: Some(
814                                    "Restore original parameter type or create new API".to_string(),
815                                ),
816                            });
817                        }
818                    }
819                }
820
821                // Check signature hash changes (catch-all for other changes)
822                if frozen_api.signature_hash != current_api.signature_hash
823                    && !violations.iter().any(|v| {
824                        v.apiname
825                            == format!(
826                                "{module}::{name}",
827                                module = current_api.module,
828                                name = current_api.name
829                            )
830                    })
831                {
832                    violations.push(CompatibilityViolation {
833                        apiname: format!(
834                            "{module}::{name}",
835                            module = current_api.module,
836                            name = current_api.name
837                        ),
838                        violation_type: CompatibilityRuleType::SignatureChange,
839                        severity: CompatibilitySeverity::Breaking,
840                        description: "API signature changed in an unspecified way".to_string(),
841                        old_signature: Some(frozen_api.clone()),
842                        new_signature: Some(current_api.clone()),
843                        fix_suggestion: Some(
844                            "Revert signature change or create new API".to_string(),
845                        ),
846                    });
847                }
848            }
849        }
850
851        // Generate suggestions for new APIs
852        for current_api in currentapis {
853            if !self
854                .frozen_apis
855                .iter()
856                .any(|api| api.name == current_api.name && api.module == current_api.module)
857            {
858                suggestions.push(CompatibilitySuggestion {
859                    apiname: format!(
860                        "{module}::{name}",
861                        module = current_api.module,
862                        name = current_api.name
863                    ),
864                    suggestion: "New API detected - ensure proper documentation".to_string(),
865                    rationale: "New APIs should be well-documented and tested".to_string(),
866                });
867            }
868        }
869
870        let is_compatible = violations
871            .iter()
872            .all(|v| v.severity != CompatibilitySeverity::Breaking);
873
874        CompatibilityCheckResult {
875            is_compatible,
876            violations,
877            warnings,
878            suggestions,
879        }
880    }
881
882    /// Check if visibility was reduced
883    fn is_visibility_reduced(old: &Visibility, new: &Visibility) -> bool {
884        use Visibility::*;
885        matches!(
886            (old, new),
887            (Public, PublicCrate) | (Public, Private) | (PublicCrate, Private)
888        )
889    }
890
891    /// Generate detailed compatibility report
892    pub fn generate_compatibility_report(&self, result: &CompatibilityCheckResult) -> String {
893        let mut report = String::from("# API Compatibility Report\n\n");
894
895        report.push_str(&format!("**Freeze Status**: {:?}\n", self.freeze_status));
896        report.push_str(&format!(
897            "**Overall Compatible**: {}\n\n",
898            result.is_compatible
899        ));
900
901        if !result.violations.is_empty() {
902            report.push_str("## ❌ Compatibility Violations\n\n");
903            for violation in &result.violations {
904                let severity_icon = match violation.severity {
905                    CompatibilitySeverity::Breaking => "💥",
906                    CompatibilitySeverity::Warning => "⚠️",
907                    CompatibilitySeverity::Info => "ℹ️",
908                };
909
910                report.push_str(&format!(
911                    "{} **{}** ({:?}): {}\n",
912                    severity_icon,
913                    violation.apiname,
914                    violation.violation_type,
915                    violation.description
916                ));
917
918                if let Some(ref fix) = violation.fix_suggestion {
919                    report.push_str(&format!("   - **Fix**: {fix}\n"));
920                }
921                report.push('\n');
922            }
923        }
924
925        if !result.warnings.is_empty() {
926            report.push_str("## ⚠️ Warnings\n\n");
927            for warning in &result.warnings {
928                report.push_str(&format!(
929                    "- **{}**: {} (Impact: {})\n",
930                    warning.apiname, warning.message, warning.impact
931                ));
932            }
933            report.push('\n');
934        }
935
936        if !result.suggestions.is_empty() {
937            report.push_str("## 💡 Suggestions\n\n");
938            for suggestion in &result.suggestions {
939                report.push_str(&format!(
940                    "- **{}**: {} ({})\n",
941                    suggestion.apiname, suggestion.suggestion, suggestion.rationale
942                ));
943            }
944            report.push('\n');
945        }
946
947        report.push_str("## 📋 Next Steps\n\n");
948        if result.is_compatible {
949            report.push_str("✅ All compatibility checks passed. Safe to proceed.\n");
950        } else {
951            report
952                .push_str("❌ Compatibility violations detected. Address issues before release:\n");
953            report.push_str("1. Review breaking changes listed above\n");
954            report.push_str("2. Apply suggested fixes or revert changes\n");
955            report.push_str("3. Re-run compatibility check\n");
956            report.push_str("4. Update documentation if needed\n");
957        }
958
959        report
960    }
961}
962
963impl Default for ApiCompatibilityChecker {
964    fn default() -> Self {
965        Self::new()
966    }
967}
968
969/// Global version registry
970static REGISTRY: OnceLock<Mutex<VersionRegistry>> = OnceLock::new();
971
972/// Global API compatibility checker
973static API_CHECKER: OnceLock<Mutex<ApiCompatibilityChecker>> = OnceLock::new();
974
975/// Get the global registry for modification
976#[allow(dead_code)]
977pub fn global_registry_mut() -> std::sync::MutexGuard<'static, VersionRegistry> {
978    REGISTRY
979        .get_or_init(|| Mutex::new(VersionRegistry::new()))
980        .lock()
981        .expect("Operation failed")
982}
983
984/// Get the global registry for reading
985#[allow(dead_code)]
986pub fn global_registry() -> &'static Mutex<VersionRegistry> {
987    REGISTRY.get_or_init(|| Mutex::new(VersionRegistry::new()))
988}
989
990/// Get the global API checker for modification
991#[allow(dead_code)]
992pub fn global_api_checker_mut() -> std::sync::MutexGuard<'static, ApiCompatibilityChecker> {
993    API_CHECKER
994        .get_or_init(|| Mutex::new(ApiCompatibilityChecker::for_beta1()))
995        .lock()
996        .expect("Operation failed")
997}
998
999/// Get the global API checker for reading
1000#[allow(dead_code)]
1001pub fn global_api_checker() -> &'static Mutex<ApiCompatibilityChecker> {
1002    API_CHECKER.get_or_init(|| Mutex::new(ApiCompatibilityChecker::for_beta1()))
1003}
1004
1005/// Helper function to create API signature from function metadata
1006#[allow(dead_code)]
1007pub fn create_api_signature(
1008    name: &str,
1009    module: &str,
1010    parameters: Vec<Parameter>,
1011    return_type: Option<String>,
1012    visibility: Visibility,
1013    stability: StabilityLevel,
1014) -> ApiSignature {
1015    let name_str = name.to_string();
1016    let module_str = module.to_string();
1017
1018    // Create a simple hash based on function signature components
1019    let mut hasher = std::collections::hash_map::DefaultHasher::new();
1020    use std::hash::{Hash, Hasher};
1021
1022    name_str.hash(&mut hasher);
1023    module_str.hash(&mut hasher);
1024    // Hash each parameter
1025    for param in &parameters {
1026        param.name.hash(&mut hasher);
1027        param.type_name.hash(&mut hasher);
1028        param.is_optional.hash(&mut hasher);
1029        if let Some(ref default) = param.defaultvalue {
1030            default.hash(&mut hasher);
1031        }
1032    }
1033    return_type.hash(&mut hasher);
1034    visibility.hash(&mut hasher);
1035
1036    ApiSignature {
1037        name: name_str,
1038        module: module_str,
1039        signature_hash: hasher.finish(),
1040        parameters,
1041        return_type,
1042        visibility,
1043        stability,
1044    }
1045}
1046
1047/// Initialize Beta 1 API freeze with core scirs2 APIs
1048#[allow(dead_code)]
1049pub fn initialize_beta1_freeze() -> Result<(), String> {
1050    let mut checker = global_api_checker_mut();
1051
1052    // Use the same API definitions for consistency
1053    let core_apis = get_test_frozen_apis();
1054
1055    checker.freeze_apis(core_apis)
1056}
1057
1058/// Get the frozen API signatures for testing
1059#[allow(dead_code)]
1060fn get_test_frozen_apis() -> Vec<ApiSignature> {
1061    vec![
1062        create_api_signature(
1063            "simd_add",
1064            "simd_ops",
1065            vec![
1066                Parameter {
1067                    name: "a".to_string(),
1068                    type_name: "&ArrayView1<Self>".to_string(),
1069                    is_optional: false,
1070                    defaultvalue: None,
1071                },
1072                Parameter {
1073                    name: "b".to_string(),
1074                    type_name: "&ArrayView1<Self>".to_string(),
1075                    is_optional: false,
1076                    defaultvalue: None,
1077                },
1078            ],
1079            Some("Array1<Self>".to_string()),
1080            Visibility::Public,
1081            StabilityLevel::Stable,
1082        ),
1083        create_api_signature(
1084            "simd_mul",
1085            "simd_ops",
1086            vec![
1087                Parameter {
1088                    name: "a".to_string(),
1089                    type_name: "&ArrayView1<Self>".to_string(),
1090                    is_optional: false,
1091                    defaultvalue: None,
1092                },
1093                Parameter {
1094                    name: "b".to_string(),
1095                    type_name: "&ArrayView1<Self>".to_string(),
1096                    is_optional: false,
1097                    defaultvalue: None,
1098                },
1099            ],
1100            Some("Array1<Self>".to_string()),
1101            Visibility::Public,
1102            StabilityLevel::Stable,
1103        ),
1104        create_api_signature(
1105            "simd_dot",
1106            "simd_ops",
1107            vec![
1108                Parameter {
1109                    name: "a".to_string(),
1110                    type_name: "&ArrayView1<Self>".to_string(),
1111                    is_optional: false,
1112                    defaultvalue: None,
1113                },
1114                Parameter {
1115                    name: "b".to_string(),
1116                    type_name: "&ArrayView1<Self>".to_string(),
1117                    is_optional: false,
1118                    defaultvalue: None,
1119                },
1120            ],
1121            Some("Self".to_string()),
1122            Visibility::Public,
1123            StabilityLevel::Stable,
1124        ),
1125        // Add new enhanced SIMD operations as experimental
1126        create_api_signature(
1127            "simd_add_cache_optimized",
1128            "simd_ops",
1129            vec![
1130                Parameter {
1131                    name: "a".to_string(),
1132                    type_name: "&ArrayView1<Self>".to_string(),
1133                    is_optional: false,
1134                    defaultvalue: None,
1135                },
1136                Parameter {
1137                    name: "b".to_string(),
1138                    type_name: "&ArrayView1<Self>".to_string(),
1139                    is_optional: false,
1140                    defaultvalue: None,
1141                },
1142            ],
1143            Some("Array1<Self>".to_string()),
1144            Visibility::Public,
1145            StabilityLevel::Experimental,
1146        ),
1147        create_api_signature(
1148            "simd_fma_advanced_optimized",
1149            "simd_ops",
1150            vec![
1151                Parameter {
1152                    name: "a".to_string(),
1153                    type_name: "&ArrayView1<Self>".to_string(),
1154                    is_optional: false,
1155                    defaultvalue: None,
1156                },
1157                Parameter {
1158                    name: "b".to_string(),
1159                    type_name: "&ArrayView1<Self>".to_string(),
1160                    is_optional: false,
1161                    defaultvalue: None,
1162                },
1163                Parameter {
1164                    name: "c".to_string(),
1165                    type_name: "&ArrayView1<Self>".to_string(),
1166                    is_optional: false,
1167                    defaultvalue: None,
1168                },
1169            ],
1170            Some("Array1<Self>".to_string()),
1171            Visibility::Public,
1172            StabilityLevel::Experimental,
1173        ),
1174        create_api_signature(
1175            "Version",
1176            "apiversioning",
1177            vec![],
1178            None,
1179            Visibility::Public,
1180            StabilityLevel::Stable,
1181        ),
1182        create_api_signature(
1183            "ApiCompatibilityChecker",
1184            "apiversioning",
1185            vec![],
1186            None,
1187            Visibility::Public,
1188            StabilityLevel::Stable,
1189        ),
1190    ]
1191}
1192
1193/// Convenience function to check current API compatibility
1194#[allow(dead_code)]
1195pub fn check_current_compatibility() -> Result<CompatibilityCheckResult, String> {
1196    let checker = global_api_checker();
1197    let checker_guard = checker.lock().map_err(|e| e.to_string())?;
1198
1199    // For testing, we'll use the same APIs that were frozen
1200    // In a real implementation, this would be generated from actual code analysis
1201    let current_apis = get_test_frozen_apis();
1202
1203    Ok((*checker_guard).check_compatibility(&current_apis))
1204}
1205
1206#[cfg(test)]
1207mod tests {
1208    use super::*;
1209
1210    #[test]
1211    fn test_version_parse() {
1212        assert_eq!(
1213            Version::parse("1.2.3").expect("Operation failed"),
1214            Version::new(1, 2, 3)
1215        );
1216        assert_eq!(
1217            Version::parse("0.1.0").expect("Operation failed"),
1218            Version::new(0, 1, 0)
1219        );
1220        assert_eq!(
1221            Version::parse("10.20.30").expect("Operation failed"),
1222            Version::new(10, 20, 30)
1223        );
1224
1225        assert!(Version::parse("1.2").is_err());
1226        assert!(Version::parse("a.b.c").is_err());
1227        assert!(Version::parse("").is_err());
1228    }
1229
1230    #[test]
1231    fn test_version_compatibility() {
1232        let v1_0_0 = Version::new(1, 0, 0);
1233        let v1_1_0 = Version::new(1, 1, 0);
1234        let v1_0_1 = Version::new(1, 0, 1);
1235        let v2_0_0 = Version::new(2, 0, 0);
1236
1237        assert!(v1_1_0.is_compatible_with(&v1_0_0));
1238        assert!(v1_0_1.is_compatible_with(&v1_0_0));
1239        assert!(!v2_0_0.is_compatible_with(&v1_0_0));
1240        assert!(!v1_0_0.is_compatible_with(&v1_1_0));
1241    }
1242
1243    #[test]
1244    fn test_version_registry() {
1245        let mut registry = VersionRegistry::new();
1246
1247        registry
1248            .register_api("Array", "core", Version::new(0, 1, 0))
1249            .register_api("Matrix", "linalg", Version::new(0, 1, 0))
1250            .register_api("OldArray", "core", Version::new(0, 1, 0));
1251
1252        registry
1253            .deprecate_api("OldArray", Version::new(0, 2, 0), Some("Array".to_string()))
1254            .expect("Operation failed");
1255
1256        let v0_1_0 = Version::new(0, 1, 0);
1257        let v0_2_0 = Version::new(0, 2, 0);
1258
1259        // Check APIs in v0.1.0
1260        let apis_v1 = registry.apis_in_version(&v0_1_0);
1261        assert_eq!(apis_v1.len(), 3);
1262
1263        // Check APIs in v0.2.0
1264        let apis_v2 = registry.apis_in_version(&v0_2_0);
1265        assert_eq!(apis_v2.len(), 2); // OldArray is deprecated
1266
1267        // Check deprecated APIs
1268        let deprecated = registry.deprecated_apis_in_version(&v0_2_0);
1269        assert_eq!(deprecated.len(), 1);
1270        assert_eq!(deprecated[0].name, "OldArray");
1271    }
1272
1273    #[test]
1274    fn test_migration_guide() {
1275        let mut registry = VersionRegistry::new();
1276
1277        registry
1278            .register_api("Feature1", "module1", Version::new(0, 1, 0))
1279            .register_api("Feature2", "module2", Version::new(0, 2, 0))
1280            .register_api("OldFeature", "module1", Version::new(0, 1, 0));
1281
1282        registry
1283            .deprecate_api(
1284                "OldFeature",
1285                Version::new(0, 2, 0),
1286                Some("Feature2".to_string()),
1287            )
1288            .expect("Operation failed");
1289
1290        let guide = registry.migration_guide(&Version::new(0, 1, 0), &Version::new(0, 2, 0));
1291
1292        assert!(guide.contains("Removed APIs"));
1293        assert!(guide.contains("OldFeature"));
1294        assert!(guide.contains("Replacement"));
1295        assert!(guide.contains("Feature2"));
1296        assert!(guide.contains("New APIs"));
1297        assert!(guide.contains("Migration Checklist"));
1298    }
1299
1300    #[test]
1301    fn test_api_compatibility_checker() {
1302        let mut checker = ApiCompatibilityChecker::new();
1303
1304        // Create initial API set
1305        let initial_apis = vec![create_api_signature(
1306            "test_func",
1307            "test_module",
1308            vec![Parameter {
1309                name: "param1".to_string(),
1310                type_name: "i32".to_string(),
1311                is_optional: false,
1312                defaultvalue: None,
1313            }],
1314            Some("String".to_string()),
1315            Visibility::Public,
1316            StabilityLevel::Stable,
1317        )];
1318
1319        // Freeze the APIs
1320        checker
1321            .freeze_apis(initial_apis.clone())
1322            .expect("Operation failed");
1323        assert_eq!(checker.freeze_status, ApiFreezeStatus::Frozen);
1324
1325        // Test compatibility with same APIs
1326        let result = checker.check_compatibility(&initial_apis);
1327        assert!(result.is_compatible);
1328        assert!(result.violations.is_empty());
1329    }
1330
1331    #[test]
1332    fn test_api_signature_changes() {
1333        let mut checker = ApiCompatibilityChecker::for_beta1();
1334
1335        let original_api = create_api_signature(
1336            "test_func",
1337            "test_module",
1338            vec![Parameter {
1339                name: "param1".to_string(),
1340                type_name: "i32".to_string(),
1341                is_optional: false,
1342                defaultvalue: None,
1343            }],
1344            Some("String".to_string()),
1345            Visibility::Public,
1346            StabilityLevel::Stable,
1347        );
1348
1349        checker
1350            .freeze_apis(vec![original_api.clone()])
1351            .expect("Operation failed");
1352
1353        // Test with modified signature (different parameter type)
1354        let modified_api = create_api_signature(
1355            "test_func",
1356            "test_module",
1357            vec![Parameter {
1358                name: "param1".to_string(),
1359                type_name: "f64".to_string(), // Changed type
1360                is_optional: false,
1361                defaultvalue: None,
1362            }],
1363            Some("String".to_string()),
1364            Visibility::Public,
1365            StabilityLevel::Stable,
1366        );
1367
1368        let result = checker.check_compatibility(&[modified_api]);
1369        assert!(!result.is_compatible);
1370        assert!(!result.violations.is_empty());
1371        assert_eq!(
1372            result.violations[0].violation_type,
1373            CompatibilityRuleType::ParameterTypeChange
1374        );
1375    }
1376
1377    #[test]
1378    fn test_api_removal_detection() {
1379        let mut checker = ApiCompatibilityChecker::for_beta1();
1380
1381        let api1 = create_api_signature(
1382            "func1",
1383            "module",
1384            vec![],
1385            None,
1386            Visibility::Public,
1387            StabilityLevel::Stable,
1388        );
1389
1390        let api2 = create_api_signature(
1391            "func2",
1392            "module",
1393            vec![],
1394            None,
1395            Visibility::Public,
1396            StabilityLevel::Stable,
1397        );
1398
1399        checker
1400            .freeze_apis(vec![api1.clone(), api2.clone()])
1401            .expect("Operation failed");
1402
1403        // Test with one API removed
1404        let result = checker.check_compatibility(&[api1]); // api2 is missing
1405        assert!(!result.is_compatible);
1406        assert_eq!(result.violations.len(), 1);
1407        assert_eq!(
1408            result.violations[0].violation_type,
1409            CompatibilityRuleType::PublicApiRemoval
1410        );
1411    }
1412
1413    #[test]
1414    fn test_visibility_reduction() {
1415        let mut checker = ApiCompatibilityChecker::for_beta1();
1416
1417        let public_api = create_api_signature(
1418            "func",
1419            "module",
1420            vec![],
1421            None,
1422            Visibility::Public,
1423            StabilityLevel::Stable,
1424        );
1425
1426        checker
1427            .freeze_apis(vec![public_api])
1428            .expect("Operation failed");
1429
1430        // Test with reduced visibility
1431        let private_api = create_api_signature(
1432            "func",
1433            "module",
1434            vec![],
1435            None,
1436            Visibility::Private, // Reduced from Public
1437            StabilityLevel::Stable,
1438        );
1439
1440        let result = checker.check_compatibility(&[private_api]);
1441        assert!(!result.is_compatible);
1442        assert_eq!(
1443            result.violations[0].violation_type,
1444            CompatibilityRuleType::VisibilityReduction
1445        );
1446    }
1447
1448    #[test]
1449    fn test_new_required_parameter() {
1450        let mut checker = ApiCompatibilityChecker::for_beta1();
1451
1452        let original_api = create_api_signature(
1453            "func",
1454            "module",
1455            vec![Parameter {
1456                name: "param1".to_string(),
1457                type_name: "i32".to_string(),
1458                is_optional: false,
1459                defaultvalue: None,
1460            }],
1461            None,
1462            Visibility::Public,
1463            StabilityLevel::Stable,
1464        );
1465
1466        checker
1467            .freeze_apis(vec![original_api])
1468            .expect("Operation failed");
1469
1470        // Test with new required parameter
1471        let modified_api = create_api_signature(
1472            "func",
1473            "module",
1474            vec![
1475                Parameter {
1476                    name: "param1".to_string(),
1477                    type_name: "i32".to_string(),
1478                    is_optional: false,
1479                    defaultvalue: None,
1480                },
1481                Parameter {
1482                    name: "param2".to_string(),
1483                    type_name: "String".to_string(),
1484                    is_optional: false, // New required parameter
1485                    defaultvalue: None,
1486                },
1487            ],
1488            None,
1489            Visibility::Public,
1490            StabilityLevel::Stable,
1491        );
1492
1493        let result = checker.check_compatibility(&[modified_api]);
1494        assert!(!result.is_compatible);
1495        assert_eq!(
1496            result.violations[0].violation_type,
1497            CompatibilityRuleType::NewRequiredParameter
1498        );
1499    }
1500
1501    #[test]
1502    fn test_compatibility_report_generation() {
1503        let mut checker = ApiCompatibilityChecker::for_beta1();
1504
1505        let original_api = create_api_signature(
1506            "test_func",
1507            "test_module",
1508            vec![],
1509            None,
1510            Visibility::Public,
1511            StabilityLevel::Stable,
1512        );
1513
1514        checker
1515            .freeze_apis(vec![original_api])
1516            .expect("Operation failed");
1517
1518        // Test with removed API
1519        let result = checker.check_compatibility(&[]); // All APIs removed
1520        let report = checker.generate_compatibility_report(&result);
1521
1522        assert!(report.contains("API Compatibility Report"));
1523        assert!(report.contains("Freeze Status"));
1524        assert!(report.contains("Compatibility Violations"));
1525        assert!(report.contains("Next Steps"));
1526        assert!(report.contains("💥")); // Breaking change icon
1527    }
1528
1529    #[test]
1530    fn test_beta1_initialization() {
1531        // Test that we can initialize the Beta 1 freeze
1532        let result = initialize_beta1_freeze();
1533        assert!(result.is_ok());
1534
1535        // Test compatibility check
1536        let compat_result = check_current_compatibility();
1537        assert!(compat_result.is_ok());
1538
1539        let result = compat_result.expect("Operation failed");
1540        // Should be compatible since we're checking against the same APIs
1541        assert!(result.is_compatible);
1542    }
1543
1544    #[test]
1545    fn test_api_signature_creation() {
1546        let signature = create_api_signature(
1547            "test_func",
1548            "test_module",
1549            vec![Parameter {
1550                name: "param".to_string(),
1551                type_name: "i32".to_string(),
1552                is_optional: false,
1553                defaultvalue: None,
1554            }],
1555            Some("String".to_string()),
1556            Visibility::Public,
1557            StabilityLevel::Stable,
1558        );
1559
1560        assert_eq!(signature.name, "test_func");
1561        assert_eq!(signature.module, "test_module");
1562        assert_eq!(signature.parameters.len(), 1);
1563        assert_eq!(signature.return_type, Some("String".to_string()));
1564        assert_eq!(signature.visibility, Visibility::Public);
1565        assert_eq!(signature.stability, StabilityLevel::Stable);
1566        assert!(signature.signature_hash != 0); // Should have a hash
1567    }
1568}