2016-07-28 64 views
3

我以前问How can I include an arbitrary set of Protobuf-built files without knowing their names? - 这是一个后续问题的基础上的结果。如何确定由包含的rust-protobuf生成的.rs文件中的消息!宏

我现在有一个文件,我包括包含在其自己的行中不同的模块 - 即:

mod foo; 
mod bar; 

这些模块及其名称可以根据哪些用户已经把目录完全随机的为原始文件。

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

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

  1. 有没有方法可以让我不知道我现在包括这个文件,包括模块名称!并使用它们内部的结构(一般 - 现在我已包括它们)。
  2. 之后,如何获得一个protobuf生成.rs文件/模块内的所有可能的消息。每个.RS文件有一个FileDescriptorProto()方法,它寻找的谷歌的protobuf文件上,类似于这样:Google Protobuf FileDescriptor
+0

我不认为你可以。本质上,你要求反思,这并不是你所需要的。作为一个例子,考虑'#[test]'属性,它基本上做了你想要的同样的事情 - 它收集所有注释的函数并调用它们。这是作为编译器本身的补充而实现的,而不是大多数程序员可用的技术。相反,请考虑增强文件转换工具,以生成一个您可以始终信任的知名和必需符号。 – Shepmaster

+0

如果我要求有一个顶级proto文件为所有其他proto文件执行了“import .proto”(在实际的.proto文件中),那该怎么办?如果我这样做了,我可以包括那个顶层。rs文件(将被编译),然后使用返回FileDescriptorProto来获得其他原型结构的方法?也许我不完全理解FileDescriptorProto()方法是如何工作的... –

回答

0

我已经想出了一个办法做到这一点的基础上,@ Shepmaster的建议在原帖子的评论:

由于Rust不支持反思(在这篇文章的时间),我不得不扩大我的货物bu ild脚本在正在生成的文件中编写代码,以使我知道的符号始终存在。

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

1

大约如果包括由build.rs脚本生成一个文件是什么。该脚本可以扫描给定的目录并生成适当的文件。

我确实有一个可以链接到的例子,但它包含了欧拉项目解决方案的解决方案,所以我不确定人们对此的看法。

这里是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")); 
+0

嗯,我的意思是,我已经在做那种事了。我的构建脚本运行protoc编译器,针对目录中的所有.proto文件,并创建一个.rs文件,该文件具有(mod foo; mod bar;等等...在单独的行上),然后包含在我的主程序中。 问题是我不知道将包含哪些模块,因为文件名可能是完全随机的,所以我不知道如何构造东西,调用实现的结构函数等。 –

相关问题