scirs2_interpolate/
deprecation.rs

1//! Deprecation policy and warnings for SciRS2 interpolation library
2//!
3//! This module provides a standardized approach to handling deprecation of experimental
4//! features, API changes, and maintenance of backward compatibility.
5//!
6//! # Overview
7//!
8//! The deprecation system supports:
9//! - Structured deprecation warnings with migration paths
10//! - Feature lifecycle management (experimental → stable → deprecated → removed)
11//! - Version-based deprecation tracking
12//! - Alternative function suggestions
13//!
14//! # Usage
15//!
16//! ```rust
17//! use scirs2_interpolate::{deprecated_function, deprecation::DeprecationLevel};
18//!
19//! pub fn old_rbf_function() {
20//!     deprecated_function!(
21//!         name = "old_rbf_function",
22//!         since = "0.1.0",
23//!         reason = "Use make_enhanced_rbf_interpolator instead",
24//!         alternative = "enhanced_rbf::make_enhanced_rbf_interpolator"
25//!     );
26//!     // Implementation
27//! }
28//! ```
29
30use std::collections::HashMap;
31use std::sync::{Mutex, OnceLock};
32
33/// Global deprecation policy configuration
34static DEPRECATION_CONFIG: OnceLock<Mutex<DeprecationConfig>> = OnceLock::new();
35
36/// Deprecation configuration and tracking
37#[derive(Debug, Clone)]
38pub struct DeprecationConfig {
39    /// Whether to show deprecation warnings
40    pub show_warnings: bool,
41
42    /// Whether to treat deprecation warnings as errors
43    pub warnings_as_errors: bool,
44
45    /// Maximum number of times to show each deprecation warning
46    pub max_warning_count: usize,
47
48    /// Track warning counts per function
49    pub warning_counts: HashMap<String, usize>,
50
51    /// Current library version for deprecation context
52    pub current_version: String,
53}
54
55impl Default for DeprecationConfig {
56    fn default() -> Self {
57        Self {
58            show_warnings: true,
59            warnings_as_errors: false,
60            max_warning_count: 3,
61            warning_counts: HashMap::new(),
62            current_version: "0.1.0-beta.4".to_string(),
63        }
64    }
65}
66
67/// Severity level of deprecation
68#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
69pub enum DeprecationLevel {
70    /// Feature is experimental and may change
71    Experimental,
72    /// Feature is deprecated but still supported
73    Soft,
74    /// Feature will be removed in next major version
75    Hard,
76    /// Feature is removed and will cause compilation errors
77    Removed,
78}
79
80/// Information about a deprecated feature
81#[derive(Debug, Clone)]
82pub struct DeprecationInfo {
83    /// Function or feature name
84    pub name: String,
85
86    /// Version when deprecation was introduced
87    pub since: String,
88
89    /// Version when feature will be removed (if known)
90    pub remove_in: Option<String>,
91
92    /// Deprecation level
93    pub level: DeprecationLevel,
94
95    /// Reason for deprecation
96    pub reason: String,
97
98    /// Suggested alternative or migration path
99    pub alternative: Option<String>,
100
101    /// Additional notes for migration
102    pub migration_notes: Option<String>,
103}
104
105/// Initialize deprecation system with default configuration
106#[allow(dead_code)]
107pub fn init_deprecation_system() {
108    let _ = DEPRECATION_CONFIG.set(Mutex::new(DeprecationConfig::default()));
109}
110
111/// Configure deprecation warning behavior
112#[allow(dead_code)]
113pub fn configure_deprecation(config: DeprecationConfig) {
114    init_deprecation_system();
115    if let Ok(mut global_config) = DEPRECATION_CONFIG.get().unwrap().lock() {
116        *global_config = config;
117    }
118}
119
120/// Issue a deprecation warning if enabled
121#[allow(dead_code)]
122pub fn issue_deprecation_warning(info: &DeprecationInfo) {
123    init_deprecation_system();
124
125    if let Ok(mut config) = DEPRECATION_CONFIG.get().unwrap().lock() {
126        if !config.show_warnings {
127            return;
128        }
129
130        let count = config.warning_counts.entry(info.name.clone()).or_insert(0);
131        *count += 1;
132
133        if *count > config.max_warning_count {
134            return;
135        }
136
137        let warning_msg = format_deprecation_warning(info);
138
139        if config.warnings_as_errors {
140            panic!("Deprecation error: {warning_msg}");
141        } else {
142            eprintln!("Deprecation warning: {warning_msg}");
143        }
144    }
145}
146
147/// Format a deprecation warning message
148#[allow(dead_code)]
149fn format_deprecation_warning(info: &DeprecationInfo) -> String {
150    let mut msg = format!(
151        "Function '{}' is deprecated since v{}",
152        info.name, info.since
153    );
154
155    if let Some(remove_version) = &info.remove_in {
156        msg.push_str(&format!(" and will be removed in v{remove_version}"));
157    }
158
159    msg.push_str(&format!(": {}", info.reason));
160
161    if let Some(alternative) = &info.alternative {
162        msg.push_str(&format!(" Use '{alternative}' instead."));
163    }
164
165    if let Some(notes) = &info.migration_notes {
166        msg.push_str(&format!(" Migration notes: {notes}"));
167    }
168
169    msg
170}
171
172/// Macro to mark a function as deprecated with structured information
173#[macro_export]
174macro_rules! deprecated_function {
175    (
176        name = $name:expr,
177        since = $since:expr,
178        reason = $reason:expr
179        $(, alternative = $alternative:expr)?
180        $(, remove_in = $remove_in:expr)?
181        $(, migration_notes = $notes:expr)?
182        $(, level = $level:expr)?
183    ) => {
184        {
185            use $crate::deprecation::{DeprecationInfo, DeprecationLevel, issue_deprecation_warning};
186
187            let info = DeprecationInfo {
188                name: $name.to_string(),
189                since: $since.to_string(),
190                remove_in: None $(.or(Some($remove_in.to_string())))?,
191                level: DeprecationLevel::Soft $(.max($level))?,
192                reason: $reason.to_string(),
193                alternative: None $(.or(Some($alternative.to_string())))?,
194                migration_notes: None $(.or(Some($notes.to_string())))?,
195            };
196
197            issue_deprecation_warning(&info);
198        }
199    };
200}
201
202/// Experimental feature marker
203#[macro_export]
204macro_rules! experimental_feature {
205    ($name:expr, $description:expr) => {{
206        use $crate::deprecation::{issue_deprecation_warning, DeprecationInfo, DeprecationLevel};
207
208        let info = DeprecationInfo {
209            name: $name.to_string(),
210            since: "0.1.0-beta.1".to_string(),
211            remove_in: None,
212            level: DeprecationLevel::Experimental,
213            reason: format!("This is an experimental feature: {}", $description),
214            alternative: None,
215            migration_notes: Some("API may change in future versions".to_string()),
216        };
217
218        issue_deprecation_warning(&info);
219    }};
220}
221
222/// Registry of deprecated and experimental features in the library
223pub struct FeatureRegistry;
224
225impl FeatureRegistry {
226    /// Get list of all deprecated features in the current version
227    pub fn deprecated_features() -> Vec<DeprecationInfo> {
228        vec![
229            // GPU acceleration features (experimental)
230            DeprecationInfo {
231                name: "gpu_accelerated".to_string(),
232                since: "0.1.0-alpha.1".to_string(),
233                remove_in: None,
234                level: DeprecationLevel::Experimental,
235                reason: "GPU acceleration is experimental and may change".to_string(),
236                alternative: None,
237                migration_notes: Some(
238                    "Enable with 'gpu' feature flag. API subject to change.".to_string(),
239                ),
240            },
241            // Neural enhanced interpolation (experimental)
242            DeprecationInfo {
243                name: "neural_enhanced".to_string(),
244                since: "0.1.0-alpha.3".to_string(),
245                remove_in: None,
246                level: DeprecationLevel::Experimental,
247                reason: "Neural enhanced interpolation is experimental".to_string(),
248                alternative: None,
249                migration_notes: Some(
250                    "API may change significantly in future versions".to_string(),
251                ),
252            },
253            // Physics-informed interpolation (experimental)
254            DeprecationInfo {
255                name: "physics_informed".to_string(),
256                since: "0.1.0-alpha.4".to_string(),
257                remove_in: None,
258                level: DeprecationLevel::Experimental,
259                reason: "Physics-informed methods are experimental".to_string(),
260                alternative: None,
261                migration_notes: Some(
262                    "Consider using standard RBF or spline methods for production".to_string(),
263                ),
264            },
265            // Some Kriging variants with warnings
266            DeprecationInfo {
267                name: "experimental_kriging_variants".to_string(),
268                since: "0.1.0-alpha.5".to_string(),
269                remove_in: None,
270                level: DeprecationLevel::Experimental,
271                reason: "Some advanced Kriging variants show implementation warnings".to_string(),
272                alternative: Some("enhanced_kriging::make_enhanced_kriging".to_string()),
273                migration_notes: Some(
274                    "Use stable Kriging implementations for production workloads".to_string(),
275                ),
276            },
277        ]
278    }
279
280    /// Get features planned for removal in specific version
281    pub fn features_removed_in(version: &str) -> Vec<DeprecationInfo> {
282        Self::deprecated_features()
283            .into_iter()
284            .filter(|f| f.remove_in.as_ref().map(|v| v == version).unwrap_or(false))
285            .collect()
286    }
287
288    /// Check if a feature is deprecated
289    pub fn is_feature_deprecated(featurename: &str) -> bool {
290        Self::deprecated_features()
291            .iter()
292            .any(|f| f.name == featurename)
293    }
294
295    /// Get deprecation info for a specific feature
296    pub fn get_deprecation_info(featurename: &str) -> Option<DeprecationInfo> {
297        Self::deprecated_features()
298            .into_iter()
299            .find(|f| f.name == featurename)
300    }
301}
302
303/// Convenience functions for common deprecation scenarios
304pub mod convenience {
305    use crate::experimental_feature;
306
307    /// Mark a GPU feature as experimental
308    pub fn warn_gpu_experimental(featurename: &str) {
309        experimental_feature!(
310            featurename,
311            "GPU acceleration support is experimental and may change significantly"
312        );
313    }
314
315    /// Mark a neural network feature as experimental  
316    pub fn warn_neural_experimental(featurename: &str) {
317        experimental_feature!(
318            featurename,
319            "Neural network enhanced interpolation is experimental"
320        );
321    }
322
323    /// Mark a physics-informed feature as experimental
324    pub fn warn_physics_experimental(featurename: &str) {
325        experimental_feature!(
326            featurename,
327            "Physics-informed interpolation methods are experimental"
328        );
329    }
330
331    /// Issue a matrix conditioning warning
332    pub fn warn_matrix_conditioning(condition_number: f64, context: &str) {
333        if condition_number > 1e14 {
334            eprintln!(
335                "NUMERICAL WARNING: Poor matrix conditioning (condition number: {condition_number:.2e}) in {context}. \
336                Consider regularization or data preprocessing."
337            );
338        }
339    }
340
341    /// Issue a performance warning for large datasets
342    pub fn warn_performance_large_dataset(operation: &str, size: usize, threshold: usize) {
343        if size > threshold {
344            eprintln!(
345                "PERFORMANCE WARNING: {operation} with {size} data points may be slow. \
346                Consider using fast variants or GPU acceleration if available."
347            );
348        }
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355
356    #[test]
357    fn test_deprecation_config() {
358        let config = DeprecationConfig::default();
359        assert!(config.show_warnings);
360        assert!(!config.warnings_as_errors);
361        assert_eq!(config.max_warning_count, 3);
362    }
363
364    #[test]
365    fn test_feature_registry() {
366        let deprecated = FeatureRegistry::deprecated_features();
367        assert!(!deprecated.is_empty());
368
369        let gpu_deprecated = FeatureRegistry::is_feature_deprecated("gpu_accelerated");
370        assert!(gpu_deprecated);
371
372        let standard_feature = FeatureRegistry::is_feature_deprecated("spline");
373        assert!(!standard_feature);
374    }
375
376    #[test]
377    fn test_deprecation_info() {
378        let info = DeprecationInfo {
379            name: "test_function".to_string(),
380            since: "0.1.0".to_string(),
381            remove_in: Some("0.2.0".to_string()),
382            level: DeprecationLevel::Soft,
383            reason: "Test deprecation".to_string(),
384            alternative: Some("new_function".to_string()),
385            migration_notes: Some("Easy migration".to_string()),
386        };
387
388        let message = format_deprecation_warning(&info);
389        assert!(message.contains("test_function"));
390        assert!(message.contains("0.1.0"));
391        assert!(message.contains("0.2.0"));
392        assert!(message.contains("new_function"));
393    }
394}