scirs2_core/api_freeze/
compatibility.rs1use crate::apiversioning::{global_registry_mut, Version};
7use crate::error::{CoreError, CoreResult, ErrorContext};
8
9#[allow(dead_code)]
11pub fn is_api_available(apiname: &str, module: &str) -> bool {
12 let registry = global_registry_mut();
13 let current_version = current_libraryversion();
14
15 registry
16 .apis_in_version(¤t_version)
17 .iter()
18 .any(|entry| entry.name == apiname && entry.module == module)
19}
20
21#[allow(dead_code)]
23pub fn check_apis_available(apis: &[(&str, &str)]) -> CoreResult<()> {
24 let mut missing = Vec::new();
25
26 for (apiname, module) in apis {
27 if !is_api_available(apiname, module) {
28 missing.push(format!("{module}::{apiname}"));
29 }
30 }
31
32 if missing.is_empty() {
33 Ok(())
34 } else {
35 Err(CoreError::ValidationError(ErrorContext::new(format!(
36 "Missing APIs: {}",
37 missing.join(", ")
38 ))))
39 }
40}
41
42#[allow(dead_code)]
44pub fn current_libraryversion() -> Version {
45 let versionstr = env!("CARGO_PKG_VERSION");
47 Version::parse(versionstr).unwrap_or_else(|_| {
48 Version::new(0, 1, 0)
50 })
51}
52
53#[allow(dead_code)]
55pub fn is_version_compatible(required: &Version) -> bool {
56 let current = current_libraryversion();
57 current.is_compatible_with(required)
58}
59
60#[macro_export]
62macro_rules! require_api {
63 ($api:expr, $module:expr) => {
64 const _: () = {
65 assert!(true, concat!("API required: ", $module, "::", $api));
68 };
69 };
70}
71
72pub struct ApiCompatibilityChecker {
74 required_apis: Vec<(String, String)>,
75 minimum_version: Option<Version>,
76}
77
78impl Default for ApiCompatibilityChecker {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84impl ApiCompatibilityChecker {
85 pub fn new() -> Self {
87 Self {
88 required_apis: Vec::new(),
89 minimum_version: None,
90 }
91 }
92
93 pub fn require_api(mut self, apiname: impl Into<String>, module: impl Into<String>) -> Self {
95 self.required_apis.push((apiname.into(), module.into()));
96 self
97 }
98
99 pub fn minimum_version(mut self, version: Version) -> Self {
101 self.minimum_version = Some(version);
102 self
103 }
104
105 pub fn check(&self) -> CoreResult<()> {
107 if let Some(min_version) = &self.minimum_version {
109 if !is_version_compatible(min_version) {
110 return Err(CoreError::ValidationError(ErrorContext::new(format!(
111 "Version {} required, but current version is {}",
112 min_version,
113 current_libraryversion()
114 ))));
115 }
116 }
117
118 let apis: Vec<(&str, &str)> = self
120 .required_apis
121 .iter()
122 .map(|(api, module)| (api.as_str(), module.as_str()))
123 .collect();
124
125 check_apis_available(&apis)
126 }
127}