use std::collections::HashMap;
use std::sync::{Mutex, OnceLock};
static DEPRECATION_CONFIG: OnceLock<Mutex<DeprecationConfig>> = OnceLock::new();
#[derive(Debug, Clone)]
pub struct DeprecationConfig {
pub show_warnings: bool,
pub warnings_as_errors: bool,
pub max_warning_count: usize,
pub warning_counts: HashMap<String, usize>,
pub current_version: String,
}
impl Default for DeprecationConfig {
fn default() -> Self {
Self {
show_warnings: true,
warnings_as_errors: false,
max_warning_count: 3,
warning_counts: HashMap::new(),
current_version: "0.1.0".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum DeprecationLevel {
Experimental,
Soft,
Hard,
Removed,
}
#[derive(Debug, Clone)]
pub struct DeprecationInfo {
pub name: String,
pub since: String,
pub remove_in: Option<String>,
pub level: DeprecationLevel,
pub reason: String,
pub alternative: Option<String>,
pub migration_notes: Option<String>,
}
#[allow(dead_code)]
pub fn init_deprecation_system() {
let _ = DEPRECATION_CONFIG.set(Mutex::new(DeprecationConfig::default()));
}
#[allow(dead_code)]
pub fn configure_deprecation(config: DeprecationConfig) {
init_deprecation_system();
if let Ok(mut global_config) = DEPRECATION_CONFIG.get().expect("Operation failed").lock() {
*global_config = config;
}
}
#[allow(dead_code)]
pub fn issue_deprecation_warning(info: &DeprecationInfo) {
init_deprecation_system();
if let Ok(mut config) = DEPRECATION_CONFIG.get().expect("Operation failed").lock() {
if !config.show_warnings {
return;
}
let count = config.warning_counts.entry(info.name.clone()).or_insert(0);
*count += 1;
if *count > config.max_warning_count {
return;
}
let warning_msg = format_deprecation_warning(info);
if config.warnings_as_errors {
panic!("Deprecation error: {warning_msg}");
} else {
eprintln!("Deprecation warning: {warning_msg}");
}
}
}
#[allow(dead_code)]
fn format_deprecation_warning(info: &DeprecationInfo) -> String {
let mut msg = format!(
"Function '{}' is deprecated since v{}",
info.name, info.since
);
if let Some(remove_version) = &info.remove_in {
msg.push_str(&format!(" and will be removed in v{remove_version}"));
}
msg.push_str(&format!(": {}", info.reason));
if let Some(alternative) = &info.alternative {
msg.push_str(&format!(" Use '{alternative}' instead."));
}
if let Some(notes) = &info.migration_notes {
msg.push_str(&format!(" Migration notes: {notes}"));
}
msg
}
#[macro_export]
macro_rules! deprecated_function {
(
name = $name:expr,
since = $since:expr,
reason = $reason:expr
$(, alternative = $alternative:expr)?
$(, remove_in = $remove_in:expr)?
$(, migration_notes = $notes:expr)?
$(, level = $level:expr)?
) => {
{
use $crate::deprecation::{DeprecationInfo, DeprecationLevel, issue_deprecation_warning};
let info = DeprecationInfo {
name: $name.to_string(),
since: $since.to_string(),
remove_in: None $(.or(Some($remove_in.to_string())))?,
level: DeprecationLevel::Soft $(.max($level))?,
reason: $reason.to_string(),
alternative: None $(.or(Some($alternative.to_string())))?,
migration_notes: None $(.or(Some($notes.to_string())))?,
};
issue_deprecation_warning(&info);
}
};
}
#[macro_export]
macro_rules! experimental_feature {
($name:expr, $description:expr) => {{
use $crate::deprecation::{issue_deprecation_warning, DeprecationInfo, DeprecationLevel};
let info = DeprecationInfo {
name: $name.to_string(),
since: "0.1.0".to_string(),
remove_in: None,
level: DeprecationLevel::Experimental,
reason: format!("This is an experimental feature: {}", $description),
alternative: None,
migration_notes: Some("API may change in future versions".to_string()),
};
issue_deprecation_warning(&info);
}};
}
pub struct FeatureRegistry;
impl FeatureRegistry {
pub fn deprecated_features() -> Vec<DeprecationInfo> {
vec![
DeprecationInfo {
name: "gpu_accelerated".to_string(),
since: "0.1.0".to_string(),
remove_in: None,
level: DeprecationLevel::Experimental,
reason: "GPU acceleration is experimental and may change".to_string(),
alternative: None,
migration_notes: Some(
"Enable with 'gpu' feature flag. API subject to change.".to_string(),
),
},
DeprecationInfo {
name: "neural_enhanced".to_string(),
since: "0.1.0".to_string(),
remove_in: None,
level: DeprecationLevel::Experimental,
reason: "Neural enhanced interpolation is experimental".to_string(),
alternative: None,
migration_notes: Some(
"API may change significantly in future versions".to_string(),
),
},
DeprecationInfo {
name: "physics_informed".to_string(),
since: "0.1.0".to_string(),
remove_in: None,
level: DeprecationLevel::Experimental,
reason: "Physics-informed methods are experimental".to_string(),
alternative: None,
migration_notes: Some(
"Consider using standard RBF or spline methods for production".to_string(),
),
},
DeprecationInfo {
name: "experimental_kriging_variants".to_string(),
since: "0.1.0".to_string(),
remove_in: None,
level: DeprecationLevel::Experimental,
reason: "Some advanced Kriging variants show implementation warnings".to_string(),
alternative: Some("enhanced_kriging::make_enhanced_kriging".to_string()),
migration_notes: Some(
"Use stable Kriging implementations for production workloads".to_string(),
),
},
]
}
pub fn features_removed_in(version: &str) -> Vec<DeprecationInfo> {
Self::deprecated_features()
.into_iter()
.filter(|f| f.remove_in.as_ref().map(|v| v == version).unwrap_or(false))
.collect()
}
pub fn is_feature_deprecated(featurename: &str) -> bool {
Self::deprecated_features()
.iter()
.any(|f| f.name == featurename)
}
pub fn get_deprecation_info(featurename: &str) -> Option<DeprecationInfo> {
Self::deprecated_features()
.into_iter()
.find(|f| f.name == featurename)
}
}
pub mod convenience {
use crate::experimental_feature;
pub fn warn_gpu_experimental(featurename: &str) {
experimental_feature!(
featurename,
"GPU acceleration support is experimental and may change significantly"
);
}
pub fn warn_neural_experimental(featurename: &str) {
experimental_feature!(
featurename,
"Neural network enhanced interpolation is experimental"
);
}
pub fn warn_physics_experimental(featurename: &str) {
experimental_feature!(
featurename,
"Physics-informed interpolation methods are experimental"
);
}
pub fn warn_matrix_conditioning(condition_number: f64, context: &str) {
if condition_number > 1e14 {
eprintln!(
"NUMERICAL WARNING: Poor matrix conditioning (condition number: {condition_number:.2e}) in {context}. \
Consider regularization or data preprocessing."
);
}
}
pub fn warn_performance_large_dataset(operation: &str, size: usize, threshold: usize) {
if size > threshold {
eprintln!(
"PERFORMANCE WARNING: {operation} with {size} data points may be slow. \
Consider using fast variants or GPU acceleration if available."
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deprecation_config() {
let config = DeprecationConfig::default();
assert!(config.show_warnings);
assert!(!config.warnings_as_errors);
assert_eq!(config.max_warning_count, 3);
}
#[test]
fn test_feature_registry() {
let deprecated = FeatureRegistry::deprecated_features();
assert!(!deprecated.is_empty());
let gpu_deprecated = FeatureRegistry::is_feature_deprecated("gpu_accelerated");
assert!(gpu_deprecated);
let standard_feature = FeatureRegistry::is_feature_deprecated("spline");
assert!(!standard_feature);
}
#[test]
fn test_deprecation_info() {
let info = DeprecationInfo {
name: "test_function".to_string(),
since: "0.1.0".to_string(),
remove_in: Some("0.2.0".to_string()),
level: DeprecationLevel::Soft,
reason: "Test deprecation".to_string(),
alternative: Some("new_function".to_string()),
migration_notes: Some("Easy migration".to_string()),
};
let message = format_deprecation_warning(&info);
assert!(message.contains("test_function"));
assert!(message.contains("0.1.0"));
assert!(message.contains("0.2.0"));
assert!(message.contains("new_function"));
}
}