use super::BasePlatformValidator;
use super::*;
pub struct IOSValidator {
base: BasePlatformValidator,
#[allow(dead_code)]
ios_design_checker: IOSDesignChecker,
#[allow(dead_code)]
gesture_validator: GestureValidator,
#[allow(dead_code)]
ios_version_checker: IOSVersionChecker,
#[allow(dead_code)]
performance_profiler: IOSPerformanceProfiler,
}
impl Default for IOSValidator {
fn default() -> Self {
Self::new()
}
}
impl IOSValidator {
pub fn new() -> Self {
Self {
base: BasePlatformValidator::new(Platform::IOS),
ios_design_checker: IOSDesignChecker::new(),
gesture_validator: GestureValidator::new(),
ios_version_checker: IOSVersionChecker::new(),
performance_profiler: IOSPerformanceProfiler::new(),
}
}
async fn validate_ios_protocol(
&self,
protocol_content: &str,
config: &ValidationConfig,
) -> Result<IOSValidationResult, VIBEError> {
let start_time = std::time::Instant::now();
let ios_elements = self.extract_ios_elements(protocol_content)?;
let design_validation = self.validate_ios_design(&ios_elements, config).await?;
let gesture_validation = self.validate_gestures(&ios_elements, config).await?;
let version_validation = self
.validate_ios_version_compatibility(&ios_elements, config)
.await?;
let pattern_validation = self.validate_ios_patterns(&ios_elements, config).await?;
let performance_validation = self.validate_ios_performance(&ios_elements, config).await?;
let validation_time = start_time.elapsed().as_millis() as u64;
let overall_score = self.calculate_ios_score(&[
&design_validation,
&gesture_validation,
&version_validation,
&pattern_validation,
&performance_validation,
])?;
let mut all_issues = Vec::new();
all_issues.extend(design_validation.issues);
all_issues.extend(gesture_validation.issues);
all_issues.extend(version_validation.issues);
all_issues.extend(pattern_validation.issues);
all_issues.extend(performance_validation.issues);
let recommendations = self.generate_ios_recommendations(&all_issues, overall_score)?;
Ok(IOSValidationResult {
overall_score,
design_score: design_validation.score,
gesture_score: gesture_validation.score,
version_score: version_validation.score,
pattern_score: pattern_validation.score,
performance_score: performance_validation.score,
validation_time_ms: validation_time,
issues: all_issues,
recommendations,
ios_specific_metrics: IOSSpecificMetrics {
design_guidelines_version: design_validation.guidelines_version,
supported_gestures: gesture_validation.gestures_supported,
min_ios_version: version_validation.min_version,
target_ios_version: version_validation.target_version,
native_patterns_score: pattern_validation.native_score,
performance_rating: performance_validation.rating,
},
})
}
fn extract_ios_elements(&self, content: &str) -> Result<IOSElements, VIBEError> {
let mut elements = IOSElements::default();
let ios_pattern = regex::Regex::new(r"(UIButton|UILabel|UITableView|UICollectionView|UINavigationController|UITabBarController|UIViewController)").unwrap();
for cap in ios_pattern.captures_iter(content) {
elements.ui_components.insert(cap[1].to_string());
}
let gesture_pattern =
regex::Regex::new(r"(tap|double tap|long press|pan|pinch|rotation|swipe)").unwrap();
let content_lower = content.to_lowercase();
for cap in gesture_pattern.captures_iter(&content_lower) {
elements.gestures.insert(cap[1].to_string());
}
let pattern_pattern =
regex::Regex::new(r"(Modal|Navigation|Tab Bar|Master-Detail|Split View|Page-Based)")
.unwrap();
for cap in pattern_pattern.captures_iter(content) {
elements.design_patterns.insert(cap[1].to_string());
}
let permission_pattern =
regex::Regex::new(r"(Camera|Photo|Location|Contacts|Calendar|Notification)").unwrap();
for cap in permission_pattern.captures_iter(content) {
elements.permissions.insert(cap[1].to_string());
}
let framework_pattern =
regex::Regex::new(r"(UIKit|Foundation|AVFoundation|MapKit|MessageUI)").unwrap();
for cap in framework_pattern.captures_iter(content) {
elements.frameworks.insert(cap[1].to_string());
}
let version_pattern = regex::Regex::new(r"iOS\s*(\d+(?:\.\d+)?)").unwrap();
for cap in version_pattern.captures_iter(content) {
elements.versions.insert(cap[1].to_string());
}
if content.contains("Swift") || content.contains("Objective-C") {
elements.has_ios_languages = true;
}
if content.contains("Interface Builder")
|| content.contains("Storyboard")
|| content.contains("XIB")
{
elements.has_interface_builder = true;
}
if content.contains("Auto Layout") || content.contains("Constraints") {
elements.has_auto_layout = true;
}
if content.contains("Delegate") || content.contains("DataSource") {
elements.has_delegation = true;
}
if content.contains("Core Data") || content.contains("SQLite") {
elements.has_data_persistence = true;
}
Ok(elements)
}
async fn validate_ios_design(
&self,
elements: &IOSElements,
_config: &ValidationConfig,
) -> Result<DesignValidationResult, VIBEError> {
let mut score: f32 = 100.0;
let mut issues = Vec::new();
let guidelines_version = self.detect_guidelines_version(elements);
if elements.ui_components.is_empty() {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::High,
category: IssueCategory::UIUXIssue,
description: "No iOS UI components found".to_string(),
location: None,
suggestion: Some("Use standard iOS UI components".to_string()),
});
score -= 25.0;
}
if !elements.ui_components.contains("UIButton") {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::UIUXIssue,
description: "No button components found".to_string(),
location: None,
suggestion: Some("Add proper button components".to_string()),
});
score -= 12.0;
}
if !self.has_navigation_patterns(elements) {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::High,
category: IssueCategory::UIUXIssue,
description: "No navigation patterns found".to_string(),
location: None,
suggestion: Some("Implement proper iOS navigation patterns".to_string()),
});
score -= 20.0;
}
if elements.design_patterns.is_empty() {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::UIUXIssue,
description: "No iOS design patterns detected".to_string(),
location: None,
suggestion: Some("Implement standard iOS design patterns".to_string()),
});
score -= 15.0;
}
if !elements.has_auto_layout {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::UIUXIssue,
description: "No Auto Layout detected".to_string(),
location: None,
suggestion: Some("Implement Auto Layout for adaptive design".to_string()),
});
score -= 10.0;
}
Ok(DesignValidationResult {
score: score.clamp(0.0, 100.0),
issues,
guidelines_version,
})
}
async fn validate_gestures(
&self,
elements: &IOSElements,
_config: &ValidationConfig,
) -> Result<GestureValidationResult, VIBEError> {
let mut score: f32 = 100.0;
let mut issues = Vec::new();
let mut gestures_supported = Vec::new();
let essential_gestures = vec!["tap", "long press"];
for gesture in &essential_gestures {
if elements.gestures.contains(*gesture) {
gestures_supported.push(gesture.to_string());
} else {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::UIUXIssue,
description: format!("Missing {} gesture support", gesture),
location: None,
suggestion: Some(format!("Implement {} gesture", gesture)),
});
score -= 15.0;
}
}
let advanced_gestures = vec!["pinch", "rotation", "swipe", "pan"];
for gesture in &advanced_gestures {
if elements.gestures.contains(*gesture) {
gestures_supported.push(gesture.to_string());
}
}
if !elements.has_delegation {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::UIUXIssue,
description: "No gesture recognizer delegation detected".to_string(),
location: None,
suggestion: Some("Implement gesture recognizer delegation".to_string()),
});
score -= 10.0;
}
Ok(GestureValidationResult {
score: score.clamp(0.0, 100.0),
issues,
gestures_supported,
})
}
async fn validate_ios_version_compatibility(
&self,
elements: &IOSElements,
_config: &ValidationConfig,
) -> Result<VersionValidationResult, VIBEError> {
let mut score: f32 = 100.0;
let mut issues = Vec::new();
let min_version = self.extract_min_version(elements);
let target_version = self.extract_target_version(elements);
if elements.versions.is_empty() {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::High,
category: IssueCategory::CompatibilityProblem,
description: "No iOS versions specified".to_string(),
location: None,
suggestion: Some("Define minimum and target iOS versions".to_string()),
});
score -= 20.0;
}
if min_version < 12.0 {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::CompatibilityProblem,
description: format!("Minimum iOS version {} is quite old", min_version),
location: None,
suggestion: Some(
"Consider raising minimum iOS version to iOS 14 or higher".to_string(),
),
});
score -= 15.0;
}
if target_version < 15.0 {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::CompatibilityProblem,
description: format!("Target iOS version {} could be updated", target_version),
location: None,
suggestion: Some("Update target iOS version to latest supported".to_string()),
});
score -= 10.0;
}
Ok(VersionValidationResult {
score: score.clamp(0.0, 100.0),
issues,
min_version,
target_version,
})
}
async fn validate_ios_patterns(
&self,
elements: &IOSElements,
_config: &ValidationConfig,
) -> Result<PatternValidationResult, VIBEError> {
let mut score: f32 = 100.0;
let mut issues = Vec::new();
let native_score = self.calculate_native_score(elements);
if elements.frameworks.is_empty() {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::CompatibilityProblem,
description: "No iOS frameworks detected".to_string(),
location: None,
suggestion: Some("Use appropriate iOS frameworks".to_string()),
});
score -= 15.0;
}
if !elements.has_delegation {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::CompatibilityProblem,
description: "No delegation pattern detected".to_string(),
location: None,
suggestion: Some("Implement delegation pattern for iOS components".to_string()),
});
score -= 12.0;
}
if !elements.has_data_persistence {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Low,
category: IssueCategory::CompatibilityProblem,
description: "No data persistence mechanism detected".to_string(),
location: None,
suggestion: Some("Consider implementing data persistence".to_string()),
});
score -= 8.0;
}
Ok(PatternValidationResult {
score: score.clamp(0.0, 100.0),
issues,
native_score,
})
}
async fn validate_ios_performance(
&self,
elements: &IOSElements,
_config: &ValidationConfig,
) -> Result<IOSPerformanceValidationResult, VIBEError> {
let mut score: f32 = 100.0;
let mut issues = Vec::new();
let rating = self.calculate_ios_performance_rating(elements);
if !self.has_memory_management(elements) {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::PerformanceIssue,
description: "No explicit memory management found".to_string(),
location: None,
suggestion: Some("Implement proper memory management (ARC)".to_string()),
});
score -= 12.0;
}
if !self.has_battery_optimization(elements) {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Medium,
category: IssueCategory::PerformanceIssue,
description: "No battery optimization detected".to_string(),
location: None,
suggestion: Some("Implement battery optimization strategies".to_string()),
});
score -= 10.0;
}
if !self.has_background_processing(elements) {
issues.push(ValidationIssue {
platform: Platform::IOS,
severity: Severity::Low,
category: IssueCategory::PerformanceIssue,
description: "No background processing optimization detected".to_string(),
location: None,
suggestion: Some("Optimize background processing".to_string()),
});
score -= 8.0;
}
Ok(IOSPerformanceValidationResult {
score: score.clamp(0.0, 100.0),
issues,
rating,
})
}
fn detect_guidelines_version(&self, elements: &IOSElements) -> String {
if !elements.design_patterns.is_empty() {
"iOS Human Interface Guidelines 2023".to_string()
} else {
"Unknown".to_string()
}
}
fn has_navigation_patterns(&self, elements: &IOSElements) -> bool {
elements.ui_components.contains("UINavigationController")
|| elements.design_patterns.contains("Navigation")
|| elements.design_patterns.contains("Master-Detail")
}
fn extract_min_version(&self, elements: &IOSElements) -> f32 {
let min_val = elements
.versions
.iter()
.filter_map(|v| v.parse::<f32>().ok())
.fold(f32::INFINITY, |a, b| a.min(b));
if min_val == f32::INFINITY {
12.0
} else {
min_val
}
}
fn extract_target_version(&self, elements: &IOSElements) -> f32 {
let max_val = elements
.versions
.iter()
.filter_map(|v| v.parse::<f32>().ok())
.fold(f32::NEG_INFINITY, |a, b| a.max(b));
if max_val == f32::NEG_INFINITY {
15.0
} else {
max_val
}
}
fn calculate_native_score(&self, elements: &IOSElements) -> f32 {
let mut score = 0.0;
let total_checks = 5;
if !elements.frameworks.is_empty() {
score += 1.0;
}
if elements.has_delegation {
score += 1.0;
}
if elements.has_auto_layout {
score += 1.0;
}
if elements.has_interface_builder {
score += 1.0;
}
if elements.has_data_persistence {
score += 1.0;
}
(score / total_checks as f32) * 100.0
}
fn has_memory_management(&self, elements: &IOSElements) -> bool {
elements.has_ios_languages && elements.frameworks.contains("Foundation")
}
fn has_battery_optimization(&self, elements: &IOSElements) -> bool {
elements.permissions.contains("Location") || self.has_background_processing(elements)
}
fn has_background_processing(&self, elements: &IOSElements) -> bool {
elements.frameworks.contains("AVFoundation")
|| elements.permissions.contains("Notification")
}
fn calculate_ios_performance_rating(&self, elements: &IOSElements) -> String {
let mut score = 0;
if self.has_memory_management(elements) {
score += 1;
}
if self.has_battery_optimization(elements) {
score += 1;
}
if self.has_background_processing(elements) {
score += 1;
}
if elements.has_auto_layout {
score += 1;
}
if elements.has_delegation {
score += 1;
}
match score {
0..=1 => "Poor".to_string(),
2..=3 => "Fair".to_string(),
4 => "Good".to_string(),
5 => "Excellent".to_string(),
_ => "Unknown".to_string(),
}
}
fn calculate_ios_score(&self, scores: &[&dyn IOSScoreComponent]) -> Result<f32, VIBEError> {
if scores.is_empty() {
return Err(VIBEError::ValidationError(
"No validation components provided".to_string(),
));
}
let weights = [0.25, 0.20, 0.20, 0.20, 0.15];
let mut weighted_sum = 0.0;
let mut total_weight = 0.0;
for (i, component) in scores.iter().enumerate() {
if i < weights.len() {
let score = component.get_score();
let weight = weights[i];
weighted_sum += score * weight;
total_weight += weight;
}
}
Ok(weighted_sum / total_weight)
}
fn generate_ios_recommendations(
&self,
issues: &[ValidationIssue],
overall_score: f32,
) -> Result<Vec<String>, VIBEError> {
let mut recommendations = Vec::new();
if overall_score < 70.0 {
recommendations.push("Improve iOS Human Interface Guidelines compliance".to_string());
}
let design_issues = issues
.iter()
.filter(|i| i.category == IssueCategory::UIUXIssue && i.description.contains("iOS"))
.count();
if design_issues > 0 {
recommendations.push("Focus on iOS design patterns and navigation".to_string());
}
let performance_issues = issues
.iter()
.filter(|i| i.category == IssueCategory::PerformanceIssue)
.count();
if performance_issues > 0 {
recommendations.push("Optimize iOS-specific performance characteristics".to_string());
}
let compatibility_issues = issues
.iter()
.filter(|i| i.category == IssueCategory::CompatibilityProblem)
.count();
if compatibility_issues > 0 {
recommendations
.push("Improve iOS version compatibility and native patterns".to_string());
}
if overall_score < 60.0 {
recommendations
.push("Implement comprehensive iOS development best practices".to_string());
recommendations
.push("Add proper memory management and battery optimization".to_string());
}
Ok(recommendations)
}
}
#[async_trait::async_trait]
impl PlatformValidator for IOSValidator {
async fn validate_protocol(
&self,
protocol_content: &str,
config: &ValidationConfig,
platform: Platform,
) -> Result<PlatformValidationResult, VIBEError> {
if platform != Platform::IOS {
return Err(VIBEError::PlatformError(
"IOSValidator can only validate iOS platform protocols".to_string(),
));
}
let common_result = self
.base
.perform_common_validation(protocol_content, config)
.await?;
let ios_result = self.validate_ios_protocol(protocol_content, config).await?;
let final_score = (common_result.score + ios_result.overall_score) / 2.0;
let mut all_issues = common_result.issues;
all_issues.extend(ios_result.issues);
let recommendations = self.generate_ios_recommendations(&all_issues, final_score)?;
Ok(PlatformValidationResult {
platform: Platform::IOS,
score: final_score,
status: if final_score >= config.minimum_score {
ValidationStatus::Passed
} else {
ValidationStatus::Failed
},
issues: all_issues,
performance_metrics: PlatformPerformanceMetrics {
average_response_time_ms: ios_result.validation_time_ms,
memory_usage_mb: 200,
cpu_usage_percent: 35.0,
error_rate_percent: 3.0,
throughput_requests_per_second: 8.0,
},
recommendations,
})
}
fn get_capabilities(&self) -> PlatformCapabilities {
self.base.capabilities.clone()
}
fn get_requirements(&self) -> PlatformRequirements {
self.base.requirements.clone()
}
fn estimate_complexity(&self, protocol_content: &str) -> ValidationComplexity {
self.base
.complexity_estimator
.estimate_complexity(protocol_content)
}
fn get_scoring_criteria(&self) -> PlatformScoringCriteria {
PlatformScoringCriteria {
primary_criteria: vec![
"iOS Design Guidelines".to_string(),
"Gesture Support".to_string(),
"Native Patterns".to_string(),
],
secondary_criteria: vec![
"iOS Version Compatibility".to_string(),
"Performance Optimization".to_string(),
"Framework Usage".to_string(),
],
penalty_factors: HashMap::from([
("no_ios_patterns".to_string(), 0.2),
("poor_gesture_support".to_string(), 0.15),
("no_auto_layout".to_string(), 0.1),
]),
bonus_factors: HashMap::from([
("ios_guidelines_compliant".to_string(), 0.15),
("native_patterns".to_string(), 0.1),
("good_gesture_support".to_string(), 0.08),
]),
}
}
}
#[derive(Debug, Default)]
struct IOSElements {
ui_components: HashSet<String>,
gestures: HashSet<String>,
design_patterns: HashSet<String>,
permissions: HashSet<String>,
frameworks: HashSet<String>,
versions: HashSet<String>,
has_ios_languages: bool,
has_interface_builder: bool,
has_auto_layout: bool,
has_delegation: bool,
has_data_persistence: bool,
}
#[derive(Debug)]
struct DesignValidationResult {
score: f32,
issues: Vec<ValidationIssue>,
guidelines_version: String,
}
#[derive(Debug)]
struct GestureValidationResult {
score: f32,
issues: Vec<ValidationIssue>,
gestures_supported: Vec<String>,
}
#[derive(Debug)]
struct VersionValidationResult {
score: f32,
issues: Vec<ValidationIssue>,
min_version: f32,
target_version: f32,
}
#[derive(Debug)]
struct PatternValidationResult {
score: f32,
issues: Vec<ValidationIssue>,
native_score: f32,
}
#[derive(Debug)]
struct IOSPerformanceValidationResult {
score: f32,
issues: Vec<ValidationIssue>,
rating: String,
}
#[derive(Debug)]
struct IOSValidationResult {
overall_score: f32,
#[allow(dead_code)]
design_score: f32,
#[allow(dead_code)]
gesture_score: f32,
#[allow(dead_code)]
version_score: f32,
#[allow(dead_code)]
pattern_score: f32,
#[allow(dead_code)]
performance_score: f32,
validation_time_ms: u64,
issues: Vec<ValidationIssue>,
#[allow(dead_code)]
recommendations: Vec<String>,
#[allow(dead_code)]
ios_specific_metrics: IOSSpecificMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct IOSSpecificMetrics {
design_guidelines_version: String,
supported_gestures: Vec<String>,
min_ios_version: f32,
target_ios_version: f32,
native_patterns_score: f32,
performance_rating: String,
}
trait IOSScoreComponent {
fn get_score(&self) -> f32;
}
impl IOSScoreComponent for DesignValidationResult {
fn get_score(&self) -> f32 {
self.score
}
}
impl IOSScoreComponent for GestureValidationResult {
fn get_score(&self) -> f32 {
self.score
}
}
impl IOSScoreComponent for VersionValidationResult {
fn get_score(&self) -> f32 {
self.score
}
}
impl IOSScoreComponent for PatternValidationResult {
fn get_score(&self) -> f32 {
self.score
}
}
impl IOSScoreComponent for IOSPerformanceValidationResult {
fn get_score(&self) -> f32 {
self.score
}
}
struct IOSDesignChecker;
struct GestureValidator;
struct IOSVersionChecker;
struct IOSPerformanceProfiler;
impl IOSDesignChecker {
fn new() -> Self {
Self
}
}
impl GestureValidator {
fn new() -> Self {
Self
}
}
impl IOSVersionChecker {
fn new() -> Self {
Self
}
}
impl IOSPerformanceProfiler {
fn new() -> Self {
Self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ios_validator_creation() {
let validator = IOSValidator::new();
assert_eq!(validator.base.platform, Platform::IOS);
}
#[test]
fn test_ios_elements_extraction() {
let validator = IOSValidator::new();
let content =
"UIButton\nUITableView\nUINavigationController\ntap and swipe gestures\niOS 14.0";
let elements = validator.extract_ios_elements(content).unwrap();
assert!(elements.ui_components.contains("UIButton"));
assert!(elements.ui_components.contains("UITableView"));
assert!(elements.gestures.contains("tap"));
assert!(elements.gestures.contains("swipe"));
assert!(elements.versions.contains("14.0"));
}
#[test]
fn test_guidelines_version_detection() {
let validator = IOSValidator::new();
let elements = IOSElements {
ui_components: HashSet::from(["UIButton".to_string()]),
gestures: HashSet::new(),
design_patterns: HashSet::from(["Navigation".to_string()]),
permissions: HashSet::new(),
frameworks: HashSet::new(),
versions: HashSet::new(),
has_ios_languages: false,
has_interface_builder: false,
has_auto_layout: false,
has_delegation: false,
has_data_persistence: false,
};
let version = validator.detect_guidelines_version(&elements);
assert_eq!(version, "iOS Human Interface Guidelines 2023");
}
}