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]
70macro_rules! require_api {
71 ($api:expr, $module:expr) => {
72 const _: () = {
73 let _ = concat!("API required: ", $module, "::", $api);
74 };
75 };
76}
77
78pub struct ApiCompatibilityChecker {
80 required_apis: Vec<(String, String)>,
81 minimum_version: Option<Version>,
82}
83
84impl Default for ApiCompatibilityChecker {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90impl ApiCompatibilityChecker {
91 pub fn new() -> Self {
93 Self {
94 required_apis: Vec::new(),
95 minimum_version: None,
96 }
97 }
98
99 pub fn require_api(mut self, apiname: impl Into<String>, module: impl Into<String>) -> Self {
101 self.required_apis.push((apiname.into(), module.into()));
102 self
103 }
104
105 pub fn minimum_version(mut self, version: Version) -> Self {
107 self.minimum_version = Some(version);
108 self
109 }
110
111 pub fn check(&self) -> CoreResult<()> {
113 if let Some(min_version) = &self.minimum_version {
115 if !is_version_compatible(min_version) {
116 return Err(CoreError::ValidationError(ErrorContext::new(format!(
117 "Version {} required, but current version is {}",
118 min_version,
119 current_libraryversion()
120 ))));
121 }
122 }
123
124 let apis: Vec<(&str, &str)> = self
126 .required_apis
127 .iter()
128 .map(|(api, module)| (api.as_str(), module.as_str()))
129 .collect();
130
131 check_apis_available(&apis)
132 }
133}