motorcortex-rust 0.2.0

Motorcortex Rust: A library for Rust client applications to control Motorcortex Core.
Documentation
use serde::Deserialize;
use std::{env, fs};
use std::path::Path;

// Define the structure for parsing the JSON file
#[derive(Deserialize)]
struct HashEntry {
    r#type: String, // Escape 'type' since it's a Rust keyword
    hash: String,
}

fn main() {
    let out_dir = std::env::var("OUT_DIR").unwrap();
    let proto_dir = "motorcortex-msg";
    let proto_file = "motorcortex-msg/motorcortex.proto";
    let hash_file = "motorcortex-msg/motorcortex_hash.json";
    let generated_file = Path::new(&out_dir).join("motorcortex.rs");
    let destination = Path::new("src/msg/motorcortex_msg.rs"); // Permanent location

    println!("cargo:rerun-if-changed={}", proto_file);
    println!("cargo:rerun-if-changed={}", hash_file);

    if env::var("COPY_FILES").is_ok() {
        // Compile the Protobuf file into Rust
        prost_build::compile_protos(&[proto_file], &[proto_dir]).unwrap();
        fs::copy(generated_file, destination).unwrap(); // Copy the file
        // Parse predefined hashes from the JSON file
        let hash_map = parse_hashes_from_json(hash_file).unwrap();
        // Modify the generated Rust file to include HASH implementations
        let modified_code = add_hashes_to_generated_code(&hash_map, &destination);
        fs::write(destination, modified_code).unwrap(); // Write the new content
    }
}

// Function to parse predefined hashes from the JSON file
fn parse_hashes_from_json(
    json_path: &str,
) -> Result<std::collections::HashMap<String, u32>, Box<dyn std::error::Error>> {
    let json_content = fs::read_to_string(json_path)?; // Read the JSON file
    let hash_entries: Vec<HashEntry> = serde_json::from_str(&json_content)?;

    let mut hash_map = std::collections::HashMap::new();
    for entry in hash_entries {
        let hash_value = u32::from_str_radix(&entry.hash.trim_start_matches("0x"), 16)?; // Convert hex string to u32
        hash_map.insert(entry.r#type.clone(), hash_value); // Use the type as the key
    }

    Ok(hash_map)
}

// Function to modify the generated Rust code to include hash values
fn add_hashes_to_generated_code(
    hash_map: &std::collections::HashMap<String, u32>,
    rust_file_path: &Path,
) -> String {
    let rust_code = fs::read_to_string(rust_file_path).unwrap(); // Read the generated Rust code
    let mut output_code = format!("use crate::Hash;\n{}", rust_code);
    for (qualified_name, &hash_value) in hash_map {
        // Convert `motorcortex.TypeName` to just `TypeName` for the message
        let type_name = qualified_name.split('.').last().unwrap();

        // Append the implementation of the Hash trait for this message
        let hash_impl = format!(
            r#"
impl Hash for {type_name} {{
    const HASH: u32 = 0x{hash_value:08x};
}}
"#,
            type_name = type_name,
            hash_value = hash_value
        );

        output_code.push_str(&hash_impl);
    }

    output_code
}