← back to dongsheng123132__udisk-inspector

Function bodies 35 total

All specs Real LLM only Function bodies
run function · rust · L100-L144 (45 LOC)
src/cli/mod.rs
pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Cli::parse();
    let mode = if cli.json {
        OutputMode::Json
    } else {
        OutputMode::Human
    };

    match cli.command {
        Commands::List => cmd_list(mode).await,
        Commands::Info { drive } => cmd_info(mode, &drive).await,
        Commands::Test {
            mount,
            capacity,
            speed,
            badblock,
            thermal,
            all,
            no_save,
            export_html,
            test_size_mb,
        } => {
            cmd_test(
                mode,
                &cli.db,
                &mount,
                capacity || all,
                speed || all,
                badblock || all,
                if all { Some(120) } else { thermal },
                no_save,
                export_html.as_deref(),
                test_size_mb,
            )
            .await
        }
        Commands::Report { action } => match action {
 
cmd_list function · rust · L145-L180 (36 LOC)
src/cli/mod.rs
async fn cmd_list(mode: OutputMode) -> Result<(), Box<dyn std::error::Error>> {
    let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
        .await?
        .map_err(|e| e)?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &drives);
        }
        OutputMode::Human => {
            if drives.is_empty() {
                println!("No USB drives found.");
                return Ok(());
            }
            let mut table = Table::new();
            table.load_preset(UTF8_FULL);
            table.set_header(vec![
                "Name", "Path", "Mount", "Capacity", "Free", "FS", "Serial",
            ]);
            for d in &drives {
                table.add_row(vec![
                    &d.name,
                    &d.path,
                    &d.mount_point,
                    &info::format_capacity(d.capacity_bytes),
                    &info::format_capacity(d.free_bytes),
                    &d.file_system,
                 
cmd_info function · rust · L181-L212 (32 LOC)
src/cli/mod.rs
async fn cmd_info(mode: OutputMode, drive: &str) -> Result<(), Box<dyn std::error::Error>> {
    let drive_str = drive.to_string();
    let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
        .await?
        .map_err(|e| e)?;

    let found = drives
        .into_iter()
        .find(|d| d.path == drive_str || d.mount_point == drive_str)
        .ok_or_else(|| format!("Drive not found: {}", drive_str))?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &found);
        }
        OutputMode::Human => {
            println!("{}", info::drive_summary(&found));
            println!("  Path:       {}", found.path);
            println!("  Mount:      {}", found.mount_point);
            println!(
                "  Capacity:   {}",
                info::format_capacity(found.capacity_bytes)
            );
            println!("  Free:       {}", info::format_capacity(found.free_bytes));
            println!("  FS:         {}", found.file_sys
cmd_test function · rust · L215-L532 (318 LOC)
src/cli/mod.rs
async fn cmd_test(
    mode: OutputMode,
    db_path: &str,
    mount: &str,
    test_capacity: bool,
    test_speed: bool,
    test_badblock: bool,
    test_thermal: Option<u64>,
    no_save: bool,
    export_html: Option<&str>,
    test_size_mb: u64,
) -> Result<(), Box<dyn std::error::Error>> {
    if !test_capacity && !test_speed && !test_badblock && test_thermal.is_none() {
        let msg = "No test selected. Use --capacity, --speed, --badblock, --thermal SECS, or --all";
        print_error(mode, msg);
        return Err(msg.into());
    }

    STOP_FLAG.store(false, Ordering::Relaxed);

    let start_time = std::time::Instant::now();

    // Get drive info
    let mount_str = mount.to_string();
    let drives = tokio::task::spawn_blocking(detect::list_usb_drives)
        .await?
        .map_err(|e| e)?;

    let drive_info = drives
        .into_iter()
        .find(|d| d.path == mount_str || d.mount_point == mount_str)
        .ok_or_else(|| format!("Drive not found at mount 
cmd_report_list function · rust · L533-L562 (30 LOC)
src/cli/mod.rs
fn cmd_report_list(mode: OutputMode, db_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let db = Database::open(db_path)?;
    let reports = db.list_reports()?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &reports);
        }
        OutputMode::Human => {
            if reports.is_empty() {
                println!("No reports found.");
                return Ok(());
            }
            let mut table = Table::new();
            table.load_preset(UTF8_FULL);
            table.set_header(vec!["ID", "Drive", "Date", "Score"]);
            for r in &reports {
                table.add_row(vec![
                    &r.id[..8],
                    &r.drive_name,
                    &r.test_date,
                    &r.total_score.to_string(),
                ]);
            }
            println!("{table}");
        }
    }
    Ok(())
}
cmd_report_show function · rust · L563-L620 (58 LOC)
src/cli/mod.rs
fn cmd_report_show(
    mode: OutputMode,
    db_path: &str,
    id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let db = Database::open(db_path)?;
    let report = db.get_report(id)?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &report);
        }
        OutputMode::Human => {
            println!("Report: {}", report.id);
            println!("Drive:  {} ({})", report.drive_name, report.drive_serial);
            println!("Date:   {}", report.test_date);
            println!("Score:  {}/100", report.total_score);
            println!(
                "  Capacity: {}/35  Speed: {}/25  Stability: {}/15  BadBlock: {}/25",
                report.capacity_score, report.speed_score, report.stability_score, report.badblock_score
            );
            if let Some(real) = report.real_capacity_bytes {
                println!(
                    "Capacity: {} real / {} claimed",
                    info::format_capacity(real),
           
cmd_report_export function · rust · L621-L660 (40 LOC)
src/cli/mod.rs
fn cmd_report_export(
    mode: OutputMode,
    db_path: &str,
    id: &str,
    html_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let db = Database::open(db_path)?;
    let report = db.get_report(id)?;

    let speed_samples = report.details_json.as_deref().unwrap_or("[]");
    let html = crate::report::html::generate_html_report(
        &report.drive_name,
        &report.test_date,
        report.claimed_capacity_bytes as f64 / 1_000_000_000.0,
        report.real_capacity_bytes.map(|v| v as f64 / 1_000_000_000.0),
        report.seq_read_speed,
        report.seq_write_speed,
        report.random_read_iops,
        report.random_write_iops,
        report.speed_stability,
        report.bad_block_count.unwrap_or(0),
        report.total_blocks.unwrap_or(0),
        report.total_score,
        speed_samples,
        "[]",
    );

    std::fs::write(html_path, &html)?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &serde_json::jso
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
cmd_report_delete function · rust · L661-L679 (19 LOC)
src/cli/mod.rs
fn cmd_report_delete(
    mode: OutputMode,
    db_path: &str,
    id: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let db = Database::open(db_path)?;
    db.delete_report(id)?;

    match mode {
        OutputMode::Json => {
            print_success(mode, &serde_json::json!({"deleted": id}));
        }
        OutputMode::Human => {
            println!("Report {} deleted.", id);
        }
    }
    Ok(())
}
make_progress_bar function · rust · L680-L699 (20 LOC)
src/cli/mod.rs
fn make_progress_bar(mode: OutputMode, prefix: &str) -> Option<ProgressBar> {
    match mode {
        OutputMode::Human => {
            let pb = ProgressBar::new(100);
            pb.set_style(
                ProgressStyle::default_bar()
                    .template(&format!(
                        "{{spinner:.green}} {} [{{bar:40.cyan/blue}}] {{pos}}% {{msg}}",
                        prefix
                    ))
                    .unwrap()
                    .progress_chars("#>-"),
            );
            pb.set_draw_target(indicatif::ProgressDrawTarget::stderr());
            Some(pb)
        }
        OutputMode::Json => None,
    }
}
eprint_progress function · rust · L700-L709 (10 LOC)
src/cli/mod.rs
fn eprint_progress(pb: &Option<ProgressBar>, progress: f64, msg: &str) {
    if let Some(pb) = pb {
        pb.set_position((progress * 100.0) as u64);
        pb.set_message(msg.to_string());
        if progress >= 1.0 {
            pb.finish_and_clear();
        }
    }
}
print_success function · rust · L17-L30 (14 LOC)
src/cli/output.rs
pub fn print_success<T: Serialize>(mode: OutputMode, data: &T) {
    match mode {
        OutputMode::Human => {}
        OutputMode::Json => {
            let envelope = JsonEnvelope {
                success: true,
                data: Some(data),
                error: None,
            };
            println!("{}", serde_json::to_string(&envelope).unwrap());
        }
    }
}
print_error function · rust · L31-L46 (16 LOC)
src/cli/output.rs
pub fn print_error(mode: OutputMode, msg: &str) {
    match mode {
        OutputMode::Human => {
            eprintln!("Error: {}", msg);
        }
        OutputMode::Json => {
            let envelope: JsonEnvelope<()> = JsonEnvelope {
                success: false,
                data: None,
                error: Some(msg.to_string()),
            };
            println!("{}", serde_json::to_string(&envelope).unwrap());
        }
    }
}
new function · rust · L19-L21 (3 LOC)
src/db.rs
    pub fn new() -> Result<Self, DbError> {
        Self::open("udisk_reports.db")
    }
open function · rust · L22-L28 (7 LOC)
src/db.rs
    pub fn open(path: &str) -> Result<Self, DbError> {
        let conn = Connection::open(path)?;
        let db = Self { conn };
        db.init_tables()?;
        Ok(db)
    }
init_tables function · rust · L29-L56 (28 LOC)
src/db.rs
    fn init_tables(&self) -> Result<(), DbError> {
        self.conn.execute_batch(
            "CREATE TABLE IF NOT EXISTS reports (
                id TEXT PRIMARY KEY,
                drive_name TEXT NOT NULL,
                drive_serial TEXT NOT NULL DEFAULT '',
                claimed_capacity_bytes INTEGER NOT NULL DEFAULT 0,
                test_date TEXT NOT NULL,
                total_score INTEGER NOT NULL DEFAULT 0,
                capacity_score INTEGER NOT NULL DEFAULT 0,
                speed_score INTEGER NOT NULL DEFAULT 0,
                stability_score INTEGER NOT NULL DEFAULT 0,
                badblock_score INTEGER NOT NULL DEFAULT 0,
                real_capacity_bytes INTEGER,
                seq_read_speed REAL,
                seq_write_speed REAL,
                random_read_iops REAL,
                random_write_iops REAL,
                speed_stability REAL,
                bad_block_count INTEGER,
                total_blocks INTEGER,
                t
Repobility · code-quality intelligence · https://repobility.com
save_report function · rust · L57-L93 (37 LOC)
src/db.rs
    pub fn save_report(&self, report: &ReportDetail) -> Result<(), String> {
        self.conn
            .execute(
                "INSERT OR REPLACE INTO reports (
                    id, drive_name, drive_serial, claimed_capacity_bytes, test_date,
                    total_score, capacity_score, speed_score, stability_score, badblock_score,
                    real_capacity_bytes, seq_read_speed, seq_write_speed,
                    random_read_iops, random_write_iops, speed_stability,
                    bad_block_count, total_blocks, test_duration_secs, details_json
                ) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20)",
                params![
                    report.id,
                    report.drive_name,
                    report.drive_serial,
                    report.claimed_capacity_bytes,
                    report.test_date,
                    report.total_score,
                    report.capacity_score,
            
get_report function · rust · L94-L134 (41 LOC)
src/db.rs
    pub fn get_report(&self, id: &str) -> Result<ReportDetail, String> {
        self.conn
            .query_row(
                "SELECT id, drive_name, drive_serial, claimed_capacity_bytes, test_date,
                        total_score, capacity_score, speed_score, stability_score, badblock_score,
                        real_capacity_bytes, seq_read_speed, seq_write_speed,
                        random_read_iops, random_write_iops, speed_stability,
                        bad_block_count, total_blocks, test_duration_secs, details_json
                 FROM reports WHERE id = ?1",
                params![id],
                |row| {
                    Ok(ReportDetail {
                        id: row.get(0)?,
                        drive_name: row.get(1)?,
                        drive_serial: row.get(2)?,
                        claimed_capacity_bytes: row.get::<_, i64>(3)? as u64,
                        test_date: row.get(4)?,
                        total_score: row.get::<_
list_reports function · rust · L135-L158 (24 LOC)
src/db.rs
    pub fn list_reports(&self) -> Result<Vec<ReportSummary>, String> {
        let mut stmt = self
            .conn
            .prepare("SELECT id, drive_name, test_date, total_score FROM reports ORDER BY test_date DESC")
            .map_err(|e| format!("Database error: {}", e))?;

        let rows = stmt
            .query_map([], |row| {
                Ok(ReportSummary {
                    id: row.get(0)?,
                    drive_name: row.get(1)?,
                    test_date: row.get(2)?,
                    total_score: row.get::<_, i64>(3)? as u32,
                })
            })
            .map_err(|e| format!("Database error: {}", e))?;

        let mut reports = Vec::new();
        for row in rows {
            reports.push(row.map_err(|e| format!("Database error: {}", e))?);
        }
        Ok(reports)
    }
delete_report function · rust · L159-L171 (13 LOC)
src/db.rs
    pub fn delete_report(&self, id: &str) -> Result<(), String> {
        let affected = self
            .conn
            .execute("DELETE FROM reports WHERE id = ?1", params![id])
            .map_err(|e| format!("Failed to delete report: {}", e))?;

        if affected == 0 {
            Err(format!("Report not found: {}", id))
        } else {
            Ok(())
        }
    }
list_usb_drives function · rust · L14-L28 (15 LOC)
src/disk/detect.rs
pub fn list_usb_drives() -> Result<Vec<DriveInfo>, String> {
    #[cfg(target_os = "windows")]
    {
        list_usb_drives_windows()
    }
    #[cfg(target_os = "macos")]
    {
        list_usb_drives_macos()
    }
    #[cfg(not(any(target_os = "windows", target_os = "macos")))]
    {
        Err("Unsupported platform".to_string())
    }
}
list_usb_drives_windows function · rust · L31-L52 (22 LOC)
src/disk/detect.rs
fn list_usb_drives_windows() -> Result<Vec<DriveInfo>, String> {
    // Use wmic first (more stable, no COM issues), WMI only as enhancement
    let mut drives = list_usb_drives_wmic_fallback().unwrap_or_default();

    // Try WMI to get better device names/serials, but don't fail if it errors
    if let Ok(wmi_drives) = std::panic::catch_unwind(|| list_usb_drives_wmi()) {
        if let Ok(wmi_drives) = wmi_drives {
            for wmi_drive in &wmi_drives {
                if let Some(existing) = drives.iter_mut().find(|d| d.path == wmi_drive.path) {
                    if !wmi_drive.name.is_empty() && wmi_drive.name != "Removable Disk" {
                        existing.name = wmi_drive.name.clone();
                    }
                    if !wmi_drive.serial.is_empty() && existing.serial.is_empty() {
                        existing.serial = wmi_drive.serial.clone();
                    }
                }
            }
        }
    }

    Ok(drives)
}
list_usb_drives_wmi function · rust · L55-L225 (171 LOC)
src/disk/detect.rs
fn list_usb_drives_wmi() -> Result<Vec<DriveInfo>, String> {
    use std::collections::HashMap;
    use wmi::{COMLibrary, WMIConnection};

    #[derive(Deserialize, Debug)]
    #[serde(rename_all = "PascalCase")]
    #[allow(dead_code)]
    struct Win32DiskDrive {
        #[serde(default)]
        caption: Option<String>,
        #[serde(default)]
        device_id: Option<String>,
        #[serde(default)]
        interface_type: Option<String>,
        #[serde(default)]
        serial_number: Option<String>,
        #[serde(default)]
        size: Option<String>,
    }

    #[derive(Deserialize, Debug)]
    #[serde(rename_all = "PascalCase")]
    struct Win32DiskDriveToDiskPartition {
        #[serde(default)]
        antecedent: Option<String>,
        #[serde(default)]
        dependent: Option<String>,
    }

    #[derive(Deserialize, Debug)]
    #[serde(rename_all = "PascalCase")]
    struct Win32LogicalDiskToPartition {
        #[serde(default)]
        antecedent: Option<String
list_usb_drives_wmic_fallback function · rust · L228-L326 (99 LOC)
src/disk/detect.rs
fn list_usb_drives_wmic_fallback() -> Result<Vec<DriveInfo>, String> {
    use std::process::Command;

    let output = Command::new("wmic")
        .args([
            "logicaldisk",
            "where",
            "drivetype=2",
            "get",
            "Caption,Description,FileSystem,FreeSpace,Size,VolumeName,VolumeSerialNumber",
            "/format:csv",
        ])
        .output()
        .map_err(|e| format!("Failed to run wmic: {}", e))?;

    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut drives = Vec::new();

    for line in stdout.lines().skip(1) {
        let line = line.trim();
        if line.is_empty() {
            continue;
        }
        let parts: Vec<&str> = line.split(',').collect();
        // CSV format: Node,Caption,Description,FileSystem,FreeSpace,Size,VolumeName,VolumeSerialNumber
        if parts.len() < 8 {
            continue;
        }

        let caption = parts[1].trim();
        let description = parts[2].trim();
        
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
list_usb_drives_macos function · rust · L329-L458 (130 LOC)
src/disk/detect.rs
fn list_usb_drives_macos() -> Result<Vec<DriveInfo>, String> {
    use std::process::Command;

    // Get list of external disks
    let output = Command::new("diskutil")
        .args(["list", "-plist", "external"])
        .output()
        .map_err(|e| format!("Failed to run diskutil: {}", e))?;

    let stdout = String::from_utf8_lossy(&output.stdout);

    // Simple plist XML parsing to extract disk identifiers
    let mut disk_ids: Vec<String> = Vec::new();
    let mut in_whole_disks = false;
    for line in stdout.lines() {
        let trimmed = line.trim();
        if trimmed.contains("WholeDisks") {
            in_whole_disks = true;
            continue;
        }
        if in_whole_disks {
            if trimmed == "</array>" {
                in_whole_disks = false;
                continue;
            }
            if trimmed.starts_with("<string>") && trimmed.ends_with("</string>") {
                let disk_id = trimmed
                    .trim_start_matches("<string>
extract_plist_string function · rust · L461-L483 (23 LOC)
src/disk/detect.rs
fn extract_plist_string(plist: &str, key: &str) -> Option<String> {
    let key_tag = format!("<key>{}</key>", key);
    let mut found_key = false;
    for line in plist.lines() {
        let trimmed = line.trim();
        if trimmed == key_tag {
            found_key = true;
            continue;
        }
        if found_key {
            if trimmed.starts_with("<string>") && trimmed.ends_with("</string>") {
                return Some(
                    trimmed
                        .trim_start_matches("<string>")
                        .trim_end_matches("</string>")
                        .to_string(),
                );
            }
            return None;
        }
    }
    None
}
extract_plist_integer function · rust · L486-L507 (22 LOC)
src/disk/detect.rs
fn extract_plist_integer(plist: &str, key: &str) -> Option<u64> {
    let key_tag = format!("<key>{}</key>", key);
    let mut found_key = false;
    for line in plist.lines() {
        let trimmed = line.trim();
        if trimmed == key_tag {
            found_key = true;
            continue;
        }
        if found_key {
            if trimmed.starts_with("<integer>") && trimmed.ends_with("</integer>") {
                return trimmed
                    .trim_start_matches("<integer>")
                    .trim_end_matches("</integer>")
                    .parse()
                    .ok();
            }
            return None;
        }
    }
    None
}
extract_plist_bool function · rust · L510-L530 (21 LOC)
src/disk/detect.rs
fn extract_plist_bool(plist: &str, key: &str) -> Option<bool> {
    let key_tag = format!("<key>{}</key>", key);
    let mut found_key = false;
    for line in plist.lines() {
        let trimmed = line.trim();
        if trimmed == key_tag {
            found_key = true;
            continue;
        }
        if found_key {
            if trimmed == "<true/>" {
                return Some(true);
            }
            if trimmed == "<false/>" {
                return Some(false);
            }
            return None;
        }
    }
    None
}
format_capacity function · rust · L2-L13 (12 LOC)
src/disk/info.rs
pub fn format_capacity(bytes: u64) -> String {
    if bytes >= 1_000_000_000_000 {
        format!("{:.1} TB", bytes as f64 / 1_000_000_000_000.0)
    } else if bytes >= 1_000_000_000 {
        format!("{:.1} GB", bytes as f64 / 1_000_000_000.0)
    } else if bytes >= 1_000_000 {
        format!("{:.1} MB", bytes as f64 / 1_000_000.0)
    } else {
        format!("{:.1} KB", bytes as f64 / 1_000.0)
    }
}
drive_summary function · rust · L14-L23 (10 LOC)
src/disk/info.rs
pub fn drive_summary(info: &DriveInfo) -> String {
    format!(
        "{} ({}) - {} [{}]",
        info.name,
        info.path,
        format_capacity(info.capacity_bytes),
        info.file_system
    )
}
write_block function · rust · L10-L23 (14 LOC)
src/disk/io.rs
pub fn write_block(path: &Path, offset: u64, data: &[u8]) -> Result<(), String> {
    let block_index = offset / BLOCK_SIZE as u64;
    let file_path = path.join(format!("_udisk_test_block_{:06}.dat", block_index));

    let mut file =
        fs::File::create(&file_path).map_err(|e| format!("Failed to create block file: {}", e))?;
    file.write_all(data)
        .map_err(|e| format!("Failed to write block: {}", e))?;
    file.sync_all()
        .map_err(|e| format!("Failed to sync block: {}", e))?;
    drop(file);

    Ok(())
}
read_block function · rust · L27-L40 (14 LOC)
src/disk/io.rs
pub fn read_block(path: &Path, offset: u64, size: usize) -> Result<Vec<u8>, String> {
    let block_index = offset / BLOCK_SIZE as u64;
    let file_path = path.join(format!("_udisk_test_block_{:06}.dat", block_index));

    // Open fresh handle to bypass read cache
    let mut file =
        fs::File::open(&file_path).map_err(|e| format!("Failed to open block file: {}", e))?;
    let mut buf = vec![0u8; size];
    file.read_exact(&mut buf)
        .map_err(|e| format!("Failed to read block: {}", e))?;
    drop(file);

    Ok(buf)
}
Source: Repobility analyzer · https://repobility.com
sync_drive function · rust · L43-L60 (18 LOC)
src/disk/io.rs
pub fn sync_drive(path: &Path) -> Result<(), String> {
    #[cfg(target_os = "windows")]
    {
        // On Windows, we rely on File::sync_all() per file.
        // Optionally call FlushFileBuffers on the volume handle, but that requires admin.
        let _ = path;
        Ok(())
    }
    #[cfg(not(target_os = "windows"))]
    {
        use std::process::Command;
        let _ = path;
        Command::new("sync")
            .output()
            .map_err(|e| format!("sync failed: {}", e))?;
        Ok(())
    }
}
main function · rust · L5-L27 (23 LOC)
src/main.rs
async fn main() {
    env_logger::init();

    ctrlc::set_handler(move || {
        eprintln!("\nStopping test...");
        udisk_inspector_lib::STOP_FLAG.store(true, Ordering::Relaxed);
    })
    .ok();

    if let Err(e) = cli::run().await {
        let json_mode = std::env::args().any(|a| a == "--json");
        if json_mode {
            let envelope = serde_json::json!({
                "success": false,
                "error": e.to_string()
            });
            println!("{}", envelope);
        } else {
            eprintln!("Error: {}", e);
        }
        std::process::exit(1);
    }
}
generate_html_report function · rust · L1-L210 (210 LOC)
src/report/html.rs
pub fn generate_html_report(
    drive_name: &str,
    test_date: &str,
    claimed_capacity_gb: f64,
    real_capacity_gb: Option<f64>,
    seq_read: Option<f64>,
    seq_write: Option<f64>,
    random_read_iops: Option<f64>,
    random_write_iops: Option<f64>,
    stability: Option<f64>,
    bad_blocks: u64,
    _total_blocks: u64,
    total_score: u32,
    speed_samples_json: &str,
    bad_block_positions_json: &str,
) -> String {
    let score_class = if total_score >= 90 {
        "excellent"
    } else if total_score >= 70 {
        "good"
    } else if total_score >= 50 {
        "fair"
    } else {
        "poor"
    };

    let grade_text = if total_score >= 90 {
        "优秀"
    } else if total_score >= 70 {
        "良好"
    } else if total_score >= 50 {
        "一般"
    } else {
        "差"
    };

    let real_gb = match real_capacity_gb {
        Some(v) => format!("{:.1} GB", v),
        None => "未测试".to_string(),
    };

    let seq_read_str = match seq_read {
        So
calculate_score function · rust · L18-L104 (87 LOC)
src/report/score.rs
pub fn calculate_score(
    claimed_capacity: u64,
    real_capacity: Option<u64>,
    seq_read_speed: Option<f64>,
    seq_write_speed: Option<f64>,
    stability: Option<f64>,
    speed_drops: Option<u32>,
    bad_block_count: Option<u64>,
    total_blocks: Option<u64>,
) -> QualityScore {
    // Capacity score (35 points)
    let capacity_score = match real_capacity {
        Some(real) => {
            let ratio = real as f64 / claimed_capacity.max(1) as f64;
            if ratio >= 0.95 {
                35
            } else if ratio < 0.50 {
                0
            } else {
                ((ratio - 0.50) / 0.45 * 35.0) as u32
            }
        }
        None => 0,
    };

    // Speed score (25 points)
    let read_score = match seq_read_speed {
        Some(speed) => ((speed / 100.0).min(1.0) * 12.0) as u32,
        None => 0,
    };
    let write_score = match seq_write_speed {
        Some(speed) => ((speed / 50.0).min(1.0) * 13.0) as u32,
        None => 0,
    }