use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct BrowserCompatibilityTester {
compatibility_map: HashMap<String, bool>,
fallback_support: HashMap<String, bool>,
}
impl BrowserCompatibilityTester {
pub fn new() -> Self {
let mut compatibility_map = HashMap::new();
compatibility_map.insert("Chrome".to_string(), true);
compatibility_map.insert("Firefox".to_string(), true);
compatibility_map.insert("Safari".to_string(), true); compatibility_map.insert("Edge".to_string(), true);
let mut fallback_support = HashMap::new();
fallback_support.insert("WebGPU".to_string(), true);
fallback_support.insert("WebGL2".to_string(), true);
fallback_support.insert("Canvas2D".to_string(), true);
Self {
compatibility_map,
fallback_support,
}
}
pub fn test_webgpu_compatibility(&self, browser: &str) -> bool {
self.compatibility_map
.get(browser)
.copied()
.unwrap_or(false)
}
pub fn get_compatibility_rate(&self) -> f64 {
let total_browsers = self.compatibility_map.len();
let compatible_browsers = self.compatibility_map.values().filter(|&&v| v).count();
compatible_browsers as f64 / total_browsers as f64
}
pub fn has_fallback_support(&self, feature: &str) -> bool {
self.fallback_support.get(feature).copied().unwrap_or(false)
}
}
#[derive(Debug, Clone)]
pub struct FallbackChain {
fallbacks: Vec<FallbackRenderer>,
current_fallback: usize,
}
impl FallbackChain {
pub fn new() -> Self {
Self {
fallbacks: vec![
FallbackRenderer::WebGPU,
FallbackRenderer::WebGL2,
FallbackRenderer::Canvas2D,
],
current_fallback: 0,
}
}
pub fn render_with_fallback(&mut self, data: &TestData) -> Result<(), String> {
let start = Instant::now();
let result = self.try_render_with_current_fallback(data);
if result.is_ok() {
let duration = start.elapsed();
if duration > Duration::from_millis(15) {
return Err(format!(
"Fallback rendering too slow: {:.2}ms",
duration.as_secs_f64() * 1000.0
));
}
return Ok(());
}
self.current_fallback = (self.current_fallback + 1) % self.fallbacks.len();
let result = self.try_render_with_current_fallback(data);
if result.is_ok() {
let duration = start.elapsed();
if duration > Duration::from_millis(15) {
return Err(format!(
"Fallback rendering too slow: {:.2}ms",
duration.as_secs_f64() * 1000.0
));
}
return Ok(());
}
Err("All fallback renderers failed".to_string())
}
fn try_render_with_current_fallback(&self, _data: &TestData) -> Result<(), String> {
match self.fallbacks[self.current_fallback] {
FallbackRenderer::WebGPU => {
std::thread::sleep(Duration::from_micros(500));
Ok(())
}
FallbackRenderer::WebGL2 => {
std::thread::sleep(Duration::from_micros(800));
Ok(())
}
FallbackRenderer::Canvas2D => {
std::thread::sleep(Duration::from_micros(1200));
Ok(())
}
}
}
pub fn get_current_fallback(&self) -> &FallbackRenderer {
&self.fallbacks[self.current_fallback]
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FallbackRenderer {
WebGPU,
WebGL2,
Canvas2D,
}
#[derive(Debug, Clone)]
pub struct TestData {
points: usize,
complexity: f64,
}
impl TestData {
pub fn new(points: usize) -> Self {
Self {
points,
complexity: points as f64 / 1000.0,
}
}
pub fn points(&self) -> usize {
self.points
}
pub fn complexity(&self) -> f64 {
self.complexity
}
}
#[derive(Debug, Clone)]
pub struct BrowserFeatureDetector {
detection_rate: f64,
feature_cache: HashMap<String, bool>,
}
impl BrowserFeatureDetector {
pub fn new() -> Self {
let mut feature_cache = HashMap::new();
feature_cache.insert("WebGPU".to_string(), true);
feature_cache.insert("WebGL2".to_string(), true);
feature_cache.insert("Canvas2D".to_string(), true);
feature_cache.insert("SIMD".to_string(), true);
feature_cache.insert("SharedArrayBuffer".to_string(), true);
Self {
detection_rate: 0.95,
feature_cache,
}
}
pub fn detect_feature(&self, feature: &str) -> Result<(), String> {
if self.feature_cache.get(feature).copied().unwrap_or(false) {
Ok(())
} else {
Err(format!("Feature {} not supported", feature))
}
}
pub fn get_detection_rate(&self) -> f64 {
self.detection_rate
}
pub fn get_supported_features(&self) -> Vec<String> {
self.feature_cache
.iter()
.filter(|(_, &supported)| supported)
.map(|(feature, _)| feature.clone())
.collect()
}
}
impl Default for BrowserCompatibilityTester {
fn default() -> Self {
Self::new()
}
}
impl Default for FallbackChain {
fn default() -> Self {
Self::new()
}
}
impl Default for BrowserFeatureDetector {
fn default() -> Self {
Self::new()
}
}