如何确定include包含的rust-protobuf生成的.rs文件中的消息!宏

时间:2016-07-28 16:56:18

标签: rust protocol-buffers

我之前曾问过How can I include an arbitrary set of Protobuf-built files without knowing their names? - 这是一个基于结果的跟进问题。

我现在有一个我包含的文件,它包含各自不同的模块 - 即:

mod foo;
mod bar;

这些模块及其名称可以完全随机,具体取决于用户放置在原型文件目录中的内容。

我需要对这些随机模块执行操作。例如,我想要做的第一件事是获取这些新模块中存在的所有消息,并将它们作为字符串呈现给我可以推送到矢量。

真的是一个2部分的问题:

  1. 有没有办法让我无法知道我现在包含在这个包含文件的模块的名称!并使用它们内部的结构(一般 - 现在我已经包含它们)。
  2. 在上面之后,如何在protobuf生成的.rs文件/模块中获取所有可能的消息。每个.rs文件都有FileDescriptorProto()方法,查看Google protobuf文档,看起来与此类似:Google Protobuf FileDescriptor

2 个答案:

答案 0 :(得分:1)

如果包含由build.rs脚本生成的单个文件,该怎么办?该脚本可以扫描给定目录并生成正确的文件。

我有一个可以链接到的示例,但它包含Project Euler解决方案的解决方案,因此我不确定人们对此的看法。

以下是我使用的build.rs

// Generate the problem list based on available modules.

use std::env;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

use regex::Regex;

extern crate regex;

fn main() {
    let odir = env::var("OUT_DIR").unwrap();
    let cwd = env::current_dir().unwrap().to_str().unwrap().to_owned();
    let dst = Path::new(&odir);
    let gen_name = dst.join("plist.rs");
    let mut f = File::create(&gen_name).unwrap();
    writeln!(&mut f, "// Auto-generated, do not edit.").unwrap();
    writeln!(&mut f, "").unwrap();
    writeln!(&mut f, "pub use super::Problem;").unwrap();
    writeln!(&mut f, "").unwrap();

    let problems = get_problems();

    // Generate the inputs.
    for &p in problems.iter() {
        writeln!(&mut f, "#[path=\"{1}/src/pr{0:03}.rs\"] mod pr{0:03};", p, cwd).unwrap();
    }
    writeln!(&mut f, "").unwrap();

    // Make the problem set.
    writeln!(&mut f, "pub fn make() -> Vec<Box<Problem + 'static>> {{").unwrap();
    writeln!(&mut f, "    let mut probs = Vec::new();").unwrap();
    for &p in problems.iter() {
        writeln!(&mut f, "    add_problem!(probs, pr{:03}::Solution);", p).unwrap();
    }
    writeln!(&mut f, "    probs").unwrap();
    writeln!(&mut f, "}}").unwrap();

    drop(f);
}

// Get all of the problems, based on standard filenames of "src/prxxx.rs" where xxx is the problem
// number.  Returns the result, sorted.
fn get_problems() -> Vec<u32> {
    let mut result = vec![];

    let re = Regex::new(r"^.*/pr(\d\d\d)\.rs$").unwrap();
    for entry in fs::read_dir(&Path::new("src")).unwrap() {
        let entry = entry.unwrap();
        let p = entry.path();
        let n = p.as_os_str().to_str();
        let name = match n {
            Some(n) => n,
            None => continue,
        };
        match re.captures(name) {
            None => continue,
            Some(cap) => {
                let num: u32 = cap.at(1).unwrap().parse().unwrap();
                result.push(num);
            },
        }
    }

    result.sort();
    result
}

src下的另一个源文件具有以下内容:

include!(concat!(env!("OUT_DIR"), "/plist.rs"));

答案 1 :(得分:0)

根据@ Shepmaster在原帖中评论中的建议,我找到了一种方法:

由于Rust不支持反射(在本文发布时),我不得不扩展我的货物构建脚本,以便在生成的文件中编写代码,以便我知道这些符号始终存在。

我为我所包含的每个模块生成了特定的函数(因为我在那时拥有了它们的模块名称),然后生成了具有通用名称的“聚合”函数,我可以在我的主代码中调用它们。