colmap 0.1.2

A comprehensive Rust library for COLMAP-style computer vision and 3D reconstruction
Documentation
//! 工具模块
//!
//! 这个模块提供了各种实用工具函数,包括:
//! - 日志工具
//! - 进度条
//! - 时间测量
//! - 内存管理

// 所有工具函数都在这个文件中实现

use std::time::{Duration, Instant};
use log::info;

/// 简单的计时器
#[derive(Debug)]
pub struct SimpleTimer {
    start: Instant,
    name: String,
}

impl SimpleTimer {
    /// 创建新的计时器
    pub fn new(name: impl Into<String>) -> Self {
        let name = name.into();
        info!("开始计时: {}", name);
        Self {
            start: Instant::now(),
            name,
        }
    }
    
    /// 获取已经过的时间
    pub fn elapsed(&self) -> Duration {
        self.start.elapsed()
    }
    
    /// 记录中间时间点
    pub fn checkpoint(&self, message: &str) {
        let elapsed = self.elapsed();
        info!("{} - {}: {:.2}s", self.name, message, elapsed.as_secs_f64());
    }
}

impl Drop for SimpleTimer {
    fn drop(&mut self) {
        let elapsed = self.elapsed();
        info!("完成计时: {} - 总耗时: {:.2}s", self.name, elapsed.as_secs_f64());
    }
}

/// 格式化字节大小
pub fn format_bytes(bytes: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    const THRESHOLD: f64 = 1024.0;
    
    if bytes == 0 {
        return "0 B".to_string();
    }
    
    let mut size = bytes as f64;
    let mut unit_index = 0;
    
    while size >= THRESHOLD && unit_index < UNITS.len() - 1 {
        size /= THRESHOLD;
        unit_index += 1;
    }
    
    format!("{:.1} {}", size, UNITS[unit_index])
}

/// 格式化持续时间
pub fn format_duration(duration: Duration) -> String {
    let total_seconds = duration.as_secs();
    let hours = total_seconds / 3600;
    let minutes = (total_seconds % 3600) / 60;
    let seconds = total_seconds % 60;
    let millis = duration.subsec_millis();
    
    if hours > 0 {
        format!("{}h {}m {}s", hours, minutes, seconds)
    } else if minutes > 0 {
        format!("{}m {}s", minutes, seconds)
    } else if seconds > 0 {
        format!("{}.{:03}s", seconds, millis)
    } else {
        format!("{}ms", millis)
    }
}

/// 验证参数范围
pub fn validate_range<T: PartialOrd + std::fmt::Display + Copy>(
    value: T,
    min: T,
    max: T,
    name: &str,
) -> crate::core::Result<()> {
    if value < min || value > max {
        return Err(crate::core::ColmapError::InvalidParameter(
            format!("{} 必须在 [{}, {}] 范围内,当前值: {}", name, min, max, value)
        ));
    }
    Ok(())
}

/// 验证参数为正数
pub fn validate_positive<T: PartialOrd + std::fmt::Display + Copy + Default>(
    value: T,
    name: &str,
) -> crate::core::Result<()> {
    if value <= T::default() {
        return Err(crate::core::ColmapError::InvalidParameter(
            format!("{} 必须为正数,当前值: {}", name, value)
        ));
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;

    #[test]
    fn test_format_bytes() {
        assert_eq!(format_bytes(0), "0 B");
        assert_eq!(format_bytes(512), "512.0 B");
        assert_eq!(format_bytes(1024), "1.0 KB");
        assert_eq!(format_bytes(1536), "1.5 KB");
        assert_eq!(format_bytes(1024 * 1024), "1.0 MB");
    }

    #[test]
    fn test_format_duration() {
        assert_eq!(format_duration(Duration::from_millis(500)), "500ms");
        assert_eq!(format_duration(Duration::from_secs(1)), "1.000s");
        assert_eq!(format_duration(Duration::from_secs(65)), "1m 5s");
        assert_eq!(format_duration(Duration::from_secs(3665)), "1h 1m 5s");
    }

    #[test]
    fn test_timer() {
        let timer = SimpleTimer::new("测试计时器");
        thread::sleep(Duration::from_millis(10));
        assert!(timer.elapsed() >= Duration::from_millis(10));
    }

    #[test]
    fn test_validation() {
        assert!(validate_range(5, 0, 10, "test").is_ok());
        assert!(validate_range(-1, 0, 10, "test").is_err());
        assert!(validate_range(11, 0, 10, "test").is_err());
        
        assert!(validate_positive(1, "test").is_ok());
        assert!(validate_positive(0, "test").is_err());
        assert!(validate_positive(-1, "test").is_err());
    }
}