2016-07-28 1 views
3

Ранее я спросил How can I include an arbitrary set of Protobuf-built files without knowing their names? - это следующий вопрос, основанный на результатах этого.Как определить сообщения в файлах .rs, созданных из ржавчины-protobuf, включенных в include! макрос

теперь у меня есть файл, который я включаю, который содержит различные модули на их собственной линии - то есть:

mod foo; 
mod bar; 

Эти модули и их имена могут быть совершенно случайным образом в зависимости от того, что пользователь поставил в каталог для прото-файлов.

Мне нужно выполнить операции над этими случайными модулями. Например, первое, что я хотел бы сделать, это получить все сообщения, которые существуют в этих новых модулях, и представить их в виде строк, которые я могу нажать на вектор.

Так действительно 2 часть вопроса:

  1. Есть ли способ, я не могу знать имена модулей, которые я сейчас в том числе и в этом файле с включают в себя! и используйте структуры внутри них (в общем - теперь, когда я их включил).
  2. После вышесказанного, как получить все возможные сообщения внутри созданного protobuf файла .rs/module. Каждый файл .rs имеет FileDescriptorProto() метод, который смотрит на документации Protobuf Google, выглядит примерно так: Google Protobuf FileDescriptor
+0

Я не думаю, что вы можете. По сути, вы просите о рефлексии, которая не совсем существует в том смысле, в котором вы нуждаетесь. В качестве примера рассмотрим атрибут '# [test]', который в основном делает то же самое, что вы хотите - он собирает все аннотированные функции и вызывает их. Это реализовано как дополнение к самому компилятору, а не технику, доступную большинству программистов. Вместо этого рассмотрите возможность расширения инструмента преобразования файлов, чтобы создать хорошо известный и необходимый символ, который всегда можно доверять, чтобы быть там. – Shepmaster

+0

Что делать, если я требовал, чтобы файл прототипа верхнего уровня выполнял «import .proto» (в фактическом файле .proto) для всех других прото-файлов. Если бы я это сделал, могу ли я включить этот верхний уровень.rs-файл (который будет скомпилирован), а затем использовать метод, который возвращает FileDescriptorProto для получения других протоструктур? Возможно, я не совсем понимаю, как работает метод FileDescriptorProto() ... –

ответ

0

Я придумал, как сделать это, основываясь на @ Shepmaster-х предложение в комментарии к оригинальному сообщению:

Поскольку Rust не поддерживает отражение (на момент публикации), мне пришлось расширить свой багаж ild, чтобы писать код в файле, который создается, чтобы иметь символы, которые, как я знал бы, всегда были бы там.

Я создал определенные функции для каждого из модулей, которые я включил (поскольку у меня были имена модулей в этой точке), а затем сгенерированные «совокупные» функции, которые имели общие имена, которые я мог бы перезвонить в своем основном коде ,

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

Ну, я имею в виду, я уже делаю это. Мой скрипт сборки запускает компилятор protoc для всех файлов .proto в каталоге и создает файл .rs, который имеет (mod foo; mod bar и т. Д.) На отдельных строках), которые затем включаю в свою основную программу. Проблема в том, что я не знаю, какие модули будут включены, потому что имена файлов могут быть абсолютно случайными, поэтому я не знаю, как строить вещи, вызывать реализованные структурные функции и т. Д. –