2016-07-28 4 views
3

私は以前に尋ねたHow can I include an arbitrary set of Protobuf-built files without knowing their names? - これはその結果に基づいてフォローアップの質問です。includeに含まれるrust-protobufから生成された.rsファイルのメッセージを特定する方法マクロ

私は今、私は自分のライン上の異なるモジュールが含まれているインクルードファイルがある - つまり:

mod foo; 
mod bar; 

これらのモジュールとそれらの名前は、ユーザーがディレクトリに入れているものに応じて、完全にランダムであることができますprotoファイル用。

これらのランダムモジュールで操作を実行する必要があります。たとえば、最初にやりたいことは、それらの新しいモジュールに存在するすべてのメッセージを取得し、ベクトルにプッシュできる文字列として返すことです。

だから、本当に2パートの質問:

  1. は私が今含めると、このファイルに含めていたモジュールの名前を知ることができない方法はあります!それらの内部の構造を使用します(一般的には、今ではそれらが含まれています)。
  2. 上記の後、protobufで生成された.rsファイル/モジュール内のすべての可能なメッセージを取得する方法。各.RSファイルは、GoogleいるProtobufドキュメントに探してFileDescriptorProto()方法は、これに似ていますGoogle Protobuf FileDescriptor
+0

私はあなたができるとは思わない。本質的には、あなたが必要とする意味ではあまり存在しない反射を求めています。例として、 '#[test]'属性を考えてみましょう。これは、基本的に同じことを行います。注釈付きの関数をすべて収集して呼び出します。これは、ほとんどのプログラマーが利用できる技術ではなく、コンパイラー自体に加えて実装されています。代わりに、ファイル変換ツールを拡張して、よく知られていて必要なシンボルを生成することを検討し、常にそこにいると信じることができます。 – Shepmaster

+0

他のすべてのprotoファイルの "import .proto"(実際の.protoファイル内)を実行したトップレベルのprotoファイルが必要な場合はどうなりますか?私がそれをしたら、その最高レベルを含めることができますか?rsファイル(コンパイルされます)を作成し、FileDescriptorProtoを返すメソッドを使用して他のプロト構造を取得しますか?たぶん私はFileDescriptorProto()メソッドがどのように機能するかを完全には理解していません... –

答えて

0

私はShepmasterの@に基づいて、これを行う方法を考え出しました

Rustはリフレクションをサポートしていないので(この記事の時点で)、私は貨物buを拡張しなければならなかった私が知っているだろうシンボルが常に存在するように生成されているファイルにコードを書くためのスクリプト。

私は(私はその時点でモジュール名を持っていたので)私が含んでいた各モジュールに対して特定の関数を生成し、次にメインコードで呼び出すことができる汎用名を持つ "集約"関数を生成しました。

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

まあ、私はすでにそれをやっています。私のビルドスクリプトは、ディレクトリ内のすべての.protoファイルに対してprotocコンパイラを実行し、(mod foo; mod bar; etc ...を別々の行に)持つ.rsファイルを作成し、それをメインプログラムに含めます。 問題は、ファイル名が完全にランダムである可能性があるため、どのモジュールが含まれているのかわからないため、構築する方法、実装された構造体関数の呼び出しなどはわかりません。 –

関連する問題