1pub mod compatibility;
63pub mod deprecation;
64pub mod migration;
65pub mod negotiation;
66pub mod semantic;
67
68use crate::error::CoreError;
69use std::collections::{BTreeSet, HashMap};
70
71use serde::{Deserialize, Serialize};
72
73pub use compatibility::{CompatibilityChecker, CompatibilityLevel, CompatibilityReport};
75pub use deprecation::{DeprecationManager, DeprecationPolicy, DeprecationStatus};
76pub use migration::{MigrationManager, MigrationPlan, MigrationStep};
77pub use negotiation::{ClientCapabilities, NegotiationResult, VersionNegotiator};
78pub use semantic::{Version, VersionBuilder, VersionConstraint, VersionRange};
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub struct ApiVersion {
83 pub version: Version,
85 pub release_date: chrono::DateTime<chrono::Utc>,
87 pub stability: StabilityLevel,
89 pub support_status: SupportStatus,
91 pub end_of_life: Option<chrono::DateTime<chrono::Utc>>,
93 pub features: BTreeSet<String>,
95 pub breakingchanges: Vec<String>,
97 pub new_features: Vec<String>,
99 pub bug_fixes: Vec<String>,
101 pub deprecated_features: Vec<String>,
103 pub min_clientversion: Option<Version>,
105 pub max_clientversion: Option<Version>,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
111pub enum StabilityLevel {
112 Experimental,
114 Alpha,
116 Beta,
118 Stable,
120 Mature,
122 Legacy,
124}
125
126impl StabilityLevel {
127 #[must_use]
129 pub const fn as_str(&self) -> &'static str {
130 match self {
131 Self::Experimental => "experimental",
132 Self::Alpha => "alpha",
133 Self::Beta => "beta",
134 Self::Stable => "stable",
135 Self::Mature => "mature",
136 Self::Legacy => "legacy",
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
143pub enum SupportStatus {
144 Active,
146 Maintenance,
148 Deprecated,
150 EndOfLife,
152 SecurityOnly,
154}
155
156impl SupportStatus {
157 #[must_use]
159 pub const fn as_str(&self) -> &'static str {
160 match self {
161 Self::Active => "active",
162 Self::Maintenance => "maintenance",
163 Self::Deprecated => "deprecated",
164 Self::EndOfLife => "end_of_life",
165 Self::SecurityOnly => "security_only",
166 }
167 }
168}
169
170pub struct VersionManager {
172 versions: HashMap<Version, ApiVersion>,
174 currentversion: Option<Version>,
176 compatibility_checker: CompatibilityChecker,
178 negotiator: VersionNegotiator,
180 migration_manager: MigrationManager,
182 deprecation_manager: DeprecationManager,
184}
185
186impl VersionManager {
187 #[must_use]
189 pub fn new() -> Self {
190 Self {
191 versions: HashMap::new(),
192 currentversion: None,
193 compatibility_checker: CompatibilityChecker::new(),
194 negotiator: VersionNegotiator::new(),
195 migration_manager: MigrationManager::new(),
196 deprecation_manager: DeprecationManager::new(),
197 }
198 }
199
200 pub fn registerversion(&mut self, apiversion: ApiVersion) -> Result<(), CoreError> {
206 let version = apiversion.version.clone();
207
208 if self.versions.contains_key(&version) {
210 return Err(CoreError::ComputationError(
211 crate::error::ErrorContext::new(format!("Version {version} is already registered")),
212 ));
213 }
214
215 self.compatibility_checker.register_version(&apiversion)?;
217
218 self.migration_manager.register_version(&apiversion)?;
220
221 self.deprecation_manager.register_version(&apiversion)?;
223
224 self.versions.insert(version, apiversion);
225 Ok(())
226 }
227
228 pub fn set_currentversion(&mut self, version: Version) -> Result<(), CoreError> {
234 if !self.versions.contains_key(&version) {
235 return Err(CoreError::ComputationError(
236 crate::error::ErrorContext::new(format!("Version {version} is not registered")),
237 ));
238 }
239
240 self.currentversion = Some(version);
241 Ok(())
242 }
243
244 #[must_use]
246 pub fn currentversion(&self) -> Option<&Version> {
247 self.currentversion.as_ref()
248 }
249
250 #[must_use]
252 pub fn getversions(&self) -> Vec<&ApiVersion> {
253 let mut versions: Vec<_> = self.versions.values().collect();
254 versions.sort_by(|a, b| a.version.cmp(&b.version));
255 versions
256 }
257
258 #[must_use]
260 pub fn get_supportedversions(&self) -> Vec<&ApiVersion> {
261 self.versions
262 .values()
263 .filter(|v| {
264 matches!(
265 v.support_status,
266 SupportStatus::Active | SupportStatus::Maintenance
267 )
268 })
269 .collect()
270 }
271
272 #[must_use]
274 pub fn getversion(&self, version: &Version) -> Option<&ApiVersion> {
275 self.versions.get(version)
276 }
277
278 pub fn check_compatibility(
284 &self,
285 fromversion: &Version,
286 toversion: &Version,
287 ) -> Result<CompatibilityLevel, CoreError> {
288 self.compatibility_checker
289 .check_compatibility(fromversion, toversion)
290 }
291
292 pub fn get_compatibility_report(
298 &self,
299 fromversion: &Version,
300 toversion: &Version,
301 ) -> Result<CompatibilityReport, CoreError> {
302 self.compatibility_checker
303 .get_compatibility_report(fromversion, toversion)
304 }
305
306 pub fn negotiateversion(
312 &self,
313 client_capabilities: &ClientCapabilities,
314 ) -> Result<NegotiationResult, CoreError> {
315 let supportedversions: Vec<_> = self
316 .get_supportedversions()
317 .into_iter()
318 .map(|v| &v.version)
319 .collect();
320
321 self.negotiator
322 .negotiate(client_capabilities, &supportedversions)
323 }
324
325 pub fn get_migration_plan(
331 &self,
332 fromversion: &Version,
333 toversion: &Version,
334 ) -> Result<MigrationPlan, CoreError> {
335 self.migration_manager
336 .create_migration_plan(fromversion, toversion)
337 }
338
339 #[must_use]
341 pub fn isversion_deprecated(&self, version: &Version) -> bool {
342 if let Some(apiversion) = self.versions.get(version) {
343 matches!(
344 apiversion.support_status,
345 SupportStatus::Deprecated | SupportStatus::EndOfLife
346 )
347 } else {
348 false
349 }
350 }
351
352 #[must_use]
354 pub fn get_deprecation_status(&self, version: &Version) -> Option<DeprecationStatus> {
355 self.deprecation_manager.get_deprecation_status(version)
356 }
357
358 pub fn update_deprecation_status(
364 &mut self,
365 version: &Version,
366 status: DeprecationStatus,
367 ) -> Result<(), CoreError> {
368 self.deprecation_manager.update_status(version, status)
369 }
370
371 #[must_use]
373 pub fn get_latest_in_major(&self, major: u64) -> Option<&ApiVersion> {
374 self.versions
375 .values()
376 .filter(|v| v.version.major() == major)
377 .max_by(|a, b| a.version.cmp(&b.version))
378 }
379
380 #[must_use]
382 pub fn get_latest_stable(&self) -> Option<&ApiVersion> {
383 self.versions
384 .values()
385 .filter(|v| {
386 v.stability == StabilityLevel::Stable || v.stability == StabilityLevel::Mature
387 })
388 .filter(|v| v.support_status == SupportStatus::Active)
389 .max_by(|a, b| a.version.cmp(&b.version))
390 }
391
392 #[must_use]
394 pub fn has_upgrade_path(&self, fromversion: &Version, toversion: &Version) -> bool {
395 self.migration_manager
396 .has_migration_path(fromversion, toversion)
397 }
398
399 pub fn validate_constraint(
405 &self,
406 constraint: &VersionConstraint,
407 ) -> Result<Vec<&Version>, CoreError> {
408 let matchingversions: Vec<_> = self
409 .versions
410 .keys()
411 .filter(|v| constraint.matches(v))
412 .collect();
413
414 Ok(matchingversions)
415 }
416
417 #[must_use]
419 pub fn getversion_statistics(&self) -> VersionStatistics {
420 let mut stats = VersionStatistics::default();
421
422 for apiversion in self.versions.values() {
423 stats.totalversions += 1;
424
425 match apiversion.stability {
426 StabilityLevel::Experimental => stats.experimentalversions += 1,
427 StabilityLevel::Alpha => stats.alphaversions += 1,
428 StabilityLevel::Beta => stats.betaversions += 1,
429 StabilityLevel::Stable => stats.stableversions += 1,
430 StabilityLevel::Mature => stats.matureversions += 1,
431 StabilityLevel::Legacy => stats.legacyversions += 1,
432 }
433
434 match apiversion.support_status {
435 SupportStatus::Active => stats.activeversions += 1,
436 SupportStatus::Maintenance => stats.maintenanceversions += 1,
437 SupportStatus::Deprecated => stats.deprecatedversions += 1,
438 SupportStatus::EndOfLife => stats.end_of_lifeversions += 1,
439 SupportStatus::SecurityOnly => stats.security_onlyversions += 1,
440 }
441 }
442
443 stats
444 }
445
446 pub fn perform_maintenance(&mut self) -> Result<MaintenanceReport, CoreError> {
452 let mut report = MaintenanceReport::default();
453 let now = chrono::Utc::now();
454
455 for (version, apiversion) in &mut self.versions {
457 if let Some(eol_date) = apiversion.end_of_life {
458 if now > eol_date && apiversion.support_status != SupportStatus::EndOfLife {
459 apiversion.support_status = SupportStatus::EndOfLife;
460 report.versions_marked_eol.push(version.clone());
461 }
462 }
463 }
464
465 let deprecation_updates = self.deprecation_manager.perform_maintenance()?;
467 report.deprecation_updates = deprecation_updates.len();
468
469 let migration_cleanup = self.migration_manager.cleanup_old_plans()?;
471 report.migration_plans_cleaned = migration_cleanup;
472
473 Ok(report)
474 }
475}
476
477impl Default for VersionManager {
478 fn default() -> Self {
479 Self::new()
480 }
481}
482
483#[derive(Debug, Clone, Default, Serialize, Deserialize)]
485pub struct VersionStatistics {
486 pub totalversions: usize,
488 pub experimentalversions: usize,
490 pub alphaversions: usize,
492 pub betaversions: usize,
494 pub stableversions: usize,
496 pub matureversions: usize,
498 pub legacyversions: usize,
500 pub activeversions: usize,
502 pub maintenanceversions: usize,
504 pub deprecatedversions: usize,
506 pub end_of_lifeversions: usize,
508 pub security_onlyversions: usize,
510}
511
512#[derive(Debug, Clone, Default, Serialize, Deserialize)]
514pub struct MaintenanceReport {
515 pub versions_marked_eol: Vec<Version>,
517 pub deprecation_updates: usize,
519 pub migration_plans_cleaned: usize,
521}
522
523pub struct ApiVersionBuilder {
525 version: Option<Version>,
526 release_date: chrono::DateTime<chrono::Utc>,
527 stability: StabilityLevel,
528 support_status: SupportStatus,
529 end_of_life: Option<chrono::DateTime<chrono::Utc>>,
530 features: BTreeSet<String>,
531 breakingchanges: Vec<String>,
532 new_features: Vec<String>,
533 bug_fixes: Vec<String>,
534 deprecated_features: Vec<String>,
535 min_clientversion: Option<Version>,
536 max_clientversion: Option<Version>,
537}
538
539impl ApiVersionBuilder {
540 #[must_use]
542 pub fn new(version: Version) -> Self {
543 Self {
544 version: Some(version),
545 release_date: chrono::Utc::now(),
546 stability: StabilityLevel::Stable,
547 support_status: SupportStatus::Active,
548 end_of_life: None,
549 features: BTreeSet::new(),
550 breakingchanges: Vec::new(),
551 new_features: Vec::new(),
552 bug_fixes: Vec::new(),
553 deprecated_features: Vec::new(),
554 min_clientversion: None,
555 max_clientversion: None,
556 }
557 }
558
559 #[must_use]
561 pub fn release_date(mut self, date: chrono::DateTime<chrono::Utc>) -> Self {
562 self.release_date = date;
563 self
564 }
565
566 #[must_use]
568 pub fn stability(mut self, stability: StabilityLevel) -> Self {
569 self.stability = stability;
570 self
571 }
572
573 #[must_use]
575 pub fn support_status(mut self, status: SupportStatus) -> Self {
576 self.support_status = status;
577 self
578 }
579
580 #[must_use]
582 pub fn end_of_life(mut self, date: chrono::DateTime<chrono::Utc>) -> Self {
583 self.end_of_life = Some(date);
584 self
585 }
586
587 #[must_use]
589 pub fn feature(mut self, feature: &str) -> Self {
590 self.features.insert(feature.to_string());
591 self
592 }
593
594 #[must_use]
596 pub fn breaking_change(mut self, change: &str) -> Self {
597 self.breakingchanges.push(change.to_string());
598 self
599 }
600
601 #[must_use]
603 pub fn new_feature(mut self, feature: &str) -> Self {
604 self.new_features.push(feature.to_string());
605 self
606 }
607
608 #[must_use]
610 pub fn bug_fix(mut self, fix: &str) -> Self {
611 self.bug_fixes.push(fix.to_string());
612 self
613 }
614
615 #[must_use]
617 pub fn deprecated_feature(mut self, feature: &str) -> Self {
618 self.deprecated_features.push(feature.to_string());
619 self
620 }
621
622 #[must_use]
624 pub fn min_clientversion(mut self, version: Version) -> Self {
625 self.min_clientversion = Some(version);
626 self
627 }
628
629 #[must_use]
631 pub fn max_clientversion(mut self, version: Version) -> Self {
632 self.max_clientversion = Some(version);
633 self
634 }
635
636 pub fn build(self) -> Result<ApiVersion, CoreError> {
642 let version = self.version.ok_or_else(|| {
643 CoreError::ComputationError(crate::error::ErrorContext::new(
644 "Version is required".to_string(),
645 ))
646 })?;
647
648 Ok(ApiVersion {
649 version,
650 release_date: self.release_date,
651 stability: self.stability,
652 support_status: self.support_status,
653 end_of_life: self.end_of_life,
654 features: self.features,
655 breakingchanges: self.breakingchanges,
656 new_features: self.new_features,
657 bug_fixes: self.bug_fixes,
658 deprecated_features: self.deprecated_features,
659 min_clientversion: self.min_clientversion,
660 max_clientversion: self.max_clientversion,
661 })
662 }
663}
664
665#[cfg(test)]
666mod tests {
667 use super::*;
668
669 #[test]
670 fn testversion_manager_creation() {
671 let manager = VersionManager::new();
672 assert!(manager.currentversion().is_none());
673 assert_eq!(manager.getversions().len(), 0);
674 }
675
676 #[test]
677 fn test_apiversion_builder() {
678 let version = Version::parse("1.0.0").unwrap();
679 let apiversion = ApiVersionBuilder::new(version)
680 .stability(StabilityLevel::Stable)
681 .feature("feature1")
682 .new_feature("New awesome feature")
683 .build()
684 .unwrap();
685
686 assert_eq!(apiversion.version.to_string(), "1.0.0");
687 assert_eq!(apiversion.stability, StabilityLevel::Stable);
688 assert!(apiversion.features.contains("feature1"));
689 assert_eq!(apiversion.new_features.len(), 1);
690 }
691
692 #[test]
693 fn testversion_registration() {
694 let mut manager = VersionManager::new();
695 let version = Version::parse("1.0.0").unwrap();
696 let apiversion = ApiVersionBuilder::new(version.clone()).build().unwrap();
697
698 manager.registerversion(apiversion).unwrap();
699 assert_eq!(manager.getversions().len(), 1);
700 assert!(manager.getversion(&version).is_some());
701 }
702
703 #[test]
704 fn test_currentversion_setting() {
705 let mut manager = VersionManager::new();
706 let version = Version::parse("1.0.0").unwrap();
707 let apiversion = ApiVersionBuilder::new(version.clone()).build().unwrap();
708
709 manager.registerversion(apiversion).unwrap();
710 manager.set_currentversion(version.clone()).unwrap();
711 assert_eq!(manager.currentversion(), Some(&version));
712 }
713
714 #[test]
715 fn test_stability_levels() {
716 assert_eq!(StabilityLevel::Experimental.as_str(), "experimental");
717 assert_eq!(StabilityLevel::Stable.as_str(), "stable");
718 assert_eq!(StabilityLevel::Mature.as_str(), "mature");
719
720 assert!(StabilityLevel::Experimental < StabilityLevel::Alpha);
721 assert!(StabilityLevel::Stable > StabilityLevel::Beta);
722 }
723
724 #[test]
725 fn test_support_status() {
726 assert_eq!(SupportStatus::Active.as_str(), "active");
727 assert_eq!(SupportStatus::Deprecated.as_str(), "deprecated");
728 assert_eq!(SupportStatus::EndOfLife.as_str(), "end_of_life");
729 }
730
731 #[test]
732 fn testversion_statistics() {
733 let mut manager = VersionManager::new();
734
735 let v1 = ApiVersionBuilder::new(Version::parse("1.0.0").unwrap())
737 .stability(StabilityLevel::Stable)
738 .build()
739 .unwrap();
740 let v2 = ApiVersionBuilder::new(Version::parse("2.0.0").unwrap())
741 .stability(StabilityLevel::Beta)
742 .support_status(SupportStatus::Maintenance)
743 .build()
744 .unwrap();
745
746 manager.registerversion(v1).unwrap();
747 manager.registerversion(v2).unwrap();
748
749 let stats = manager.getversion_statistics();
750 assert_eq!(stats.totalversions, 2);
751 assert_eq!(stats.stableversions, 1);
752 assert_eq!(stats.betaversions, 1);
753 assert_eq!(stats.activeversions, 1);
754 assert_eq!(stats.maintenanceversions, 1);
755 }
756}