Function write_files

Source
pub fn write_files(
    export_file_type: ExportFileType,
    workspace_path: &Path,
    machines: &HashMap<String, Machine>,
    progress_callback: ProgressCallback,
) -> Result<PathBuf, Box<dyn Error + Send + Sync>>
Expand description

Writes machine data to the specified export file type.

This function handles the export of machine data to the chosen format (SQLite, JSON, or CSV) by creating the necessary export folder in the workspace path and invoking the appropriate writer function. It ensures that the target directory exists, then delegates the writing task to the relevant module based on the selected ExportFileType. Progress updates and messages are provided via a callback function.

§Parameters

  • export_file_type: An ExportFileType enum specifying the format for data export. Supported types are:
    • ExportFileType::Sqlite: Exports data to a SQLite database file.
    • ExportFileType::Json: Exports data to a JSON file.
    • ExportFileType::Csv: Exports data to a CSV file.
  • workspace_path: A reference to a Path representing the base directory where the exported files will be stored.
  • machines: A reference to a HashMap where keys are machine names and values are Machine structs containing detailed information about each MAME machine.
  • progress_callback: A callback function of type ProgressCallback that provides status updates and progress information during the export process. The callback receives a ProgressInfo struct containing progress, total, message, and callback_type.

§Returns

Returns a Result<PathBuf, Box<dyn Error + Send + Sync>>:

  • On success: Contains a PathBuf representing the path to the folder where the export files are stored.
  • On failure: Contains an error if the export folder cannot be created or if there is an issue during the writing process.

§Errors

This function will return an error if:

  • The export folder cannot be created due to permission issues or file system errors.
  • The writing process fails for the selected export file type due to data formatting issues or I/O errors.

§Callback

The progress callback function provides real-time updates on the export process. It receives:

  • progress: The current progress of the export operation (e.g., number of records processed).
  • total: The total number of items to be exported.
  • message: A status message indicating the current operation (e.g., “Creating export folder”, “Writing to file”).
  • callback_type: The type of callback, such as CallbackType::Info, CallbackType::Error, CallbackType::Progress, or CallbackType::Finish.

§Example Sqlite

fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    // Define the workspace path
    let workspace_path = Path::new("playground");

    // Create a multi progress bar
    let multi_progress: Arc<MultiProgress> = Arc::new(MultiProgress::new());

    // Create progress bars for each data type
    let progress_bars = Arc::new(
        MameDataType::all_variants()
            .iter()
            .map(|&data_type| {
                let progress_bar = multi_progress.add(ProgressBar::new(100));
                progress_bar.set_style(
                    ProgressStyle::default_bar()
                        .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] [{{bar:20.cyan/blue}}] {{pos}}/{{len}} ({{eta}}) {{msg}}"))
                        .progress_chars("#>-"),
                );
                (data_type, progress_bar)
            })
            .collect::<Vec<_>>(),
    );

    // Create a shared progress callback
    let shared_progress_callback: SharedProgressCallback = Arc::new(
        move |data_type: MameDataType, progress_info: ProgressInfo| {
            if let Some((_, progress_bar)) = progress_bars.iter().find(|(dt, _)| *dt == data_type) {
                // Update the progress bar
                match progress_info.callback_type {
                    CallbackType::Progress => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                    }
                    CallbackType::Info => {
                        progress_bar.set_message(progress_info.message);
                    }
                    CallbackType::Finish => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                        progress_bar.finish_with_message(progress_info.message);
                    }
                    CallbackType::Error => {
                        progress_bar.finish_with_message(progress_info.message);
                    }
                }
            }
        },
    );

    let handle = thread::spawn(move || {
        multi_progress.join().unwrap();
    });

    // Read the files
    let machines = read_files(workspace_path, shared_progress_callback);

    handle.join().unwrap();

    // Print the result
    match machines {
        Ok(machines) => {
            let progress_bar = ProgressBar::new(100);
            progress_bar.set_style(
                ProgressStyle::default_bar()
                    .template("{spinner:.green} [{elapsed_precise}] [{bar:20.cyan/blue}] {pos}/{len} ({eta}) {msg}")
                    .progress_chars("#>-"),
            );

            // Create a progress callback
            let progress_callback: ProgressCallback =
                Box::new(move |progress_info: ProgressInfo| {
                    // Update the progress bar
                    match progress_info.callback_type {
                        CallbackType::Progress => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                        }
                        CallbackType::Info => {
                            progress_bar.set_message(progress_info.message);
                        }
                        CallbackType::Finish => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                            progress_bar.finish_with_message(progress_info.message);
                        }
                        CallbackType::Error => {
                            progress_bar.finish_with_message(progress_info.message);
                        }
                    }
                });
            // Write the machines to a SQLite database
            let result = write_files(
                ExportFileType::Sqlite,
                workspace_path,
                &machines,
                progress_callback,
            );
            match result {
                Ok(result) => {
                    println!("Machines written to {}.", result.to_string_lossy());
                }
                Err(e) => {
                    eprintln!("Error writing data files: {}", e);
                }
            }
        }
        Err(e) => {
            eprintln!("Error reading data files: {}", e);
        }
    }

    Ok(())
}

§Example Csv

fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    // Define the workspace path
    let workspace_path = Path::new("playground");

    // Create a multi progress bar
    let multi_progress: Arc<MultiProgress> = Arc::new(MultiProgress::new());

    // Create progress bars for each data type
    let progress_bars = Arc::new(
        MameDataType::all_variants()
            .iter()
            .map(|&data_type| {
                let progress_bar = multi_progress.add(ProgressBar::new(100));
                progress_bar.set_style(
                    ProgressStyle::default_bar()
                        .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] [{{bar:20.cyan/blue}}] {{pos}}/{{len}} ({{eta}}) {{msg}}"))
                        .progress_chars("#>-"),
                );
                (data_type, progress_bar)
            })
            .collect::<Vec<_>>(),
    );

    // Create a shared progress callback
    let shared_progress_callback: SharedProgressCallback = Arc::new(
        move |data_type: MameDataType, progress_info: ProgressInfo| {
            if let Some((_, progress_bar)) = progress_bars.iter().find(|(dt, _)| *dt == data_type) {
                // Update the progress bar
                match progress_info.callback_type {
                    CallbackType::Progress => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                    }
                    CallbackType::Info => {
                        progress_bar.set_message(progress_info.message);
                    }
                    CallbackType::Finish => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                        progress_bar.finish_with_message(progress_info.message);
                    }
                    CallbackType::Error => {
                        progress_bar.finish_with_message(progress_info.message);
                    }
                }
            }
        },
    );

    let handle = thread::spawn(move || {
        multi_progress.join().unwrap();
    });

    // Read the files
    let machines = read_files(workspace_path, shared_progress_callback);

    handle.join().unwrap();

    // Print the result
    match machines {
        Ok(machines) => {
            let progress_bar = ProgressBar::new(100);
            progress_bar.set_style(
                ProgressStyle::default_bar()
                    .template("{spinner:.green} [{elapsed_precise}] [{bar:20.cyan/blue}] {pos}/{len} ({eta}) {msg}")
                    .progress_chars("#>-"),
            );

            // Create a progress callback
            let progress_callback: ProgressCallback =
                Box::new(move |progress_info: ProgressInfo| {
                    // Update the progress bar
                    match progress_info.callback_type {
                        CallbackType::Progress => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                        }
                        CallbackType::Info => {
                            progress_bar.set_message(progress_info.message);
                        }
                        CallbackType::Finish => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                            progress_bar.finish_with_message(progress_info.message);
                        }
                        CallbackType::Error => {
                            progress_bar.finish_with_message(progress_info.message);
                        }
                    }
                });
            // Write the machines to CSV files
            let result = write_files(
                ExportFileType::Csv,
                workspace_path,
                &machines,
                progress_callback,
            );
            match result {
                Ok(result) => {
                    println!("Machines written to {}.", result.to_string_lossy());
                }
                Err(e) => {
                    eprintln!("Error writing data files: {}", e);
                }
            }
        }
        Err(e) => {
            eprintln!("Error reading data files: {}", e);
        }
    }

    Ok(())
}

§Example Json

fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
    // Define the workspace path
    let workspace_path = Path::new("playground");

    // Create a multi progress bar
    let multi_progress: Arc<MultiProgress> = Arc::new(MultiProgress::new());

    // Create progress bars for each data type
    let progress_bars = Arc::new(
        MameDataType::all_variants()
            .iter()
            .map(|&data_type| {
                let progress_bar = multi_progress.add(ProgressBar::new(100));
                progress_bar.set_style(
                    ProgressStyle::default_bar()
                        .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] [{{bar:20.cyan/blue}}] {{pos}}/{{len}} ({{eta}}) {{msg}}"))
                        .progress_chars("#>-"),
                );
                (data_type, progress_bar)
            })
            .collect::<Vec<_>>(),
    );

    // Create a shared progress callback
    let shared_progress_callback: SharedProgressCallback = Arc::new(
        move |data_type: MameDataType, progress_info: ProgressInfo| {
            if let Some((_, progress_bar)) = progress_bars.iter().find(|(dt, _)| *dt == data_type) {
                // Update the progress bar
                match progress_info.callback_type {
                    CallbackType::Progress => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                    }
                    CallbackType::Info => {
                        progress_bar.set_message(progress_info.message);
                    }
                    CallbackType::Finish => {
                        progress_bar.set_length(progress_info.total);
                        progress_bar.set_position(progress_info.progress);
                        progress_bar.finish_with_message(progress_info.message);
                    }
                    CallbackType::Error => {
                        progress_bar.finish_with_message(progress_info.message);
                    }
                }
            }
        },
    );

    let handle = thread::spawn(move || {
        multi_progress.join().unwrap();
    });

    // Read the files
    let machines = read_files(workspace_path, shared_progress_callback);

    handle.join().unwrap();

    // Print the result
    match machines {
        Ok(machines) => {
            let progress_bar = ProgressBar::new(100);
            progress_bar.set_style(
                ProgressStyle::default_bar()
                    .template("{spinner:.green} [{elapsed_precise}] [{bar:20.cyan/blue}] {pos}/{len} ({eta}) {msg}")
                    .progress_chars("#>-"),
            );

            // Create a progress callback
            let progress_callback: ProgressCallback =
                Box::new(move |progress_info: ProgressInfo| {
                    // Update the progress bar
                    match progress_info.callback_type {
                        CallbackType::Progress => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                        }
                        CallbackType::Info => {
                            progress_bar.set_message(progress_info.message);
                        }
                        CallbackType::Finish => {
                            progress_bar.set_length(progress_info.total);
                            progress_bar.set_position(progress_info.progress);
                            progress_bar.finish_with_message(progress_info.message);
                        }
                        CallbackType::Error => {
                            progress_bar.finish_with_message(progress_info.message);
                        }
                    }
                });
            // Write the machines to Json files
            let result = write_files(
                ExportFileType::Json,
                workspace_path,
                &machines,
                progress_callback,
            );
            match result {
                Ok(result) => {
                    println!("Machines written to {}.", result.to_string_lossy());
                }
                Err(e) => {
                    eprintln!("Error writing data files: {}", e);
                }
            }
        }
        Err(e) => {
            eprintln!("Error reading data files: {}", e);
        }
    }

    Ok(())
}