veda-rs 1.0.0

High-performance parallel runtime for Rust with work-stealing and adaptive scheduling
Documentation
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::sync::atomic::{AtomicUsize, Ordering};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PanicStrategy {
    Abort,
    Isolate,
    LogAndContinue,
}

impl Default for PanicStrategy {
    fn default() -> Self {
        PanicStrategy::LogAndContinue
    }
}

pub struct PanicHandler {
    strategy: PanicStrategy,
    panic_count: AtomicUsize,
}

impl PanicHandler {
    pub fn new(strategy: PanicStrategy) -> Self {
        Self {
            strategy,
            panic_count: AtomicUsize::new(0),
        }
    }
    
    pub fn execute<F, R>(&self, f: F) -> Result<R, PanicInfo>
    where
        F: FnOnce() -> R + std::panic::UnwindSafe,
    {
        match catch_unwind(AssertUnwindSafe(f)) {
            Ok(result) => Ok(result),
            Err(panic_payload) => {
                self.panic_count.fetch_add(1, Ordering::Relaxed);
                
                let panic_info = PanicInfo::from_payload(panic_payload);
                
                match self.strategy {
                    PanicStrategy::Abort => {
                        eprintln!("VEDA: Task panicked (abort strategy)");
                        std::process::abort();
                    }
                    PanicStrategy::Isolate => {}
                    PanicStrategy::LogAndContinue => {
                        eprintln!("VEDA: Task panicked: {}", panic_info.message);
                        if let Some(location) = &panic_info.location {
                            eprintln!("  at {}", location);
                        }
                    }
                }
                
                Err(panic_info)
            }
        }
    }
    
    pub fn panic_count(&self) -> usize {
        self.panic_count.load(Ordering::Relaxed)
    }
    
    pub fn reset_count(&self) {
        self.panic_count.store(0, Ordering::Relaxed);
    }
    
    pub fn strategy(&self) -> PanicStrategy {
        self.strategy
    }
}

impl Default for PanicHandler {
    fn default() -> Self {
        Self::new(PanicStrategy::default())
    }
}

#[derive(Debug, Clone)]
pub struct PanicInfo {
    pub message: String,
    pub location: Option<String>,
}

impl PanicInfo {
    fn from_payload(payload: Box<dyn std::any::Any + Send>) -> Self {
        let message = if let Some(s) = payload.downcast_ref::<&str>() {
            s.to_string()
        } else if let Some(s) = payload.downcast_ref::<String>() {
            s.clone()
        } else {
            "Unknown panic".to_string()
        };
        
        Self {
            message,
            location: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_panic_handler_isolate() {
        let handler = PanicHandler::new(PanicStrategy::Isolate);
        
        let result = handler.execute(|| {
            panic!("test panic");
        });
        
        assert!(result.is_err());
        assert_eq!(handler.panic_count(), 1);
    }
    
    #[test]
    fn test_panic_handler_success() {
        let handler = PanicHandler::new(PanicStrategy::Isolate);
        
        let result = handler.execute(|| 42);
        
        assert_eq!(result.unwrap(), 42);
        assert_eq!(handler.panic_count(), 0);
    }
    
    #[test]
    fn test_panic_counter() {
        let handler = PanicHandler::new(PanicStrategy::LogAndContinue);
        
        for _ in 0..5 {
            let _ = handler.execute(|| {
                panic!("test");
            });
        }
        
        assert_eq!(handler.panic_count(), 5);
        
        handler.reset_count();
        assert_eq!(handler.panic_count(), 0);
    }
}