use super::version_manager::VersionManager;
use crate::ErrorManager::ErrorManager;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompatibilityMode {
Strict, Tolerant, BestEffort, }
pub struct ForwardCompatibilityManager {
mode: CompatibilityMode,
}
impl ForwardCompatibilityManager {
pub fn new(mode: CompatibilityMode) -> Self {
ForwardCompatibilityManager { mode }
}
pub fn handle_unknown_element(
&self,
element_type: &str,
element_name: &str,
_element_data: Option<&str>,
_context: Option<&HashMap<String, String>>,
) -> Result<bool, String> {
let error_manager = ErrorManager::get_shared_instance();
error_manager.log_info(&format!(
"Processing unknown element: {}::{}",
element_type, element_name
));
match self.mode {
CompatibilityMode::Strict => self.handle_strict(element_type, element_name),
CompatibilityMode::Tolerant => self.handle_tolerant(element_type, element_name),
CompatibilityMode::BestEffort => self.handle_best_effort(element_type, element_name),
}
}
pub fn validate_compatibility(
&self,
script: &crate::Compiler::AST::DixScript,
) -> CompatibilityValidationResult {
let script_version = super::version_manager::extract_version_from_ast(script);
let manager = VersionManager::instance().read().unwrap();
let compiler_version = manager.get_current_version().to_string();
let mut result = CompatibilityValidationResult {
is_compatible: false,
is_newer_version: false,
script_version: script_version.clone(),
compiler_version: compiler_version.clone(),
errors: Vec::new(),
warnings: Vec::new(),
handled_elements: Vec::new(),
};
let error_manager = ErrorManager::get_shared_instance();
error_manager.log_info(&format!(
"Validating compatibility: Script v{} with Compiler v{}",
result.script_version, result.compiler_version
));
if !manager.is_compatible_with(&script_version) {
error_manager.log_warning(&format!(
"Script version {} is newer than compiler",
script_version
));
result.is_newer_version = true;
if script_version != "1.0.0" {
result.errors.push(format!(
"Script version {} not supported by v1.0.0 compiler",
script_version
));
}
} else {
result.is_compatible = true;
}
result.is_compatible = result.errors.is_empty();
result
}
fn handle_strict(&self, element_type: &str, element_name: &str) -> Result<bool, String> {
let manager = VersionManager::instance().read().unwrap();
let message = format!(
"Unknown {} '{}' not supported in v{}",
element_type,
element_name,
manager.get_current_version()
);
let error_manager = ErrorManager::get_shared_instance();
error_manager.log_error(&message);
Err(message)
}
fn handle_tolerant(&self, element_type: &str, element_name: &str) -> Result<bool, String> {
let message = format!("Ignoring unknown {}: {}", element_type, element_name);
let error_manager = ErrorManager::get_shared_instance();
error_manager.log_warning(&message);
Ok(true)
}
fn handle_best_effort(&self, element_type: &str, element_name: &str) -> Result<bool, String> {
let error_manager = ErrorManager::get_shared_instance();
error_manager.log_warning(&format!(
"Unknown {} '{}' - using tolerant handling",
element_type, element_name
));
self.handle_tolerant(element_type, element_name)
}
pub fn get_compatibility_info(&self) -> HashMap<String, String> {
let manager = VersionManager::instance().read().unwrap();
let mut info = HashMap::new();
info.insert("Mode".to_string(), format!("{:?}", self.mode));
info.insert(
"CompilerVersion".to_string(),
manager.get_current_version().to_string(),
);
info.insert(
"Note".to_string(),
"v1.0.0 minimal forward compatibility".to_string(),
);
info
}
}
#[derive(Debug, Clone)]
pub struct CompatibilityValidationResult {
pub is_compatible: bool,
pub is_newer_version: bool,
pub script_version: String,
pub compiler_version: String,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub handled_elements: Vec<String>,
}
impl CompatibilityValidationResult {
pub fn has_issues(&self) -> bool {
!self.errors.is_empty() || !self.warnings.is_empty()
}
pub fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
pub fn has_warnings(&self) -> bool {
!self.warnings.is_empty()
}
}
impl std::fmt::Display for CompatibilityValidationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"Compatibility: {}",
if self.is_compatible {
"COMPATIBLE"
} else {
"INCOMPATIBLE"
}
)?;
writeln!(
f,
"Script: v{}, Compiler: v{}",
self.script_version, self.compiler_version
)?;
if self.is_newer_version {
writeln!(f, "(Script is newer)")?;
}
if self.has_errors() {
writeln!(f, "Errors: {}", self.errors.join("; "))?;
}
if self.has_warnings() {
writeln!(f, "Warnings: {}", self.warnings.join("; "))?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compatibility_modes() {
let strict = ForwardCompatibilityManager::new(CompatibilityMode::Strict);
let tolerant = ForwardCompatibilityManager::new(CompatibilityMode::Tolerant);
assert!(strict
.handle_unknown_element("section", "FUTURE", None, None)
.is_err());
assert!(tolerant
.handle_unknown_element("section", "FUTURE", None, None)
.is_ok());
}
}