monoio_rust2go_cli/
lib.rs

1use std::io::Cursor;
2
3use clap::Parser;
4use monoio_rust2go_common::raw_file::RawRsFile;
5
6#[derive(Parser, Debug, Default, Clone)]
7#[command(author, version, about, long_about = None)]
8pub struct Args {
9    /// Path of source rust file
10    #[arg(short, long)]
11    pub src: String,
12
13    /// Path of destination go file
14    #[arg(short, long)]
15    pub dst: String,
16
17    /// With or without go main function
18    #[arg(long, default_value = "false")]
19    pub without_main: bool,
20
21    /// Go 1.18 compatible
22    #[arg(long, default_value = "false")]
23    pub go118: bool,
24
25    /// Disable auto format go file
26    #[arg(long, default_value = "false")]
27    pub no_fmt: bool,
28}
29
30pub fn generate(args: &Args) {
31    // Read and parse rs file.
32    let file_content = std::fs::read_to_string(&args.src).expect("Unable to read file");
33    let raw_file = RawRsFile::new(file_content);
34
35    // Convert to Ref structs and write to output file.
36    let (name_mapping, ref_content) = raw_file
37        .convert_structs_to_ref()
38        .expect("Unable to convert to ref");
39    std::fs::write(&args.dst, ref_content.to_string()).expect("Unable to write file");
40
41    // Convert output file with cbindgen.
42    let mut cbuilder = cbindgen::Builder::new()
43        .with_language(cbindgen::Language::C)
44        .with_src(&args.dst)
45        .with_header("// Generated by rust2go. Please DO NOT edit this C part manually.");
46    for name in name_mapping.values() {
47        cbuilder = cbuilder.include_item(name.to_string());
48    }
49    let mut output = Vec::<u8>::new();
50    cbuilder
51        .generate()
52        .expect("Unable to generate bindings")
53        .write(Cursor::new(&mut output));
54
55    // Convert headers into golang.
56    let mut output = String::from_utf8(output).expect("Unable to convert to string");
57
58    let traits = raw_file.convert_trait().unwrap();
59    traits
60        .iter()
61        .for_each(|t| output.push_str(&t.generate_c_callbacks()));
62
63    let import_reflect = if args.go118 { "\n\"reflect\"" } else { "" };
64    let mut go_content = format!(
65    "package main\n\n/*\n{output}*/\nimport \"C\"\nimport ({import_reflect}\n\"unsafe\"\n\"runtime\"\n)\n"
66);
67    let levels = raw_file.convert_structs_levels().unwrap();
68    traits.iter().for_each(|t| {
69        go_content.push_str(&t.generate_go_interface());
70        go_content.push_str(&t.generate_go_exports(&levels));
71    });
72    go_content.push_str(
73        &raw_file
74            .convert_structs_to_go(&levels, args.go118)
75            .expect("Unable to generate go structs"),
76    );
77    if !args.without_main {
78        go_content.push_str("func main() {}\n");
79    }
80
81    std::fs::write(&args.dst, go_content).expect("Unable to write file");
82
83    if !args.no_fmt {
84        std::process::Command::new("go")
85            .arg("fmt")
86            .arg(&args.dst)
87            .status()
88            .unwrap();
89    }
90}