use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityConfig {
pub preservation_level: PreservationLevel,
pub comment_preservation: CommentPreservationConfig,
pub processing_instruction_preservation: bool,
pub extension_preservation: ExtensionPreservationConfig,
pub attribute_preservation: AttributePreservationConfig,
pub namespace_preservation: NamespacePreservationConfig,
pub whitespace_preservation: WhitespacePreservationConfig,
}
impl Default for FidelityConfig {
fn default() -> Self {
Self {
preservation_level: PreservationLevel::Standard,
comment_preservation: CommentPreservationConfig::default(),
processing_instruction_preservation: false,
extension_preservation: ExtensionPreservationConfig::default(),
attribute_preservation: AttributePreservationConfig::default(),
namespace_preservation: NamespacePreservationConfig::default(),
whitespace_preservation: WhitespacePreservationConfig::default(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PreservationLevel {
Basic,
Standard,
Perfect,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommentPreservationConfig {
pub enabled: bool,
pub preserve_document_comments: bool,
pub preserve_element_comments: bool,
pub preserve_inline_comments: bool,
pub preserve_comment_positioning: bool,
pub max_comment_length: usize,
}
impl Default for CommentPreservationConfig {
fn default() -> Self {
Self {
enabled: false,
preserve_document_comments: true,
preserve_element_comments: true,
preserve_inline_comments: false,
preserve_comment_positioning: true,
max_comment_length: 0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExtensionPreservationConfig {
pub enabled: bool,
pub known_extensions: Vec<String>,
pub unknown_extension_handling: UnknownExtensionHandling,
pub preserve_extension_attributes: bool,
pub extension_validation: ExtensionValidationConfig,
}
impl Default for ExtensionPreservationConfig {
fn default() -> Self {
Self {
enabled: true,
known_extensions: vec![
"http://spotify.com/ddex".to_string(),
"http://apple.com/ddex".to_string(),
"http://youtube.com/ddex".to_string(),
"http://amazon.com/ddex".to_string(),
],
unknown_extension_handling: UnknownExtensionHandling::Preserve,
preserve_extension_attributes: true,
extension_validation: ExtensionValidationConfig::default(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnknownExtensionHandling {
Preserve,
Drop,
ValidateAndPreserve,
Generalize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExtensionValidationConfig {
pub validate_uris: bool,
pub validate_schema: bool,
pub max_nesting_depth: usize,
pub max_extension_count: usize,
}
impl Default for ExtensionValidationConfig {
fn default() -> Self {
Self {
validate_uris: true,
validate_schema: false,
max_nesting_depth: 10,
max_extension_count: 1000,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributePreservationConfig {
pub preserve_ordering: bool,
pub preserve_unknown_attributes: bool,
pub preserve_empty_attributes: bool,
pub normalization: AttributeNormalizationConfig,
pub validation: AttributeValidationConfig,
}
impl Default for AttributePreservationConfig {
fn default() -> Self {
Self {
preserve_ordering: false,
preserve_unknown_attributes: true,
preserve_empty_attributes: false,
normalization: AttributeNormalizationConfig::default(),
validation: AttributeValidationConfig::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeNormalizationConfig {
pub normalize_booleans: bool,
pub normalize_numbers: bool,
pub normalize_datetime: bool,
pub normalize_whitespace: bool,
}
impl Default for AttributeNormalizationConfig {
fn default() -> Self {
Self {
normalize_booleans: true,
normalize_numbers: true,
normalize_datetime: true,
normalize_whitespace: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeValidationConfig {
pub validate_formats: bool,
pub validate_constraints: bool,
pub custom_rules: HashMap<String, AttributeValidationRule>,
}
impl Default for AttributeValidationConfig {
fn default() -> Self {
Self {
validate_formats: true,
validate_constraints: true,
custom_rules: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeValidationRule {
pub pattern: Option<String>,
pub min_value: Option<f64>,
pub max_value: Option<f64>,
pub allowed_values: Option<Vec<String>>,
pub validation_message: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NamespacePreservationConfig {
pub preserve_prefixes: bool,
pub preserve_unused_declarations: bool,
pub minimization_strategy: NamespaceMinimizationStrategy,
pub default_namespace_handling: DefaultNamespaceHandling,
}
impl Default for NamespacePreservationConfig {
fn default() -> Self {
Self {
preserve_prefixes: false,
preserve_unused_declarations: false,
minimization_strategy: NamespaceMinimizationStrategy::Aggressive,
default_namespace_handling: DefaultNamespaceHandling::Preserve,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum NamespaceMinimizationStrategy {
None,
Conservative,
Aggressive,
Custom(NamespaceMinimizationRules),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct NamespaceMinimizationRules {
pub always_preserve: Vec<String>,
pub can_remove: Vec<String>,
pub preferred_prefixes: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DefaultNamespaceHandling {
Preserve,
Remove,
ConvertToPrefix,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WhitespacePreservationConfig {
pub preserve_significant: bool,
pub preserve_formatting: bool,
pub normalize_line_endings: bool,
pub line_ending_style: LineEndingStyle,
pub indentation_style: IndentationStyle,
}
impl Default for WhitespacePreservationConfig {
fn default() -> Self {
Self {
preserve_significant: true,
preserve_formatting: false,
normalize_line_endings: true,
line_ending_style: LineEndingStyle::Unix,
indentation_style: IndentationStyle::Spaces(2),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum LineEndingStyle {
Unix,
Windows,
Mac,
Preserve,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum IndentationStyle {
Spaces(usize),
Tabs,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityStatistics {
pub elements_preserved: HashMap<String, usize>,
pub attributes_preserved: HashMap<String, usize>,
pub comments_preserved: usize,
pub processing_instructions_preserved: usize,
pub extensions_preserved: HashMap<String, usize>,
pub namespaces_processed: usize,
pub processing_time: Duration,
pub memory_usage: usize,
}
impl Default for FidelityStatistics {
fn default() -> Self {
Self {
elements_preserved: HashMap::new(),
attributes_preserved: HashMap::new(),
comments_preserved: 0,
processing_instructions_preserved: 0,
extensions_preserved: HashMap::new(),
namespaces_processed: 0,
processing_time: Duration::ZERO,
memory_usage: 0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityResult {
pub success: bool,
pub achieved_level: PreservationLevel,
pub statistics: FidelityStatistics,
pub issues: Vec<FidelityIssue>,
pub recommendations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FidelityIssue {
pub severity: FidelitySeverity,
pub category: String,
pub message: String,
pub path: Option<String>,
pub suggestion: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FidelitySeverity {
Critical,
Major,
Minor,
Info,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fidelity_config_default() {
let config = FidelityConfig::default();
assert_eq!(config.preservation_level, PreservationLevel::Standard);
assert!(!config.comment_preservation.enabled);
assert!(!config.processing_instruction_preservation);
assert!(config.extension_preservation.enabled);
}
#[test]
fn test_preservation_levels() {
let basic = PreservationLevel::Basic;
let standard = PreservationLevel::Standard;
let perfect = PreservationLevel::Perfect;
let custom = PreservationLevel::Custom;
assert_ne!(basic, standard);
assert_ne!(standard, perfect);
assert_ne!(perfect, custom);
}
#[test]
fn test_comment_preservation_config() {
let mut config = CommentPreservationConfig::default();
assert!(!config.enabled);
config.enabled = true;
assert!(config.enabled);
assert!(config.preserve_document_comments);
assert!(config.preserve_element_comments);
assert!(!config.preserve_inline_comments);
}
#[test]
fn test_extension_preservation() {
let config = ExtensionPreservationConfig::default();
assert!(config.enabled);
assert!(!config.known_extensions.is_empty());
assert_eq!(
config.unknown_extension_handling,
UnknownExtensionHandling::Preserve
);
}
#[test]
fn test_namespace_minimization() {
let strategy = NamespaceMinimizationStrategy::Aggressive;
match strategy {
NamespaceMinimizationStrategy::Aggressive => {}
_ => panic!("Expected Aggressive strategy"),
}
}
}